An ongoing effort is under way to establish Calyx as a dialect in the LLVM umbrella project CIRCT. There is documentation about the Calyx dialect on the MLIR site. While semantically equivalent, they are syntactically different. Because the Calyx dialect is still under progress and does not include all the optimizations that the native Rust compiler supports, we have crafted an emitter from the Calyx dialect (MLIR) to the native compiler representation (used by the Rust compiler). This means you can lower from your favorite frontend in MLIR to the Calyx dialect, and continue all the way to SystemVerilog (with spunky optimizations) using the native compiler.

The native compiler also supports round-tripping back into the MLIR representation. We'll assume you've already built the Rust compiler and installed fud. Here are the steps below to round-trip:

MLIR to Native Representation

  1. Set up the CIRCT project with these instructions.

  2. There should be a circt-translate binary in <root-directory>/build/bin. To emit the native compiler representation, use the command:

path/to/circt-translate --export-calyx /path/to/file

For example, you can use the expected output of the test tests/backend/mlir/simple.expect:

calyx.program "main" {

calyx.component @main(%go: i1 {go=1}, %clk: i1 {clk=1}, %reset: i1 {reset=1}) -> (%out: i1, %done: i1 {done=1}) {, %r1.write_en, %r1.clk, %r1.reset, %r1.out, %r1.done = calyx.register @r1 : i1, i1, i1, i1, i1, i1
  %_1_1.out = hw.constant 1 : i1
  calyx.wires { @Group1 {
      calyx.assign = %_1_1.out : i1
      calyx.assign %r1.write_en = %_1_1.out : i1
      calyx.group_done %r1.done : i1

  calyx.control {
    calyx.seq {
      calyx.enable @Group1


Using the command:

# Don't worry too much about the file alias; this is used for testing purposes.
path/to/circt-translate --export-calyx tests/backend/mlir/simple.expect

This should output:

// -p well-formed -b mlir
import "primitives/core.futil";
component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: 1) {
  cells {
    r1 = std_reg(1);
  wires {
    group Group1 { = 1'd1;
      r1.write_en = 1'd1;
      Group1[done] = r1.done;
  control {
    seq { Group1; }

Native Representation to MLIR

To round-trip back to the Calyx dialect, we can use fud:

fud exec path/to/file --to mlir

For example,

fud exec tests/backend/mlir/simple.futil --to mlir

This should emit the Calyx dialect once again.