Serial Dependencies Between Synthesis Phases #5117
Replies: 4 comments 2 replies
-
I think there have been some discussions around enforcing order (or detecting when it is violated in a script and reporting that), but at present the only enforcement is that some passes will report an error if the design has incompatible elements. i.e. rather than checking "has There was a recent bug report for a design with two fsms, where trying to process both at the same time was causing them to be optimized away, but could be avoided by running In general, Unfortunately, there isn't very much documentation around pass ordering/dependencies except what is written in the individual pass help messages. The main split we have is for passes that work on coarse word-level cells, and those that work on fine gate-level cells (and some like If you're asking for the purpose of finding and reporting bugs, I would strongly suggest sticking to the existing |
Beta Was this translation helpful? Give feedback.
-
Regarding the proc pass, while it is true that “there is nothing to prevent you from loading some design, calling proc, doing other steps, then loading another design and calling proc again,” this applies to different designs. In contrast, for the same design, proc cannot be applied repeatedly. This is because proc is an irreversible pass that lowers always blocks (i.e., procedural constructs) into lower-level representations such as assign, case, and if statements. Once proc has been executed, the original always constructs are eliminated from the design. As a result, reapplying proc to the same module has no effect, since there are no procedural blocks left to process Moreover, as discussed in issue #4945 regarding dependencies between Yosys passes (e.g., hierarchy, proc, memory, fsm, opt, setundef, alumacc, etc.), certain fine-grained passes must operate after their coarse-grained predecessors. In particular, hierarchy should always be the first command after a design is read. By specifying the top module, hierarchy also sets the (* top *) attribute, which is required by downstream passes that rely on the top module information. 2.Once any pass from a certain stage has been executed, is it disallowed to go back and run passes from an earlier stage? For example, is executing a hierarchy or proc pass after running opt_* considered invalid? “In general, opt_clean should be able to run at any point of a synthesis flow without preventing further passes from operating, though I think there are cases where that isn't true (many of which may be bugs or mis-implemented code). opt less so, but as far as I'm aware there isn't any reason it couldn't be run before hierarchy or proc.”-----Thank you for the clarification. To elaborate on my implementation: the four-phase pass structure I described follows a strict sequential phase advancement policy. Specifically, at any given a design, the passes can from the stage1 phase or the other phase are permitted. And at any given point, only passes from the current phase or the next phase are permitted. Backtracking to earlier phases is disallowed, and while phases must progress forward, it is permissible to skip intermediate phases if desired. Within each phase, the order of individual passes is unrestricted. This design enforces clear boundaries between major transformation stages (e.g., hierarchy, proc, opt, techmap) and helps ensure that phase-sensitive passes are not applied in an inconsistent or unintended context. Certain utility passes like opt_clean are allowed to run across phases due to their non-invasive nature, but core transformation passes must comply with the phase discipline. |
Beta Was this translation helpful? Give feedback.
-
Modern hardware synthesis flows, such as those implemented in Yosys, consist of multiple transformation phases, each responsible for handling specific aspects of the design, including hierarchy analysis, control flow elaboration, optimization, and netlist generation. These phases are not independent; rather, they follow a strict serial dependency chain, where the output of one phase provides the required semantic or structural preconditions for the next. For example, Verilog process constructs such as always blocks are initially parsed into intermediate representations (AST or RTLIL processes) that are not directly synthesizable. These must be translated into a gate-level form through the proc pass (or its sub-passes like proc_init, proc_mux, and proc_clean). Failure to execute these passes before invoking technology mapping or netlist export (e.g., techmap, abc, or write_edif) results in incomplete or invalid designs, as the backends do not support unmapped process structures. This structural dependency can be illustrated by the following minimal phase sequence: verilog read_verilog → hierarchy → flatten → proc → opt → techmap → abc → write_edif flatten ensures a flat design hierarchy for process elaboration. proc is semantically essential to convert high-level process constructs into synthesizable forms. opt and techmap require the process-expanded netlist to function correctly. write_edif explicitly disallows unmapped processes, leading to a fatal error if earlier phases are skipped. This observation reflects a broader principle in synthesis flow orchestration: legality and effectiveness of transformations are not merely syntactic but deeply rooted in semantic readiness of intermediate representations. Tools like Yosys do not perform implicit corrections; thus, a syntactically valid pass sequence may still fail catastrophically if it violates the underlying phase dependency semantics. |
Beta Was this translation helpful? Give feedback.
-
I would like to take this opportunity to explain the intended goal of my work. My research focuses on modeling and analyzing the serial dependencies between synthesis passes in Yosys, with the aim of constructing legal and diverse transformation sequences for testing and evaluating synthesis tool robustness. To this end, I have explored decomposing monolithic passes (such as proc, fsm, and memory) into their constituent sub-passes, not for practical manual usage, but to capture fine-grained execution semantics and establish phase constraints that ensure legal pass scheduling. The classification you pointed out — e.g., proc_dff, proc_mux, fsm_detect, etc. — was introduced to reflect internal transformation boundaries and support constrained sequence generation under a phased model, in which backtracking is disallowed and explicit dependencies are respected. Regarding the mention of dff2dffe, you are absolutely correct — this pass is deprecated and no longer part of the current Yosys codebase. This was an oversight on my part, and I have removed references to it in subsequent revisions of my pass list. Concerning the inclusion of options such as hierarchy -top, hierarchy -keep_positionals, hierarchy -keep_portwidths, and hierarchy -nokeep_asserts after hierarchy -check, I would like to clarify that in my modeling, these options are treated as independent and optional variants that may appear in any order or combination following hierarchy -check. I fully acknowledge that certain combinations — for instance, applying hierarchy -keep_positionals after hierarchy -top — may be semantically redundant due to irreversible transformations (e.g., positional arguments having already been converted to named ports). However, in the context of my work, I deliberately preserve such combinations in the legal synthesis space, as long as they do not result in errors or synthesis failures. This approach allows for maximal exploration of the valid pass space, with the aim of discovering unusual but syntactically permitted behaviors that may trigger latent issues in synthesis tool chains. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
While studying the pass-level transformation dependencies in Yosys, I noticed what appears to be a strict serial dependency structure across major pass categories during synthesis. Based on documentation and observed behavior, I would like to verify whether the following phase-based ordering is officially enforced or only recommended:
Proposed phase structure:
Phase 1: Hierarchy & Structural Setup
Hierarchy Sub-Phase 1
Phase 2:
Proc
Phase 3: RTL Lowering
Sub-phase 1: memory/fsm interface normalization
"memory_collect": 3, "fsm_detect": 3, "fsm_extract": 3, "Dff2dffe": 3, "dffsr2dff": 3, "Clk2fflogic": 3, "coolrunner2_sop": 3,
"Alumacc": 3, "Rmports": 3, "Connwrappers-sign": 3, "Connwrappers-unsign": 3,
"Connwrappers-port": 3, "Pmux2shiftx": 3, "pmuxtree": 3,
Stage 3 Sub-Phase 2
Phase 4:
"opt_expr": 4,"opt_expr -mux_undef": 4,"opt_expr -mux_bool": 4,"opt_expr -fine": 4, "opt_expr -full": 4,
"opt_expr -undriven": 4, "opt_merge": 4, "opt_merge -nomux": 4,"opt_demorgan": 4,
"opt_mem": 4,"opt_mem -feedback": 4, "opt_mem -widen": 4, "opt_dff": 4, "opt_dff -keepdc": 4,
"opt_clean": 4, "opt_clean -purge": 4,"ice40_opt": 4,
"setundef -undriven": 4, "setundef -expose": 4,"setundef -zero": 4,"setundef -one": 4,"setundef -undef": 4,
"setundef -random": 4, "lut2mux": 4, "pmuxtree": 4, "splitcells": 4, "splitnets": 4, "splice": 4,
"Freduce": 4, "gatemate_foldinv": 4,
My questions:
1.Does Yosys enforce a strict phase progression where executing a pass from a later stage (e.g., proc) is only allowed if all required passes from earlier stages (e.g., hierarchy) have been completed?
2.Once any pass from a certain stage has been executed, is it disallowed to go back and run passes from an earlier stage? For example, is executing a hierarchy or proc pass after running opt_* considered invalid?
Are there any pass groups that may be safely interleaved across phases?
3.Within each stage, is the execution order of passes flexible as long as explicit dependencies (e.g., opt_expr -mux_undef depending on fsm_opt) are satisfied?
To avoid producing undefined or unsupported sequences, I would like to clearly understand which dependencies are structural and which are advisory.
Beta Was this translation helpful? Give feedback.
All reactions