LLVM Discussion Forums

FIRRTL aggregate types discussion

I think the Handshake to FIRRTL conversion existed before a lot of the recent work to flesh out the RTL dialect. That conversion doesn’t appear to need a ton of high- or mid-level constructs in FIRRTL. I see it using when ops and the bundle type. We may not need the when ops, but the bundle type is used pervasively to represent a data signal and its valid and ready bits.

I don’t see why we can’t target RTL from Handshake. If we support a new type in the RTL dialect that can represent the data+valid+ready bundles, I think that conversion would work pretty much like it does today. As you mentioned, we would then need to flatten the higher-level type into something EmitVerilog understands, or update EmitVerilog to model this type (perhaps using SV interfaces).

If we didn’t have such a type, the lowering from Handshake would have to generate flat lists of signals for all the data+valid+ready bundles.

My current thinking is to keep targeting FIRRTL from Handshake, and in the short term support lowering the aggregate types within the FIRRTL dialect. This way, the FIRRTL produced by the existing lowering can be made compatible with the lower-level types expected by RTL, LLHD, and EmitVerilog. It also enables other clients of FIRRTL that may be using bundle types.

This is really just a pragmatic choice to connect the dots with minimal changes (and changes that we want to do anyway). I’d also be interested in seeing more high-level types available in the RTL dialect long term, and in that case, lowering from Handshake directly to RTL make sense to me.

I tend to agree that Handshake could be lowered directly to RTL. I think it’s a little early to see the tradeoffs of this though. To actually generate verilog does require some sort of mid-FIRRTL to low-FIRRTL lowering, IIRC.

My personal opinion is that the primary dialect for optimizing RTL should be based on a Graph Region. It’s unclear to me whether this matches what others are looking for in the RTL dialect. This might not be the easiest dialect to lower into directly, depending on where you start. Our experience so far is that conversions from graph regions to non-graph regions tend to be ‘global’ transformations with signficant bookkeeping and complexity, while transformations that preserve the graph nature or SSACFG nature tend to be simpler because the basic structure is often preserved.

I apologize for hijacking the thread. Let’s continue this discussion in a new one.

That drawing is super-helpful! :+1: @mikeurbach Any chance this is something like diagrams.net / draw.io which can be edited collaboratively to keep track of things :wink:? It would be great to add Behavioural LLHD, Moore, and Synthesizers/Simulators to the picture, to see how things could flow in a first “full stack” demonstration.

I fully agree! We used SV interfaces quite extensively for some of our ASIC/FPGA work in the PULP project, but then decided to move to a more struct-centric approach (with one input and one output struct), to work around a lot of tooling issues we have encountered; and the fact that interfaces add an implicit module parametrization that you virtually can’t get a hold of in a portable manner, or override in a synthesizer.

It’s time I added these to Moore. Haven’t worked a lot with them; just seen that they have tagged and untagged variants. Sounds super useful, and like something we should somehow represent in the dialects to avoid bitcasting things around.

I have a feeling that there are quite a few SV-to-SV dialect passes to be had, which remove redundancy or improve readability of the SV output. Or allow for better tool integration, like a “flatten interfaces” SV-to-SV pass. For something like that I can imagine it helps to have types in the SV dialect which reflect types of the SV language 1:1 :thinking: What do you think?

I agree. I think the general consensus here is to have the SV dialect ops/types correspond pretty much directly to the AST of System Verilog.

I was just saying that if the core RTL dialects types were sufficient to express the SV semantics, why create new ones?

The other argument for not having any types in a the SystemVerilog dialect (which I may or may not buy) is that the SV dialect is supposed to be an “AST” dialect with the syntax entirely defined by Ops. So the RTL types would be lowered into syntax Ops.

Yeah that’s a good point. This can also be an opt-in thing: try to stick with the RTL types as long as possible, and if it turns out thay we need something more specific, add an SV type if absolutely needed.

The SV type system is pretty awkward, especially around arrays, structs and signing. I can imagine that there are cases where we need a translation step from “sane RTL types” to the “crazy SV types”.

Hmmm yeah. Seems to me like being able to apply transformations to the SV dialect for the sake of cleanup and other readability improvements will need some semantic information, at least bound names and some notion of types. :thinking:

Yep, here is a drawio that should be editable: https://drive.google.com/file/d/1uzB0lUqHmXkX6n0Jmx8mnJHTjtUq6BBU/view?usp=sharing.

Yeah, that’s probably the most practical action.

Not knowing anything about drawio, is there any way we could put this in the git repo?

The file is just XML that drawio/diagrams.net can understand, so we could check it in if we wanted.

1 Like

(catching up on this thread):

I agree with much of what is said above, we should have the SV dialect correspond more or less to the “ugly truth” (meant with all kinds of fondness) of SystemVerilog, and allow it to express the important parts of that language that any frontend will want to emit. This should also include things like nodes to represent casex and other higher level constructs that we’d like to see in “pretty verilog”.

One correction to the pretty diagram above: while it is true that EmitVerilog currently supports the RTL, SV, and FIRRTL dialect, this is a bug (more like a work in progress stage), not a feature ;-). I (and others) are slowly working on building out the RTL/SV dialects to express everything that FIRRTL can emit, and enhancing the firrtl lower-to-rtl pass lower everything in FIRRTL. Once this is done, I’d like to completely remove the support in EmitVerilog for handling FIRRTL dialect.

This will leave us with a flow that looks like this (coming from low firrtl, the other parts of the diagram are the same: “LowerToRTL; Canonicalize; EmitVerilog”. We can then introduce a new pass to do larger restructurings than would make sense for canonicalization – e.g. merging if’s with the same conditions, formation of casex, etc, and end up with a pass pipeline like “LowerToRTL; Canonicalize; FormPrettyVerilog; EmitVerilog”.

The result of this work should allow other frontends to use the SV/RTL dialects in a lot of interesting ways without having to go through FIRRTL.


One other (possibly crazy thing) to consider after all this refactoring is done: it doesn’t really make sense for EmitVerilog to be special cased to two dialects (RTL and SV). When all of this is done, we may want to turn some significant chunk of EmitVerilog into an OpInterface driven system to allow extra-dialect extension of the system without hacking EmitVerilog. I’m not aware of any specific reason to do this in the chisel world, but it would make for a much more hackable system that could lend itself to interesting research in the future etc.


1 Like