Other than the DeclareOpInterfaceMethods this seems identical in terms of information isn’t it?
And so injecting the DeclareOpInterfaceMethods in the base class (SPV_Op) or just leaving this as is here seems fine to me.
You could have SPV_Op
add those in ODS, that is why we have base classes for the ops, and so have class SPV_Op
adding those or using “mix in” trait. Given the lazy evaluation semantics, one could even modify the traits of the op inside the class (that may make it more complicated, one would actually need to prototype it to see the cost/complexity). The point is not about specifics, but rather the general that this need not make adding ops much more complicated and that that complexity could be captured in the base class for the ops.
Injecting it at base SPV_Op
class means all ops are forced to implement all these interfaces. A large portion of ops (e.g., arithmetic ops) simply do not have any version/extension/capability requirement at all. That would be unfortunate to still generate all the interface implementation for all of them. It bloats the library and makes availability probing slower compared to just check isa<*Interface>
.
Having DeclareOpInterfaceMethods
on each of the op (or letting each op to override the base one, which is the same) is duplicating information. It would be tolerable if there is only a handful of such cases, but many ops are gated by versions/capabilities/extensions and cases can be quite diverse: op A may have max-version & capability requirement, op B may have min-version & extension requirement, etc. That means a large amount of duplication. I don’t think that goes with the general philosophy of ODS of trying to have single source of truth.
Besides, the availability
field directly in a SPIR-V op definition is just for the opcode itself. If I have an opcode itself is available from, say, version 1.1 and the op has an enum attribute that has a value whose availability requires, say, an capability Shader
, then the op should declare two interface, one for the min version, one for the capability. Now it’s all manual: whoever adding the op needs to write the argument list, and also check all argument’s availability requirements and figure out what additional interfaces are. It’s more tedious and error prone than letting an ODS hook to look at the op and its argument list to figure out what traits to add programmatically.
Right, back to my question: how do you get this compiled in the tblgen binary is still what I’m after.
The tblgen binary is standalone and does not link any dialect. An out-of-tree user does not need to modify the MLIR tblgen binary today to use ODS.
IIUC, the mlir-*
tools are just binaries for MLIR core’s own use and we said other projects are free to define their own ones wherever suitable. For example, we have tf-opt
in TensorFlow to use instead of mlir-opt
.
My understanding is that, one can define its own my-tblgen
like
add_tablegen(my-tblgen
MyOwnGen.cpp
${MLIR_SOURCE_DIR}/[tools/mlir-tblgen/OpDefinitionsGen.cpp](http://tools/mlir-tblgen/OpDefinitionsGen.cpp)
MyODSHook.cpp
)
and then use my-tblgen
to generate stuff.
If we do look at the specifics, isn’t an example of something we want a general interface for and this is just a prototype for SpirV to get experience with approach before a general one is created? General versioning is the goal. So the complexity in the base class would only persist until then. Now of course, different folks might have different requirements, and in which case this amounts to two traits extra per op defined.
This is a good point. If the op availability mechanism is integrated directly into base Op
and other definitions, I guess my use case can be solved too. The problem is mainly that the generated C++ class for the op is closed so adding traits pragmatically is not possible, if not touching existing OpDefintionsGen
.
I think its good to highlight what could be done with this extension rather than custom TableGen backend (as we use for exporting tflite flatbuffers for example, we didn’t modify mlir-tblgen). I’d say my main concern would be that ODS’s C++ classes are not stable, I wouldn’t even call them an unstable API. So we might change 90% of them and this seems to open that more/provide less structure. And then it is less clear when they should use this vs create a new backend
A custom TableGen backend definitely takes full control of everything. But I think still we cannot easily have additional contents plus all the ODS generated contents for op classes, unless we want to duplicate all the logic already existing in ODS and modify the code in the new TableGen backend. I think that should not be a favorable approach.
I proposed this because @nicolasvasilache told me that he also has a use case. So I think this can be a general useful feature to have. But maybe Nicolas also has his own workarounds for things.