Dialect Attributes in MLIR C-API

I’ve found that I’m not able to read or write some attributes in ODS dialect ops through the MLIR C-API. I’d like to use Rust, but if the C API itself doesn’t work then things like Melior won’t work either, so I’ve reduced the issue to just the C API for simplicity. Perhaps this is due to gaps with non-attribute properties? Am I making a newbie mistake? Or is there something else going on?

A concrete example from a CIRCT dialect is the cond attribute of the sv.ifdef.procedural op. Here is a link to a code example that reproduces both the read and write issues detailed below: https://github.com/jgreenbaum/mlir-c-api-attribute-issue.

When I call mlirOperationHasInherentAttributeByName with an argument of cond on an instance of an sv.ifdef.procedural op it returns true as expected. And when I call mlirOperationGetInherentAttributeByName the returned attribute is non-null. But svAttrIsASVAttributeAttr returns false, and mlirAttributeGetType returns a null type, so I can’t read the attribute directly. I suspect the former is due to the latter. I can, however, print the value with mlirAtributePrint and the value is printed as an #sv<macro.ident> attribute as expected. So how do i get the macro.ident symbol via the MLIR-C API? Of course I could just parse it if all I want is to read it, but how to I write it? I’ve tried creating an sv.macro.ident attribute built with svSVAttributeAttrGet and calling mlirOperationSetInherentAttributeByName, but verification fails with an error about needing the cond attribute set.

What am I missing here? Or are there pieces of glue missing for the C API to work fully with the CIRCT SV dialect?

I’m not an expert on the C API, but, as far as I’m aware, there’s currently no process for automatically generating C bindings for dialect attributes and you have to manually define the wrappers for anything tou need.

There’s an future where someone adds a TableGen processor to emit these C headers (I think there’s something like that for parts of the Python bindings), but I’m not aware of anyone actively working on this.

Can someone point me to the “design pattern” I should follow from existing dialect? I’m not afraid of writing TableGen code if it is straightforward.

If you want to write these by hand, we have some examples in iree/compiler/bindings/c/iree/compiler/dialects/iree_gpu.h at main · iree-org/iree · GitHub

The APIs you’re looking at are for SVAttributeAttr, but what you actually want is MacroIdentAttr, which is different. You can look at the implementation here: circt/lib/CAPI/Dialect/SV.cpp at main · llvm/circt · GitHub

The “type” referenced here is the type from TypedAttrInterface, which probably isn’t relevant here.

Your right, but SVAttributeAttr appears to be the only attribute type implemented today. I was grasping at straws, but see the def now of SVAttribute in the .td files.

Looking more at the .td files and TableGen it doesn’t seem too hard to generate dialect attribute construction C APIs, and region/argument accessor functions. Am I oversimplifying, or will I hit issues quickly if I try to write some TableGen generators?

It’s not hard no. This was not done as there was a few folks objecting about generating at build time given folks may expect stability from C API. I think it is a useful function even if just to bootstrap, append or manually update (we do try to keep the C API mostly stable). This would only work easily for AttrDefs rather constraint ones (well, you will have to hard code some builders).

Just FYI you can’t do it “out-of-tree” ie you’re going to have to add the code directly here llvm-project/mlir/tools/mlir-tblgen at main · llvm/llvm-project · GitHub and that can’t be maintained down-stream without forking (which CIRCT does not do). So if you write such a generator you would need to upstream it. Or we would again need to revisit whether all of the stuff in mlir-tblgen should be public API. Personally I’m in support of both such a generator existing upstream (and thus being usable with upstream dialects) and the stuff in mlir-tblgen being public API (so that downstream can further extend said generator).

I did write a generator, and updated my example to use the code from it. The MLIR TableGen records take a little while to learn how to navigate, but it wasn’t too hard to generate IsA, Get, GetAltN, and GetXXX calls.

The updated example is at GitHub - jgreenbaum/mlir-c-api-attribute-issue at mlir-capi-gen. See the generated_capi/cc/ directory for the generated code. The generator, which I wrote in Rust with tblgen-rs, is at GitHub - jgreenbaum/mlir-attr-gen-exp: This Rust crate is an experiment in generating the C API for MLIR ODS dialects like those from the (CIRCT Projerct)[circt.llvm.org]..

Since my goal is to use Rust with the CIRCT dialects, I’ve started a discussion in the Melior github about whether a generator like this should be integrated there until such a time that someone adds this capability to mlir-tblgen. Any other followup I should consider? I haven’t seen any recent discussion about Melior or Rust here.

It would be a nice feature to have upstream, but not a sufficiently large one to introduce another language in the source mix (even as much as I expect compiler folks to be pro-Rust). If there is a desire to rewrite it in C++ and add to mlir-tblgen, which also has wrappers around relevant record structures that could have made the process a bit easier, it is most welcome.

You won’t find any discussion of Melior here because it is not an LLVM project.

If people like the generated C API for dialect attributes that I’ve prototyped, I could work with a maintainer to reimplement the feature in mlir-tblgen. It is fitting in new code with the existing infrastructure that I could use collaboration (and code review) around, I’m sure I could make it work, just not in as clean and maintainable way as when working with a maintainer.

I volunteer - I’ve wanted this feature forever. When you have a draft you can ping me on it (with an @makslevental) or you can reach out to me on the Discord under the same handle.

(I’ll volunteer as fallback :slight_smile: )