hw.module @ssa_cycle(in %a: i1, in %b: i1, out out0: i1) {
%0 = comb.and %a, %b : i1
%1 = comb.and %0, %a : i1
hw.output %1 : i1
}
$circt-opt -synth-functional-reduction bar.mlir
module {
hw.module @ssa_cycle(in %a : i1, in %b : i1, out out0 : i1) {
%0 = comb.and %a, %b : i1
%1 = comb.and %2, %a : i1
%2 = synth.choice %0, %1 : i1
hw.output %2 : i1
}
This is because %0, %1 are semantically equivalent but %0 is used by %1.
It's necessary remove cycles via perform post-processing in FunctionalReduction something like this:
if (noCycle(block)) return;
for (auto scc: findSCC(block)) {
// By construction SCC should contain a choice node (because choice created a cycle)
for (ChoiceOp choice: choices) {
// There should be at least one operand that came from outside of SCC
// (Otherwise it implies there was a SSA cycle before FunctionalReduction and it should have been rejected in pre-pass).
// So drop values defined within SCC.
dropChoiceOperandsInSCC(choice);
}
}
This is because %0, %1 are semantically equivalent but %0 is used by %1.
It's necessary remove cycles via perform post-processing in FunctionalReduction something like this: