[Mlir-commits] [mlir] [mlir-tblgen] Render enum keyword alternatives in generated attr/type docs (PR #203677)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Jun 12 23:40:09 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-ods

@llvm/pr-subscribers-mlir

Author: Maksim Levental (makslevental)

<details>
<summary>Changes</summary>

When mlir-tblgen generates documentation for AttrDefs/TypeDefs that have EnumParameter fields, it previously rendered the raw C++ type (e.g. `::mlir::BufferAccess`) 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:
```
  #kernel_arg<
    int32_t,   # index
    ::mlir::BufferAccess,   # access
  >
```

After:
```
  #kernel_arg<
    int32_t,   # index
    `read` | `read_write`,   # access
  >
```

Co-Authored-By: Claude Opus 4.6

---
Full diff: https://github.com/llvm/llvm-project/pull/203677.diff


3 Files Affected:

- (modified) mlir/include/mlir/IR/EnumAttr.td (+3) 
- (modified) mlir/test/mlir-tblgen/gen-dialect-doc.td (+25) 
- (modified) mlir/tools/mlir-tblgen/OpDocGen.cpp (+23-1) 


``````````diff
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 &param) {
+  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 &param = 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";

``````````

</details>


https://github.com/llvm/llvm-project/pull/203677


More information about the Mlir-commits mailing list