[Mlir-commits] [mlir] [MLIR][TableGen] Add inheritableExtraClassDeclaration/Definition for Op and AttrOrTypeDef (PR #182265)
Henrich Lauko
llvmlistbot at llvm.org
Thu Feb 19 05:58:26 PST 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/182265
>From bee4de8f34676ff975086dff4fea9c623a37745f Mon Sep 17 00:00:00 2001
From: xlauko <xlauko at mail.muni.cz>
Date: Thu, 19 Feb 2026 14:22:18 +0100
Subject: [PATCH] [MLIR][TableGen] Add
inheritableExtraClassDeclaration/Definition for Op and AttrOrTypeDef
---
mlir/include/mlir/IR/AttrTypeBase.td | 9 +++++
mlir/include/mlir/IR/OpBase.td | 9 +++++
mlir/include/mlir/TableGen/AttrOrTypeDef.h | 6 +++
mlir/include/mlir/TableGen/Operator.h | 6 +++
mlir/lib/TableGen/AttrOrTypeDef.cpp | 10 +++++
mlir/lib/TableGen/Operator.cpp | 8 ++++
mlir/test/mlir-tblgen/op-decl-and-defs.td | 45 +++++++++++++++++++++
mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp | 10 ++++-
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 12 +++++-
9 files changed, 111 insertions(+), 4 deletions(-)
diff --git a/mlir/include/mlir/IR/AttrTypeBase.td b/mlir/include/mlir/IR/AttrTypeBase.td
index 16f7f8b532521..eee78eb8c2a94 100644
--- a/mlir/include/mlir/IR/AttrTypeBase.td
+++ b/mlir/include/mlir/IR/AttrTypeBase.td
@@ -250,6 +250,15 @@ class AttrOrTypeDef<string valueType, string name, list<Trait> defTraits,
// replaced by the class name.
code extraClassDefinition = [{}];
+ // Extra class declarations/definitions that are inherited by all derived
+ // classes. These can be set at any level in the class hierarchy. Unlike
+ // extraClassDeclaration/extraClassDefinition, the inheritable values carry
+ // over to all derived classes — both the inheritable and the regular extra
+ // declarations are concatenated in the generated code. A derived class can
+ // discard inherited declarations by setting these to empty [{}].
+ code inheritableExtraClassDeclaration = [{}];
+ code inheritableExtraClassDefinition = [{}];
+
// Generate a default 'getAlias' method for OpAsm{Type,Attr}Interface.
bit genMnemonicAlias = 0;
}
diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td
index 7a667d701ab71..4d288c6fc09f4 100644
--- a/mlir/include/mlir/IR/OpBase.td
+++ b/mlir/include/mlir/IR/OpBase.td
@@ -440,6 +440,15 @@ class Op<Dialect dialect, string mnemonic, list<Trait> props = []> {
// generated code is placed inside the op's C++ namespace. `$cppClass` is
// replaced by the op's C++ class name.
code extraClassDefinition = ?;
+
+ // Extra class declarations/definitions that are inherited by all derived op
+ // classes. These can be set at any level in the class hierarchy. Unlike
+ // extraClassDeclaration/extraClassDefinition, the inheritable values carry
+ // over to all derived ops — both the inheritable and the regular extra
+ // declarations are concatenated in the generated code. A derived class can
+ // discard inherited declarations by setting these to empty [{}].
+ code inheritableExtraClassDeclaration = [{}];
+ code inheritableExtraClassDefinition = [{}];
}
// The arguments of an op.
diff --git a/mlir/include/mlir/TableGen/AttrOrTypeDef.h b/mlir/include/mlir/TableGen/AttrOrTypeDef.h
index 65992f9fef5e9..97888c12ba108 100644
--- a/mlir/include/mlir/TableGen/AttrOrTypeDef.h
+++ b/mlir/include/mlir/TableGen/AttrOrTypeDef.h
@@ -216,6 +216,12 @@ class AttrOrTypeDef {
/// Returns the def's extra class definition code.
std::optional<StringRef> getExtraDefs() const;
+ /// Returns the def's inheritable extra class declaration code.
+ std::optional<StringRef> getInheritableExtraDecls() const;
+
+ /// Returns the def's inheritable extra class definition code.
+ std::optional<StringRef> getInheritableExtraDefs() const;
+
/// Returns true if we need to generate a default 'getAlias' implementation
/// using the mnemonic.
bool genMnemonicAlias() const;
diff --git a/mlir/include/mlir/TableGen/Operator.h b/mlir/include/mlir/TableGen/Operator.h
index f0514d8e61748..ec4d0b94017c9 100644
--- a/mlir/include/mlir/TableGen/Operator.h
+++ b/mlir/include/mlir/TableGen/Operator.h
@@ -303,6 +303,12 @@ class Operator {
/// Returns this op's extra class definition code.
StringRef getExtraClassDefinition() const;
+ /// Returns this op's inheritable extra class declaration code.
+ StringRef getInheritableExtraClassDeclaration() const;
+
+ /// Returns this op's inheritable extra class definition code.
+ StringRef getInheritableExtraClassDefinition() const;
+
/// Returns the Tablegen definition this operator was constructed from.
/// TODO: do not expose the TableGen record, this is a temporary solution to
/// OpEmitter requiring a Record because Operator does not provide enough
diff --git a/mlir/lib/TableGen/AttrOrTypeDef.cpp b/mlir/lib/TableGen/AttrOrTypeDef.cpp
index bf835a860cd5b..f3c6538f6284d 100644
--- a/mlir/lib/TableGen/AttrOrTypeDef.cpp
+++ b/mlir/lib/TableGen/AttrOrTypeDef.cpp
@@ -207,6 +207,16 @@ std::optional<StringRef> AttrOrTypeDef::getExtraDefs() const {
return value.empty() ? std::optional<StringRef>() : value;
}
+std::optional<StringRef> AttrOrTypeDef::getInheritableExtraDecls() const {
+ auto value = def->getValueAsString("inheritableExtraClassDeclaration");
+ return value.empty() ? std::optional<StringRef>() : value;
+}
+
+std::optional<StringRef> AttrOrTypeDef::getInheritableExtraDefs() const {
+ auto value = def->getValueAsString("inheritableExtraClassDefinition");
+ return value.empty() ? std::optional<StringRef>() : value;
+}
+
bool AttrOrTypeDef::genMnemonicAlias() const {
return def->getValueAsBit("genMnemonicAlias");
}
diff --git a/mlir/lib/TableGen/Operator.cpp b/mlir/lib/TableGen/Operator.cpp
index 82dfbcbfa4d4f..0f65f62ed22c0 100644
--- a/mlir/lib/TableGen/Operator.cpp
+++ b/mlir/lib/TableGen/Operator.cpp
@@ -180,6 +180,14 @@ StringRef Operator::getExtraClassDefinition() const {
return def.getValueAsString(attr);
}
+StringRef Operator::getInheritableExtraClassDeclaration() const {
+ return def.getValueAsString("inheritableExtraClassDeclaration");
+}
+
+StringRef Operator::getInheritableExtraClassDefinition() const {
+ return def.getValueAsString("inheritableExtraClassDefinition");
+}
+
const Record &Operator::getDef() const { return def; }
bool Operator::skipDefaultBuilders() const {
diff --git a/mlir/test/mlir-tblgen/op-decl-and-defs.td b/mlir/test/mlir-tblgen/op-decl-and-defs.td
index 80dedb8475b9e..e0a148b0f8baa 100644
--- a/mlir/test/mlir-tblgen/op-decl-and-defs.td
+++ b/mlir/test/mlir-tblgen/op-decl-and-defs.td
@@ -360,6 +360,21 @@ def NS_IOp : NS_Op<"op_with_same_operands_and_result_types_trait", [SameOperands
// CHECK: static IOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::ValueRange operands, const Properties &properties, ::llvm::ArrayRef<::mlir::NamedAttribute> discardableAttributes = {});
// CHECK: static IOp create(::mlir::ImplicitLocOpBuilder &builder, ::mlir::ValueRange operands, const Properties &properties, ::llvm::ArrayRef<::mlir::NamedAttribute> discardableAttributes = {});
+// CHECK-LABEL: NS::InheritableOpA declarations
+// CHECK: int getInheritedHelper();
+// CHECK: void doA();
+
+// CHECK-LABEL: NS::InheritableOpB declarations
+// CHECK: int getInheritedHelper();
+
+// Discard: no inheritable declarations.
+// CHECK-LABEL: NS::InheritableOpC declarations
+// CHECK-NOT: int getInheritedHelper();
+
+// DEFS-LABEL: NS::InheritableOpA definitions
+// DEFS: int InheritableOpA::getInheritedHelper() { return 42; }
+// DEFS: void InheritableOpA::doA() {}
+
// Check default value of `attributes` for the `genInferredTypeCollectiveParamBuilder` builder
def NS_JOp : NS_Op<"op_with_InferTypeOpInterface_interface", [DeclareOpInterfaceMethods<InferTypeOpInterface>]> {
let arguments = (ins AnyType:$a, AnyType:$b);
@@ -551,3 +566,33 @@ def _TypeInferredPropOp : NS_Op<"type_inferred_prop_op_with_properties", [
let results = (outs AnyType:$result);
let hasCustomAssemblyFormat = 1;
}
+
+// Test inheritable extra class declarations/definitions.
+class NS_InheritableOp<string mnemonic, list<Trait> traits = []>
+ : NS_Op<mnemonic, traits> {
+ let inheritableExtraClassDeclaration = [{
+ int getInheritedHelper();
+ }];
+ let inheritableExtraClassDefinition = [{
+ int $cppClass::getInheritedHelper() { return 42; }
+ }];
+}
+
+// Both inheritable and regular extra declarations should appear.
+def NS_InheritableOpA : NS_InheritableOp<"inheritable_op_a"> {
+ let extraClassDeclaration = [{
+ void doA();
+ }];
+ let extraClassDefinition = [{
+ void $cppClass::doA() {}
+ }];
+}
+
+// Only inheritable declarations (no extraClassDeclaration).
+def NS_InheritableOpB : NS_InheritableOp<"inheritable_op_b"> {}
+
+// Discard inheritable declarations by setting to empty.
+def NS_InheritableOpC : NS_InheritableOp<"inheritable_op_c"> {
+ let inheritableExtraClassDeclaration = [{}];
+ let inheritableExtraClassDefinition = [{}];
+}
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
index 031e03071842f..f2d8a4397ebcf 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
@@ -273,7 +273,10 @@ void DefGen::createParentWithTraits() {
/// Include declarations specified on NativeTrait
static std::string formatExtraDeclarations(const AttrOrTypeDef &def) {
SmallVector<StringRef> extraDeclarations;
- // Include extra class declarations from NativeTrait
+ // Include inheritable extra class declarations.
+ if (std::optional<StringRef> inheritable = def.getInheritableExtraDecls())
+ extraDeclarations.push_back(*inheritable);
+ // Include extra class declarations from NativeTrait.
for (const auto &trait : def.getTraits()) {
if (auto *attrOrTypeTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {
StringRef value = attrOrTypeTrait->getExtraConcreteClassDeclaration();
@@ -292,7 +295,10 @@ static std::string formatExtraDeclarations(const AttrOrTypeDef &def) {
/// replaced by the C++ class name.
static std::string formatExtraDefinitions(const AttrOrTypeDef &def) {
SmallVector<StringRef> extraDefinitions;
- // Include extra class definitions from NativeTrait
+ // Include inheritable extra class definitions.
+ if (std::optional<StringRef> inheritable = def.getInheritableExtraDefs())
+ extraDefinitions.push_back(*inheritable);
+ // Include extra class definitions from NativeTrait.
for (const auto &trait : def.getTraits()) {
if (auto *attrOrTypeTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {
StringRef value = attrOrTypeTrait->getExtraConcreteClassDefinition();
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index d1f1e85371133..3556a7504e627 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1164,7 +1164,11 @@ static void genPropertyVerifier(
/// Include declarations specified on NativeTrait
static std::string formatExtraDeclarations(const Operator &op) {
SmallVector<StringRef> extraDeclarations;
- // Include extra class declarations from NativeTrait
+ // Include inheritable extra class declarations.
+ StringRef inheritable = op.getInheritableExtraClassDeclaration();
+ if (!inheritable.empty())
+ extraDeclarations.push_back(inheritable);
+ // Include extra class declarations from NativeTrait.
for (const auto &trait : op.getTraits()) {
if (auto *opTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {
StringRef value = opTrait->getExtraConcreteClassDeclaration();
@@ -1182,7 +1186,11 @@ static std::string formatExtraDeclarations(const Operator &op) {
/// Include declarations specified on NativeTrait
static std::string formatExtraDefinitions(const Operator &op) {
SmallVector<StringRef> extraDefinitions;
- // Include extra class definitions from NativeTrait
+ // Include inheritable extra class definitions.
+ StringRef inheritable = op.getInheritableExtraClassDefinition();
+ if (!inheritable.empty())
+ extraDefinitions.push_back(inheritable);
+ // Include extra class definitions from NativeTrait.
for (const auto &trait : op.getTraits()) {
if (auto *opTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {
StringRef value = opTrait->getExtraConcreteClassDefinition();
More information about the Mlir-commits
mailing list