[Mlir-commits] [mlir] [mlir-tblgen] Render enum keyword alternatives in generated attr/type docs (PR #203677)
Maksim Levental
llvmlistbot at llvm.org
Sat Jun 13 08:54:00 PDT 2026
https://github.com/makslevental updated https://github.com/llvm/llvm-project/pull/203677
>From bd6c6fa2345f5976d8f495a0eb051a8949cb8bd5 Mon Sep 17 00:00:00 2001
From: Maksim Levental <maksim.levental at gmail.com>
Date: Fri, 12 Jun 2026 23:27:02 -0700
Subject: [PATCH 1/3] [mlir-tblgen] Render enum keyword alternatives in
generated attr/type docs
When mlir-tblgen generates documentation for AttrDefs/TypeDefs that have
EnumParameter fields, it previously rendered the raw C++ type (e.g.
`::mlir::ns::MyEnum`) in the syntax block. This was unhelpful for
users who need to know the valid keyword values.
This patch:
1. Adds an `EnumInfo enum = enumInfo;` field to the `EnumParameter`
TableGen class, persisting the enum record for tooling to inspect.
2. Modifies `emitAttrOrTypeDefAssemblyFormat` in OpDocGen.cpp to detect
EnumParameter fields and render their cases as backtick-quoted
alternatives (e.g. `` `read` | `read_write` ``).
3. Adds a test case to gen-dialect-doc.td verifying the new behavior.
Before:
#my_dialect.my_attr<
int32_t, # index
::mlir::ns::MyEnum, # access
>
After:
#my_dialect.my_attr<
int32_t, # index
`read` | `read_write`, # access
>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
mlir/include/mlir/IR/EnumAttr.td | 3 +++
mlir/test/mlir-tblgen/gen-dialect-doc.td | 25 ++++++++++++++++++++++++
mlir/tools/mlir-tblgen/OpDocGen.cpp | 24 ++++++++++++++++++++++-
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/mlir/include/mlir/IR/EnumAttr.td b/mlir/include/mlir/IR/EnumAttr.td
index 6eef5075fe18a..5f3384e95ba79 100644
--- a/mlir/include/mlir/IR/EnumAttr.td
+++ b/mlir/include/mlir/IR/EnumAttr.td
@@ -503,6 +503,9 @@ class I64BitEnumAttr<string name, string summary,
class EnumParameter<EnumInfo enumInfo>
: AttrParameter<enumInfo.cppNamespace # "::" # enumInfo.className,
"an enum of type " # enumInfo.className> {
+ // Store the enum info so that tooling (e.g. doc generation) can inspect the
+ // enum cases without re-parsing the C++ type string.
+ EnumInfo enum = enumInfo;
let parser = !if(!isa<EnumAttrInfo>(enumInfo),
!cast<EnumAttrInfo>(enumInfo).parameterParser, ?);
let printer = !if(!isa<EnumAttrInfo>(enumInfo),
diff --git a/mlir/test/mlir-tblgen/gen-dialect-doc.td b/mlir/test/mlir-tblgen/gen-dialect-doc.td
index 72916704369ee..c373f3fb6801b 100644
--- a/mlir/test/mlir-tblgen/gen-dialect-doc.td
+++ b/mlir/test/mlir-tblgen/gen-dialect-doc.td
@@ -67,6 +67,24 @@ def TestAttrDefParams : AttrDef<Test_Dialect, "TestAttrDefParams"> {
let assemblyFormat = "`<` $value `>`";
}
+def TestEnumForParam :
+ I32EnumAttr<"TestEnumForParam",
+ "enum for param test", [
+ I32EnumAttrCase<"Alpha", 0, "alpha">,
+ I32EnumAttrCase<"Beta", 1, "beta">]> {
+ let genSpecializedAttr = 0;
+ let cppNamespace = "NS";
+}
+
+def TestAttrWithEnum : AttrDef<Test_Dialect, "TestAttrWithEnum"> {
+ let mnemonic = "with_enum";
+ let parameters = (ins
+ "int":$value,
+ EnumParameter<TestEnumForParam>:$mode
+ );
+ let assemblyFormat = "`<` $value `,` $mode `>`";
+}
+
def TestTypeDef : TypeDef<Test_Dialect, "TestTypeDef"> {
let mnemonic = "test_type_def";
}
@@ -140,6 +158,13 @@ def TestEnum :
// CHECK: Syntax:
// CHECK: #test.test_attr_def_params
+// CHECK: TestAttrWithEnumAttr
+// CHECK: Syntax:
+// CHECK: #test.with_enum<
+// CHECK-NEXT: int, # value
+// CHECK-NEXT: `alpha` | `beta` # mode
+// CHECK-NEXT: >
+
// CHECK: ## Type constraints
// CHECK: ### type summary
// CHECK: type description
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index 5e3cf302ed3ea..7c050dbb08a3b 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -384,6 +384,25 @@ static void emitTypeDoc(const Type &type, raw_ostream &os) {
// TypeDef Documentation
//===----------------------------------------------------------------------===//
+/// If \p param is an EnumParameter, return a string listing the enum's keyword
+/// alternatives (e.g. "`read` | `read_write`"). Otherwise return std::nullopt.
+static std::optional<std::string>
+getEnumParameterDocSyntax(const AttrOrTypeParameter ¶m) {
+ const auto *paramDef = dyn_cast<DefInit>(param.getDef());
+ if (!paramDef || !paramDef->getDef()->isSubClassOf("EnumParameter"))
+ return std::nullopt;
+ const Record *enumRec = paramDef->getDef()->getValueAsDef("enum");
+ EnumInfo enumInfo(enumRec);
+ std::vector<EnumCase> cases = enumInfo.getAllCases();
+ std::string result;
+ for (const auto &caseIt : llvm::enumerate(cases)) {
+ if (caseIt.index() > 0)
+ result += " | ";
+ result += (llvm::Twine("`") + caseIt.value().getStr() + "`").str();
+ }
+ return result;
+}
+
static void emitAttrOrTypeDefAssemblyFormat(const AttrOrTypeDef &def,
raw_ostream &os) {
ArrayRef<AttrOrTypeParameter> parameters = def.getParameters();
@@ -399,7 +418,10 @@ static void emitAttrOrTypeDefAssemblyFormat(const AttrOrTypeDef &def,
<< "<\n";
for (const auto &it : llvm::enumerate(parameters)) {
const AttrOrTypeParameter ¶m = it.value();
- os << " " << param.getSyntax();
+ if (auto enumSyntax = getEnumParameterDocSyntax(param))
+ os << " " << *enumSyntax;
+ else
+ os << " " << param.getSyntax();
if (it.index() < (parameters.size() - 1))
os << ",";
os << " # " << param.getName() << "\n";
>From f29b6c0f70c616fd0096e1115b520c20cd8e29d6 Mon Sep 17 00:00:00 2001
From: Maksim Levental <maksim.levental at gmail.com>
Date: Sat, 13 Jun 2026 06:27:21 -0700
Subject: [PATCH 2/3] Update mlir/tools/mlir-tblgen/OpDocGen.cpp
Co-authored-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
mlir/tools/mlir-tblgen/OpDocGen.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index 7c050dbb08a3b..d91b134764b28 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -384,7 +384,7 @@ static void emitTypeDoc(const Type &type, raw_ostream &os) {
// TypeDef Documentation
//===----------------------------------------------------------------------===//
-/// If \p param is an EnumParameter, return a string listing the enum's keyword
+/// If `param` is an EnumParameter, return a string listing the enum's keyword
/// alternatives (e.g. "`read` | `read_write`"). Otherwise return std::nullopt.
static std::optional<std::string>
getEnumParameterDocSyntax(const AttrOrTypeParameter ¶m) {
>From 47001d7786004f3383537c7643d6fe64e2b51db6 Mon Sep 17 00:00:00 2001
From: makslevental <m_levental at apple.com>
Date: Sat, 13 Jun 2026 08:53:46 -0700
Subject: [PATCH 3/3] address comment
---
mlir/tools/mlir-tblgen/OpDocGen.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index d91b134764b28..971039d31ed34 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -395,11 +395,9 @@ getEnumParameterDocSyntax(const AttrOrTypeParameter ¶m) {
EnumInfo enumInfo(enumRec);
std::vector<EnumCase> cases = enumInfo.getAllCases();
std::string result;
- for (const auto &caseIt : llvm::enumerate(cases)) {
- if (caseIt.index() > 0)
- result += " | ";
- result += (llvm::Twine("`") + caseIt.value().getStr() + "`").str();
- }
+ llvm::interleave(
+ cases, [&](const EnumCase &c) { result += "`" + c.getStr().str() + "`"; },
+ [&] { result += " | "; });
return result;
}
More information about the Mlir-commits
mailing list