Circuit IR Compilers and Tools


This document describes the available CIRCT passes and their contracts.

Conversion Passes 

-analyze-dataflow: Print resource (operation) statistics 

-canonicalize-dataflow: Canonicalize handshake IR 

-convert-hw-to-llhd: Convert HW to LLHD 

This pass translates a HW design into an equivalent structural LLHD description.

-convert-llhd-to-llvm: Convert LLHD to LLVM 

This pass translates LLHD to LLVM.

-create-dataflow: Convert standard MLIR into dataflow IR 

-create-pipeline: Create StaticLogic pipeline operations 

-handshake-insert-buffer: Insert buffers to break graph cycles 


-strategies : List of strategies to apply. Possible values are: cycles

-lower-calyx-to-hw: Lower Calyx to HW 

This pass lowers Calyx to HW.

-lower-firrtl-to-hw: Lower FIRRTL to HW 

Lower a module of FIRRTL dialect to the HW dialect family.


-warn-on-unprocessed-annotations : Emit warnings on unprocessed annotations during lower-to-hw pass

-lower-handshake-to-firrtl: Lower Handshake to FIRRTL 

Lower Handshake to FIRRTL.

-remove-block-structure: Remove block structure in handshake IR 

ESI Dialect Passes 

-lower-esi-ports: Lower ESI input and/or output ports. 

-lower-esi-to-hw: Lower ESI to HW where possible and SV elsewhere. 

-lower-esi-to-physical: Lower ESI abstract Ops to ESI physical ops. 

FIRRTL Dialect Passes 

-firrtl-blackbox-memory: Replace all FIRRTL memories with an external module black box. 

This pass replaces all sequential memory operations with an external module black box. For each memory operation, it creates a FModuleOp which replicates the return types of the memory operation, and replaces the MemoryOp with an instance of the module. Inside the new module, an instance of an FExtModule black box is created. The black box module must use the same parameter naming conventions used by the ReplaceSeqMemories pass in the Scala FIRRTL compiler.


-emit-wrapper : Create a wrapper module around the black box external module.

-firrtl-blackbox-reader: Load source files for black boxes into the IR 

This pass handles reads the Verilog source files for black boxes and adds them as sv.verbatim.file operations into the IR. Later passes can then write these files back to disk to ensure that they can be accessed by other tools down the line in a well-known location. Supports inline, resource, and path annotations for black box source files.

The supported firrtl.circuit annotations are:

  • {class = "firrtl.transforms.BlackBoxTargetDirAnno", targetDir = "..."} Overrides the target directory into which black box source files are emitted.
  • {class = "firrtl.transforms.BlackBoxResourceFileNameAnno", resourceFileName = "xyz.f"} Specifies the output file name for the list of black box source files that is generated as a collateral of the pass.

