Closed seldridge closed 2 years ago
I think there is value in a debug-mode compile for firrtl. This would promote nodes to wires and don't touch all wires. That should be sufficient to ensure all names survive.
That said, we can also do a better job not dropping names. This means the canonicalization which removes names from nodes and then removes nodes needs to instead try to move the name from a node to the expression feeding it as a name attribute. This won't prevent optimizations, but will ensure that if an expression is spilled, then the name of the node it fed in the fir file will be used.
I am less thrilled than I used to be with the debug-view idea because it does interfere with optimization and leave dead-code in the production-path module.
Fixed in: https://github.com/llvm/circt/pull/2676.
tl;dr: this is a proposal for a "debug mode" which enables specific CIRCT signals to always show up in the output, but also to not block optimizations. This is entirely based off of ideas of and discussions with @fabianschuiki and @darthscsi.
Consider the following input FIRRTL circuit:
Currently, CIRCT produces the following Verilog:
A combination of canonicalization
not(x) -> xor(x, 1)
andmux(~cond, left, right) -> mux(cond, right, left)
, inlining, and CSE result in all internal names (foo
andbar
) being lost. A user who wrote the above code in Chisel may care deeply thatfoo
andbar
exist so they can debug their code.Analogously, this is like the compiler optimizing away a
printf
in C. There's no way for the user to reconstructfoo
orbar
in their waveform. This makes for grumpy users.The SFC, entirely coincidentally, preserves both
foo
andbar
because it doesn't implementnot(x) -> xor(x, 1)
canonicalization. With the SFC you get:Note that if
foo
andbar
canonicalize in the SFC to the same thing (i.e., you use different expressions for which the SFC implemented those canonicalizations), you will wind up with onlyfoo
in the output.This is enormously problematic because CIRCT then has diametrically opposed goals:
Relatedly, it's unclear that we can get ourselves out of this with only better naming. E.g., what should
_T
be called here? It's justc_or_d
, but that's not useful. What to do withfoo
andbar
? They're totally gone and there's no good way to kludge them back in.Both @fabianschuiki and @darthscsi have suggested great ideas in this space that I try to synthesize below. When we're confronted with a situation like this where no good name is possible we need a mechanism to not block optimizations while still preserving the original names. This can either be achieved with a new type of "dont touch" / symbol that guarantees that something will exist, but doesn't block optimizations. We could then produce the hypothetical:
This can then be further improved by extracting the debug logic to a bound instance like how FIRRTL dialect test code extraction or Grand Central works:
For the above to have no effect on the final circuit
Foo
, it may be necessary to duplicate all logic (that affects named signals) fromFoo
intoFoo_DEBUG
so that the effect of this "debug mode" doesn't result in a different circuitFoo
.Note: This isn't saying that we shouldn't try to generate good names, just that we need some fallback debug mode when good names aren't possible.
This is related to #2470.