calyxir / calyx

Intermediate Language (IL) for Hardware Accelerator Generators
https://calyxir.org
MIT License
450 stars 44 forks source link

Nondeterminism in wire initialization when using `ref` cells. #2016

Closed nathanielnrn closed 3 weeks ago

nathanielnrn commented 3 weeks ago

The compiler can initialize wires in a non-deterministic order when passing in to ref cells. We suspect this has to do with HashMap iterators somewhere in the verilog backend.

An MRE to reproduce looks like this:

import "primitives/core.futil";
component comp_with_ref() -> () {
  cells {
    ref my_ref_reg = std_reg(8);
  }
  wires {
    group some_group {
      some_group[done] = 1'b0 ? 1'b1; //this allows us to have an "empty" group without the compiler getting mad. Not important to reproduce AFAIK.
    }
  }
  control {
          some_group;
  }
}
component main() -> () {
  cells {
    my_actual_reg = std_reg(8);
    my_ref_comp = comp_with_ref();
  }
  wires {
  }
  control {
    seq {
      par {
        seq {
          invoke my_ref_comp[my_ref_reg=my_actual_reg]()();
        }
      }
    }
  }
}

And can be compared with /target/debug/calyx <path to above file> -b verilog --disable-verify -o tmp.v && ./target/debug/calyx <path to above file> -b verilog --disable-verify -o tmp2.v && diff tmp.v tmp2.v && rm tmp.v tmp2.v

@sampsyo suggested that these lines may the culprit. Which also suggests this wire_decls function may be to blame.

Tried to write down all of the relevant information here, but in case I missed anything here is the original Slack thread.