The supported firrtl.extmodule annotations are:

  • {
      class = "firrtl.transforms.BlackBoxInlineAnno",
      name = "myfile.v",
      text = "..."
    Specifies the black box source code (text) inline. Generates a file with the given name in the target directory.
  • {
      class = "firrtl.transforms.BlackBoxPathAnno",
      path = "myfile.v"
    Specifies the file path as source code for the module. Copies the file to the target directory.
  • {
      class = "firrtl.transforms.BlackBoxResourceAnno",
      resourceId = "myfile.v"
    Specifies the file path as source code for the module. In contrast to the BlackBoxPathAnno, the file is searched for in the black box resource search path. This is a remnant of the Scala origins of FIRRTL. Copies the file to the target directory.


-input-prefix    : Prefix for input paths in black box annotations. This should be the directory where the input file was located, to allow for annotations relative to the input file.
-resource-prefix : Search path for black box sources specified via the `BlackBoxResourceAnno` annotation.

-firrtl-check-comb-cycles: Check combinational cycles and emit errors 

This pass checks combinational cycles in the IR and emit errors.

-firrtl-expand-whens: Remove all when conditional blocks. 

This pass will:

  1. Resolve last connect semantics.
  2. Remove all when operations.

When a wire has multiple connections, only the final connection is used, all previous connections are overwritten. When there is a conditional connect, the previous connect is only overwritten when the condition holds:

w <= a
when c :
  w <= b

; Equivalent to:
w <= mux(c, b, a)

This pass requires that all connects are expanded.

-firrtl-grand-central: Remove Grand Central Annotations 

Processes annotations associated with SiFive’s Grand Central utility.

-firrtl-grand-central-taps: Generate code for grand central data and memory taps 

-firrtl-imconstprop: Intermodule constant propagation and dead code elimination 

Use optimistic constant propagation to delete ports and unreachable IR.

-firrtl-infer-resets: Infer reset synchronicity and add implicit resets 

This pass infers whether resets are synchronous or asynchronous, and extends reset-less registers with an asynchronous reset based on the following annotations:

  • sifive.enterprise.firrtl.FullAsyncResetAnnotation
  • sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation

-firrtl-infer-widths: Infer the width of types 

This pass infers the widths of all types throughout a FIRRTL module, and emits diagnostics for types that could not be inferred.

-firrtl-inliner: Performs inlining, flattening, and dead module elimination 

This inliner pass will inline any instance of module marked as inline, and recursively inline all instances inside of a module marked with flatten. This pass performs renaming of every entity with a name that is inlined by prefixing it with the instance name. This pass also will remove any module which is not reachable from the top level module.

The inline and flatten annotation attributes are attached to module definitions, and they are:

  {class = "firrtl.passes.InlineAnnotation"}
  {class = "firrtl.transforms.FlattenAnnotation"}

-firrtl-lower-chirrtl: Infer the memory ports of SeqMem and CombMem 

This pass finds the CHIRRTL behavioral memories and their ports, and transforms them into standard FIRRTL memory operations. For each seqmem or combmem, a new memory is created. For every memoryport operation using a CHIRRTL memory, a memory port is defined on the new standard memory.

The direction or kind of the port is inferred from how each of the memory ports is used in the IR. If a memory port is only written to, it becomes a Write port. If a memory port is only read from, it become a Read port. If it is used both ways, it becomes a ReadWrite port.

Write, ReadWrite and combinational Read ports are disabled by default, but then enabled when the CHIRRTL memory port is declared. Sequential Read ports have more complicated enable inference:

  1. If a wire or register is used as the index of the memory port, then the memory is enabled whenever a non-invalid value is driven to the address.
  2. If a node is used as the index of the memory port, then the memory is enabled at the declaration of the node.
  3. In all other cases, the memory is never enabled.

In the first two cases, they can easily produce a situation where we try to enable the memory before it is even declared. This produces a compilation error.

-firrtl-lower-types: Lower FIRRTL types to ground types 

Lower aggregate FIRRTL types to ground types. Memories, ports, wires, etc are split appart by elements of aggregate types. The only aggregate types which exist after this pass are memory ports, though memory data types are split.

Connect and partial connect expansion and canonicalization happen in this pass.

-firrtl-print-instance-graph: Print a DOT graph of the module hierarchy. 

LLHD Dialect Passes 

-llhd-early-code-motion: Move side-effect-free instructions and llhd.prb up in the CFG 

Moves side-effect-free instructions as far up in the CFG as possible. That means to the earliest block where all operands are defined. Special care has to be given to the llhd.prb instruction (which is the only side-effect instruction moved by this pass) as it must stay in the same temporal region, because otherwise it might sample an older or newer state of the signal. This pass is designed as a preparatory pass for the Temporal Code Motion pass to be able to move the llhd.drv operations in a single TR exiting block without having to move operations defining the operands used by the llhd.drv. It also enables total control flow elimination as the llhd.prb instructions would not be moved by other canonicalization passes.

-llhd-function-elimination: Deletes all functions. 

Deletes all functions in the module. In case there is still a function call in an entity or process, it fails. This pass is intended as a post-inlining pass to check if all functions could be successfully inlined and remove the inlined functions. This is necessary because Structural LLHD does not allow functions. Fails in the case that there is still a function call left in a llhd.proc or llhd.entity.

-llhd-memory-to-block-argument: Promote memory to block arguments. 

Promotes memory locations allocated with llhd.var to block arguments. This enables other optimizations and is required to be able to lower behavioral LLHD to structural LLHD. This is because there are no memory model and control flow in structural LLHD. After executing this pass, the “-llhd-block-argument-to-mux” pass can be used to convert the block arguments to multiplexers to enable more control-flow elimination.


llhd.proc @check_simple(%condsig : !llhd.sig<i1>) -> () {
  %c5 = llhd.const 5 : i32
  %cond = llhd.prb %condsig : !llhd.sig<i1>
  %ptr = llhd.var %c5 : i32
  cond_br %cond, ^bb1, ^bb2
  %c6 = llhd.const 6 : i32 %ptr, %c6 : !llhd.ptr<i32>
  br ^bb2
  %ld = llhd.load %ptr : !llhd.ptr<i32>
  %res = llhd.not %ld : i32

is transformed to

llhd.proc @check_simple(%condsig : !llhd.sig<i1>) -> () {
  %c5 = llhd.const 5 : i32
  %cond = llhd.prb %condsig : !llhd.sig<i1>
  cond_br %cond, ^bb1, ^bb2(%c5 : i32)
  %c6 = llhd.const 6 : i32
  br ^bb2(%c6 : i32)
^bb2(%arg : i32):
  %res = llhd.not %arg : i32

-llhd-process-lowering: Lowers LLHD Processes to Entities. 


MSFT Dialect Passes 

-run-generators: Run the MSFT design entry generators 

Generators allow designers to model their system with high-level constructs (which they define), then lower them down into synthesizable code. High-level constructs are modeled as MLIR Operations. Generators are essentially lowerings of those operations and they are registered along with the name of an MLIR operation which they lower. Generators also have a name so multiple can be registered per operation then one of them selected by some criteria, allowing the designer to choose a particular implementation of the same logical feature.


-generators : List of possible generators to run.

Seq Dialect Passes 

-lower-seq-to-sv: Lower sequential ops to SV. 

SV Dialect Passes 

-hw-cleanup: Cleanup transformations for operations in hw.module bodies 

This pass merges sv.alwaysff operations with the same condition, sv.ifdef nodes with the same condition, and perform other cleanups for the IR. This is a good thing to run early in the HW/SV pass pipeline to expose opportunities for other simpler passes (like canonicalize).

-hw-generator-callout: Lower Generator Schema to external module 

This pass calls an external program for all the hw.module.generated nodes, following the description in the hw.generator.schema node.


-schema-name                    : Name of the schema to process
-generator-executable           : Generator program executable with optional full path
-generator-executable-arguments : Generator program arguments separated by ;

-hw-legalize-modules: Eliminate features marked unsupported in LoweringOptions 

This pass lowers away features in the SV/Comb/HW dialects that are unsupported by some tools, e.g. multidimensional arrays. This pass is run relatively late in the pipeline in preparation for emission. Any passes run after this must be aware they cannot introduce new invalid constructs.

-hw-legalize-names: Legalize module/variable names in hw.modules and their bodies 

This pass modifies the names of modules and names such that they do not cause conflicts with SV keywords. This is a good thing to run before Verilog emission.

-hw-memory-sim: Implement FIRRTMMem memories nodes with simulation model 

This pass replaces generated module nodes of type FIRRTLMem with a model suitable for simulation.

-hw-stub-external-modules: transform external hw modules to empty hw modules 

This pass creates empty module bodies for external modules. This is useful for linting to eliminate missing file errors.

-prettify-verilog: Transformations to improve quality of ExportVerilog output 

This pass contains elective transformations that improve the quality of SystemVerilog generated by the ExportVerilog library. This pass is not compulsory: things that are required for ExportVerilog to be correct should be included as part of the ExportVerilog pass itself to make sure it is self contained.

-sv-extract-test-code: Extract simulation only constructs to modules and bind 

This pass extracts cover, assume, assert operations to a module, along with any ops feeding them only, to modules which are instantiated with a bind statement.