There seems to be conflicting or missing information on how EnumAttr should be used successfully. I read through whatever code and write-ups I could find - e.g. mlir/IR/EnumAttr.td, the generated .inc files, mlir reference etc etc, and tried several different ways, but each time I try to have the Enum attribute as an Op argument I run into myriad of problems.
Below is one attempt and error.
def MyEnum: I32EnumAttr<"MyEnum", "my enum tries", [
I32EnumAttrCase<"RED", 0>,
I32EnumAttrCase<"GREEN", 1>,
I32EnumAttrCase<"BLUE", 2> ]> {
let genSpecializedAttr = 0;
let cppNamespace = "::mlir::MyDialect";
}
def MyEnumAttr : EnumAttr<MyDialect, MyEnum, "my_enum">;
def MyOp : MyDialect_Op<"myOp"> {
let summary = "Trying to get enumAttr to work in an op";
let description = [{ }];
let arguments = (ins MyTensorType:$src,
MyEnumAttr:$method);
let results = (outs MyTensorType:$dst);
let assemblyFormat =
"$src $method attr-dict `:` type($src) `->` type($dst)";
}
Error:
error: format ambiguity caused by `:` literal found after attribute `method` which does not have a buildable type
$src $method attr-dict `:` type($src) `->` type($dst)
Based on my previous attempts, I think the problem is in how I am using EnumAttr. If I use MyEnum directly into the MyOp (instead of MyEnumAttr) it compiles but gives new series of errors.
Please have a look at the above code . There MUST be a straightforward way of doing this as I am not doing anything fancy up here except trying to use Enum. I have lots of existing codes w/o Enum that works all fine.
If you look at the error message, it’s complaining about the operation assembly format.
Any attribute with a non-buildable type in an operation assembly format followed by the literal : is a format ambiguity, even with attr-dict in between because it is optional. This is because attributes optionally have types that are parsed separately from the attribute itself: when parsing attributes, the parser looks ahead to find and parse a colon-type.
Regular enums have special handling in the assembly format generator (which is deprecated and will be removed). I will check if a buildable type can be added to enum attributes, which would allow this syntax. For now, you will need to avoid having : after the enum attribute.
Alternatively, you can add a buildable type to the EnumAttr by specifying valueType, a Type that has builderCall, e.g.
I tried changing both above and it just gives new errors.
All I really want to know is how to implement in MLiR a simple Enum attribute e.g. enum Color { RED, GREEN, BLUE };
What should the tablegen description of ir should be to fit in properly into an Op, if my Op has as argument something like let arguments = (ins MyTensorType:$src, ColorAttr:$colour);
My definition of ColorAttr is (for which I just followed mlir/IR/EnumAttr.td):
The MLIR ref doc states , " To facilitate the interaction between *EnumAttrs and their C++ consumers, …TableGen backend can generate a few common utilities: … conversion functions from/to strings.". But the above code fails with error:
.cpp.inc:1017:29: error: ‘::symbolizeColor’ has not been declared
From above it looks like the default symbolize/stringify were not generated.
any thoughts ? I think an answer to this will not only help me but anyone else who comes along new to using EnumAttr in their implementation.
Thanks a lot.
This is controlled via the `-gen-enum-decls` and `-gen-enum-defs` command-line options of `mlir-tblgen` .
Have you modified the CMakeLists.txt to invoke mlir-tblgen with those command line options? (You can look at llvm/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt for an example.)
If you are generating the enum sources, it may just be a matter of adding a #include for the generated enum header. As an example, in the LLVM dialect header (llvm/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h) you will see the following line:
Yes I had those -gen-enum-decls and -gen-enum-defs commands and Enum definitions are generated already. The problem is more intricate I am afraid and lies somewhere else actually.
Kiran, actually your code highlights another concern which is not clear in MLIR. ‘ScheduleModifier’ is already an EnumAttr, so why did you need to wrap it into another ‘EnumAttr’ (ScheduleModifierAttr) ?
In case it’s helpful, a few weeks ago I migrated the CIRCT codebase to use the new EnumAttr API, and in my GitHub Pull Request description, I wrote up a bit of information about the new APIs: https://github.com/llvm/circt/pull/2901
It may not be immediately obvious, but there is indeed an additional layer of nested compared to the older APIs. The key thing to keep in mind is that the I32EnumAttr contains more of the pure Enum-like behavior (i.e. representing an enumeration of values), while the EnumAttr contains more of the Attr-like behavior (something that is attached to Ops).