[Debug][FIRRTL][2/13] Lower circt_debug_* intrinsics to Debug ops#10647
[Debug][FIRRTL][2/13] Lower circt_debug_* intrinsics to Debug ops#10647fkhaidari wants to merge 1 commit into
Conversation
Convert circt_debug_var, circt_debug_subfield, and circt_debug_enumdef into Debug-dialect ops carrying source-language type metadata. A pre-pass stages subfield leaves and enumdef variant data (keyed by FQN), then erases both, so the converters stay stateless. Linkage is by FQN: a subfield's `parent` names the root variable and `name` is its dotted display path. Enum use sites build a dbg.enum inline from the staged variants, so no separate definition op is needed. Leaf matching descends bundles and vectors and treats FIRRTL enum fields as leaves; a dangling FQN or unmatched leaf is a warning, not an error.
|
Hey @fabianschuiki, @uenoku, @darthscsi, @seldridge! In this PR, I'm continuing my work on the debug stack that was started in #10579. The first user for new dbg operations is appearing here. New intrinsics was introduced in Chisel v7.13.0. And do not be afraid of diff size. Most of it are tests |
uenoku
left a comment
There was a problem hiding this comment.
I haven't looked at the detail yet but:
- Why can't we reuse/extend https://github.com/llvm/circt/blob/main/lib/Dialect/FIRRTL/Transforms/MaterializeDebugInfo.cpp?
- Why is a huge framework change for LowerIntrinsic necessary? I think we would be more comfortable if the change is simply adding intrinsics ... Especially representation of
debug_enumdefis very outlier compared to other intrinsics. Can we embed that information to thedebug_varorsubfieldintrinsic itself? - nit: Could you consider using tablegen for instrinsic definition?
resolveRootSignalfeels very fragile and I'm not sure it's going to work ... it looks encoding another SSA edge into intrinsic's field. Can't we pass these values to intrinsics simply?
|
Thanks @uenoku, going in order:
@jackkoenig, both of these (1 and 4) touch how Chisel emits the debug intrinsics, so wanted your input. For point 2 I'm planning to inline the enum variants into Plan: do point 2 now, settle point 4 with Jack first. |
We definitely want to avoid doing anything by name. 2.5 possibilities come to mind:
val monitor = Wire(Output(someBidirectionalThing)) // Output coerces all directions to aligned
monitor :#= someBidirectionalThingCan we do something like that? It depends on what the operation is trying to do of course.
|
|
Thanks @jackkoenig! I prototyped both option 1 and option 2.5 end-to-end and compared emitted Verilog and debug output against the by-name baseline. Option 1 works: with a droppable Option 2.5 came out cleaner: the maximal flip-free subtrees are already passive expressions, so the frontend just passes them as operands plus their paths in an optional So the plan: implement option 2.5 in this PR and delete |
There was a problem hiding this comment.
Hey @fkhaidari! Really cool that you are building this stuff out 🥳. One thing I'm wondering: why do you need things like enumdef? Since you are essentially attaching debug information to an SSA value, I don't think there's any need for a definition/declaration indirection. Could you have the debug var intrinsic, or some debug enum value intrinsic, carry the exact layout of the enum as an attribute?
It would be great to have a chat or discussion about how to represent this in CIRCT. Looking at some of the code, I feel like most of this has been driven by what the easiest way to emit some of this stuff in Chisel is. Chisel is very strange and quirky though, and we'd probably rather want to have the compiler itself have a robust idiomatic representation for the debug info and then do the heavy lifting on how to generate that on the Chisel side.
Do you have a concrete example of what exactly you would like to preserve from Chisel all the way to the output? I suspect that you'll need very little compiler machinery -- only something like a dbg.enum op to ascribe an enum type to an SSA value. All the other stuff, enumdef, subfields, etc. feels like it's a consequence of Chisel's weird connect semantics, but you'd actually just use dbg.array and dbg.struct to reconstruct the aggregates. No need for subfields. You use dbg.enum and other type metadata ops on the individual SSA values corresponding to the subfields, and then aggregate them back up with dbg.array and dbg.struct.
|
Hey @fabianschuiki, thanks for taking a look! enumdef: agreed, and it's already on its way out on both levels. At the dialect level the definition/declaration indirection is gone since the #10579 review: The direction: the goal is one structured debug-info document (UHDI) that opensource debugging tools like hgdb, tywaves, and chiseltrace consume. Two kinds of information have to survive from the frontend to that output. First, named source values with their source types: aggregates, enums, type parameters. There you're right that very little machinery is needed: everything lowers into the ops from #10579 ( Example: an end-to-end sample (ChiselEnum FSM through Chat: gladly. There's an RFC with the full picture: https://discourse.llvm.org/t/uhdi-structured-debug-info-export-for-chisel-firrtl/90973, happy to discuss there, and I can add an agenda item for the July 15 ODM. |
Convert circt_debug_var, circt_debug_subfield, and circt_debug_enumdef into Debug-dialect ops carrying source-language type metadata.
A pre-pass stages subfield leaves and enumdef variant data (keyed by FQN), then erases both, so the converters stay stateless. Linkage is by FQN: a subfield's
parentnames the root variable andnameis its dotted display path. Enum use sites build a dbg.enum inline from the staged variants, so no separate definition op is needed. Leaf matching descends bundles and vectors and treats FIRRTL enum fields as leaves; a dangling FQN or unmatched leaf is a warning, not an error.