Index: mlir/docs/AttributesAndTypes.md =================================================================== --- mlir/docs/AttributesAndTypes.md +++ mlir/docs/AttributesAndTypes.md @@ -1038,17 +1038,20 @@ }; ``` -### Extra declarations +### Extra declarations and definitions The declarative Attribute and Type definitions try to auto-generate as much logic and methods as possible. With that said, there will always be long-tail -cases that won't be covered. For such cases, `extraClassDeclaration` can be -used. Code within the `extraClassDeclaration` field will be copied literally to -the generated C++ Attribute or Type class. - -Note that `extraClassDeclaration` is a mechanism intended for long-tail cases by -power users; for not-yet-implemented widely-applicable cases, improving the -infrastructure is preferable. +cases that won't be covered. For such cases, `extraClassDeclaration` and +`extraClassDefinition` can be used. Code within the `extraClassDeclaration` +field will be copied literally to the generated C++ Attribute or Type class. +Code within `extraClassDefinition` will be added to the generated source file +inside the class's C++ namespace. The substitution `$cppClass` will be replaced +by the Attribute or Type's C++ class name. + +Note that these are mechanisms intended for long-tail cases by power users; for +not-yet-implemented widely-applicable cases, improving the infrastructure is +preferable. ### Registering with the Dialect Index: mlir/include/mlir/IR/AttrTypeBase.td =================================================================== --- mlir/include/mlir/IR/AttrTypeBase.td +++ mlir/include/mlir/IR/AttrTypeBase.td @@ -215,6 +215,11 @@ // Extra code to include in the class declaration. code extraClassDeclaration = [{}]; + + // Additional code that will be added to the generated source file. The + // generated code is placed inside the class's C++ namespace. `$cppClass` is + // replaced by the class name. + code extraClassDefinition = [{}]; } // Define a new attribute, named `name`, belonging to `dialect` that inherits Index: mlir/include/mlir/TableGen/AttrOrTypeDef.h =================================================================== --- mlir/include/mlir/TableGen/AttrOrTypeDef.h +++ mlir/include/mlir/TableGen/AttrOrTypeDef.h @@ -198,6 +198,9 @@ /// Returns the def's extra class declaration code. Optional getExtraDecls() const; + /// Returns the def's extra class definition code. + Optional getExtraDefs() const; + /// Get the code location (for error printing). ArrayRef getLoc() const; Index: mlir/lib/TableGen/AttrOrTypeDef.cpp =================================================================== --- mlir/lib/TableGen/AttrOrTypeDef.cpp +++ mlir/lib/TableGen/AttrOrTypeDef.cpp @@ -175,6 +175,11 @@ return value.empty() ? Optional() : value; } +Optional AttrOrTypeDef::getExtraDefs() const { + auto value = def->getValueAsString("extraClassDefinition"); + return value.empty() ? Optional() : value; +} + ArrayRef AttrOrTypeDef::getLoc() const { return def->getLoc(); } bool AttrOrTypeDef::skipDefaultBuilders() const { Index: mlir/test/mlir-tblgen/attrdefs.td =================================================================== --- mlir/test/mlir-tblgen/attrdefs.td +++ mlir/test/mlir-tblgen/attrdefs.td @@ -148,3 +148,23 @@ // DEF: ParamWithAccessorTypeAttrStorage // DEF: ParamWithAccessorTypeAttrStorage(std::string param) // DEF: StringRef ParamWithAccessorTypeAttr::getParam() + +def G_TestExtraClassAttr : TestAttr<"TestExtraClass"> { + let extraClassDeclaration = [{ + /// Test Method + static int getFoo(int i); + }]; + let extraClassDefinition = [{ + int $cppClass::getFoo(int i) { + return i+1; + } + }]; +} + +// DECL-LABEL: TestExtraClassAttr : public ::mlir::Attribute +// DECL: /// Test Method +// DECL-NEXT: static int getFoo(int i); + +// DEF-LABEL: int TestExtraClassAttr::getFoo(int i) { +// DEF: return i+1; +// DEF-NEXT: } Index: mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp =================================================================== --- mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp +++ mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp @@ -97,6 +97,8 @@ void emitAccessors(); /// Emit interface methods. void emitInterfaceMethods(); + /// Emit extra class definition, if specified. + void emitExtraClassDefinition(); //===--------------------------------------------------------------------===// // Builder Emission @@ -157,6 +159,8 @@ StringRef valueType; /// The prefix/suffix of the TableGen def name, either "Attr" or "Type". StringRef defType; + /// Hand-written extra class definitions. + std::string extraClassDefinition; }; } // namespace @@ -191,6 +195,8 @@ emitAccessors(); // Emit trait interface methods emitInterfaceMethods(); + // Emit hand written class definitions + emitExtraClassDefinition(); defCls.finalize(); // Emit a storage class if one is needed if (storageCls && def.genStorageClass()) @@ -214,6 +220,14 @@ defCls.addParent(std::move(defParent)); } +void DefGen::emitExtraClassDefinition() { + if (Optional extraDef = def.getExtraDefs()) { + FmtContext ctx = FmtContext().addSubst("cppClass", def.getCppClassName()); + extraClassDefinition = tgfmt(*extraDef, &ctx).str(); + defCls.declare("", extraClassDefinition); + } +} + void DefGen::emitTopLevelDeclarations() { // Inherit constructors from the attribute or type class. defCls.declare(Visibility::Public);