Skip to content

Conversation

@fabianschuiki
Copy link
Contributor

Add a circt-tblgen tool identical to how MLIR has this set up. This needs to be pulled in by the root cmake file to ensure that the interesting CIRCT_TABLEGEN_EXE and CIRCT_TABLEGEN_TARGET variables are visible to the rest of the project.

Having a custom TableGen in CIRCT allows us to be more fancy about how we generate code from tables. As a first example, add a backend to generate the code to register lowerings for FIRRTL intrinsics, and a backend to generate Markdown documentation snippets from the same table.

I have only migrated two intrinsics over into the table to not pollute the PR with a purely mechanical change. Once this lands we can follow up with a PR that moves all intrinsics into that table. This then enforces that every supported FIRRTL intrinsic has corresponding documentation.

I'm sure we can find a lot more uses for circt-tblgen :-)

@fabianschuiki fabianschuiki changed the title Add circt-tblgen, generate FIRRTL intrinsic docs Add circt-tblgen, generate FIRRTL intrinsics docs Jan 15, 2026
@fabianschuiki fabianschuiki force-pushed the fschuiki/tablegen branch 2 times, most recently from e0a3254 to c8888f3 Compare January 15, 2026 18:20
Add a `circt-tblgen` tool identical to how MLIR has this set up. This
needs to be pulled in by the root cmake file to ensure that the
interesting `CIRCT_TABLEGEN_EXE` and `CIRCT_TABLEGEN_TARGET` variables
are visible to the rest of the project.

Having a custom TableGen in CIRCT allows us to be more fancy about how
we generate code from tables. As a first example, add a backend to
generate the code to register lowerings for FIRRTL intrinsics, and a
backend to generate Markdown documentation snippets from the same table.

I have only migrated two intrinsics over into the table to not pollute
the PR with a purely mechanical change. Once this lands we can follow up
with a PR that moves all intrinsics into that table. This then enforces
that every supported FIRRTL intrinsic has corresponding documentation.

I'm sure we can find a lot more uses for circt-tblgen :-)
Copy link
Contributor

@dtzSiFive dtzSiFive left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really neat, thanks for putting this together!

I've left some feedback.

I have not carefully reviewed the CMake portion, and I recall it being quite .. involved, having previously poked at use in the MLIR-built-and-installed-standalone flow I use for packaging.

One possibly useful litmus test -- possibly after this PR -- is to see how well this can be used from a downstream project. Especially from an install (not just a build tree as often used).

Anyway when we move forward with this let's see if we can't be sure to follow-up promptly-ish (I'll help!) so we get everything moved over quickly (and don't have things mid-transition for too long). Not eagerly converting things, especially while under review, is a good call for now 👍 .

// lowering code, as well as fragments for the dialect documentation.
class FIRRTLIntrinsic {
// The mnemonic for the intrinsic, e.g. "circt.sizeof". This should use the
// form with dots. A second mnemonic with only underscores will be generated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we standardized on the underscore format, actually, and that's what the user-facing documentation uses today. I'm not sure offhand if there's any utility in keeping the dot variant in today's flows, but I'd want to triple-check where that was ever used, to be honest.

I'm open to arguments the other way, but regardless of which format we decide on I don't think it makes much sense to actually support both other than as a transition detail / legacy support.
(right? WDYT?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concrete suggestion was to make the underscore version the primary format, but we can't produce the dot format easily from that (which may have underscores as well), so that might be something that "goes along with" removing supporting both.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good points! I've had a similar reaction: let's make the underscore the default -- and then I realized that the dot format needs to be the default because we can't get that from the underscore format. But since this is now generated, I think once we've migrated everything over and we have officially removed support for ".", we can just tweak the few lines here?


| Argument | Type | Description |
| -------- | ---- | ------------------------------------------ |
| i | Any | value whose type's size is to be returned |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be super neat to auto-generate these tables! 🙃

Something like how arguments / results / parameters are defined for MLIR instructions, maybe? Just brainstorming.

That said, I don't know how well we could auto-generate (for example) the check/convert snippets for the majority of cases, from a programmatic / table description. A few likely will still make more sense done manually or at least via escape-hatch "just use this code as the check or convert part".

Maybe we could or otherwise could basically provide the same "interface" as currently given when adding an intrinsic re:what's needed to derive from one of the Conversion helpers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just moving this over verbatim is a great start, can't help but getting excited about where things might be able to go! 😁

It's valuable to not overdo things in that direction too hastily, probably, but curious what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be so cool to autogenerate! The snippets in the converter that handle the different flavors of arguments are a bit tricky though, as you say. Maybe we gradually increase how much of this we autogenerate over time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

struct IntrinsicDef {
const Record *def;
StringRef mnemonic;
std::string altMnemonic;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SmallString's instead of std::string ?

Copy link
Contributor Author

@fabianschuiki fabianschuiki Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had that initially, and then I remember that there are on the order of 100 of these that get allocated, and SmallString was giving off that strong premature optimization smell 🤣 . I'm happy to switch this to SmallString though if you want 😁

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, keep it.

I haven't looked at this closely enough 🙃 and let's go with your preference. Hence the question mark 😉 .

Thing I argue for most directly is avoiding a bunch of temporary std::string allocations on the way to constructing the final thing, which is only even a tiny bit relevant re:converter. And the fact that in practice it's unlikely these names will be very long.

I wonder how much the common sort of "SSO" gets us, anyway...

Just beating the good practices drum 😉 .

mnemonic = def->getValueAsString("mnemonic");
description = def->getValueAsOptionalString("description").value_or("");

// Determine the alternative mnemonic by replacing any unsavory characters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"unsavory characters" 🤣 ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants