diff --git a/mlir/docs/AttributesAndTypes.md b/mlir/docs/AttributesAndTypes.md --- a/mlir/docs/AttributesAndTypes.md +++ b/mlir/docs/AttributesAndTypes.md @@ -1065,13 +1065,16 @@ 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 diff --git a/mlir/include/mlir/IR/AttrTypeBase.td b/mlir/include/mlir/IR/AttrTypeBase.td --- a/mlir/include/mlir/IR/AttrTypeBase.td +++ b/mlir/include/mlir/IR/AttrTypeBase.td @@ -223,6 +223,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 diff --git a/mlir/include/mlir/TableGen/AttrOrTypeDef.h b/mlir/include/mlir/TableGen/AttrOrTypeDef.h --- a/mlir/include/mlir/TableGen/AttrOrTypeDef.h +++ b/mlir/include/mlir/TableGen/AttrOrTypeDef.h @@ -201,6 +201,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; diff --git a/mlir/include/mlir/TableGen/Class.h b/mlir/include/mlir/TableGen/Class.h --- a/mlir/include/mlir/TableGen/Class.h +++ b/mlir/include/mlir/TableGen/Class.h @@ -557,7 +557,7 @@ StringRef extraClassDeclaration; /// The string of the extra class definitions. It is re-indented before /// printed. - StringRef extraClassDefinition; + std::string extraClassDefinition; }; /// A class used to emit C++ classes from Tablegen. Contains a list of public diff --git a/mlir/lib/TableGen/AttrOrTypeDef.cpp b/mlir/lib/TableGen/AttrOrTypeDef.cpp --- a/mlir/lib/TableGen/AttrOrTypeDef.cpp +++ b/mlir/lib/TableGen/AttrOrTypeDef.cpp @@ -179,6 +179,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 { diff --git a/mlir/test/mlir-tblgen/attrdefs.td b/mlir/test/mlir-tblgen/attrdefs.td --- a/mlir/test/mlir-tblgen/attrdefs.td +++ b/mlir/test/mlir-tblgen/attrdefs.td @@ -158,3 +158,23 @@ // DECL-LABEL: class BuilderWithReturnTypeAttr // DECL: ::mlir::Attribute get( // DECL: ::mlir::Attribute getChecked( + +def H_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: } diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp --- a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp +++ b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp @@ -214,14 +214,26 @@ defCls.addParent(std::move(defParent)); } +/// Extra class definitions have a `$cppClass` substitution that is to be +/// replaced by the C++ class name. +static std::string formatExtraDefinitions(const AttrOrTypeDef &def) { + if (Optional extraDef = def.getExtraDefs()) { + FmtContext ctx = FmtContext().addSubst("cppClass", def.getCppClassName()); + return tgfmt(*extraDef, &ctx).str(); + } + return ""; +} + void DefGen::emitTopLevelDeclarations() { // Inherit constructors from the attribute or type class. defCls.declare(Visibility::Public); defCls.declare("Base::Base"); // Emit the extra declarations first in case there's a definition in there. - if (Optional extraDecl = def.getExtraDecls()) - defCls.declare(*extraDecl); + Optional extraDecl = def.getExtraDecls(); + std::string extraDef = formatExtraDefinitions(def); + defCls.declare(extraDecl ? *extraDecl : "", + std::move(extraDef)); } void DefGen::emitBuilders() {