[Mlir-commits] [mlir] Add support for enum doc gen (PR #98885)

Tom Natan llvmlistbot at llvm.org
Mon Jul 15 12:21:40 PDT 2024


https://github.com/tomnatan30 updated https://github.com/llvm/llvm-project/pull/98885

>From 41c2c0c0c8915c5530e0aead04ff9c3e3befa4d8 Mon Sep 17 00:00:00 2001
From: tomnatan30 <tomnatan at google.com>
Date: Mon, 15 Jul 2024 11:13:15 +0000
Subject: [PATCH 1/4] add support for enum doc gen

---
 mlir/test/mlir-tblgen/gen-dialect-doc.td | 21 +++++++
 mlir/tools/mlir-tblgen/OpDocGen.cpp      | 73 +++++++++++++++++++++---
 2 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/mlir/test/mlir-tblgen/gen-dialect-doc.td b/mlir/test/mlir-tblgen/gen-dialect-doc.td
index c9492eb9ac3ce..79d755111e8f6 100644
--- a/mlir/test/mlir-tblgen/gen-dialect-doc.td
+++ b/mlir/test/mlir-tblgen/gen-dialect-doc.td
@@ -3,6 +3,7 @@
 
 include "mlir/IR/OpBase.td"
 include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/EnumAttr.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
 
 def Test_Dialect : Dialect {
@@ -69,6 +70,16 @@ def TestTypeDefParams : TypeDef<Test_Dialect, "TestTypeDefParams"> {
   let assemblyFormat = "`<` $value `>`";
 }
 
+def TestEnum :
+    I32EnumAttr<"TestEnum",
+        "enum summary", [
+        I32EnumAttrCase<"First", 0, "first">,
+        I32EnumAttrCase<"Second", 1, "second">,
+        I32EnumAttrCase<"Third", 2, "third">]> {
+  let genSpecializedAttr = 1;
+  let cppNamespace = "NS";
+}
+
 // CHECK: Dialect without a [TOC] here.
 // CHECK: TOC added by tool.
 // CHECK: [TOC]
@@ -109,6 +120,16 @@ def TestTypeDefParams : TypeDef<Test_Dialect, "TestTypeDefParams"> {
 // CHECK: Syntax:
 // CHECK: !test.test_type_def_params
 
+// CHECK: ## Enums
+// CHECK: ### TestEnum
+// CHECK: enum summary
+// CHECK: #### Cases:
+// CHECK: | Symbol | Value | String |
+// CHECK: | :----: | :---: | ------ |
+// CHECK: | First | `0` | first |
+// CHECK: | Second | `1` | second |
+// CHECK: | Third | `2` | third |
+
 def Toc_Dialect : Dialect {
   let name = "test_toc";
   let summary = "Dialect of ops to test";
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index 7cd2690ea8155..d55414d7b95f8 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -16,6 +16,7 @@
 #include "OpGenHelpers.h"
 #include "mlir/Support/IndentedOstream.h"
 #include "mlir/TableGen/AttrOrTypeDef.h"
+#include "mlir/TableGen/Attribute.h"
 #include "mlir/TableGen/GenInfo.h"
 #include "mlir/TableGen/Operator.h"
 #include "llvm/ADT/DenseMap.h"
@@ -37,7 +38,7 @@
 // Commandline Options
 //===----------------------------------------------------------------------===//
 static llvm::cl::OptionCategory
-    docCat("Options for -gen-(attrdef|typedef|op|dialect)-doc");
+    docCat("Options for -gen-(attrdef|typedef|enum|op|dialect)-doc");
 llvm::cl::opt<std::string>
     stripPrefix("strip-prefix",
                 llvm::cl::desc("Strip prefix of the fully qualified names"),
@@ -381,6 +382,38 @@ static void emitAttrOrTypeDefDoc(const RecordKeeper &recordKeeper,
     emitAttrOrTypeDefDoc(AttrOrTypeDef(def), os);
 }
 
+//===----------------------------------------------------------------------===//
+// Enum Documentation
+//===----------------------------------------------------------------------===//
+
+static void emitEnumDoc(const EnumAttr &def, raw_ostream &os) {
+  os << llvm::formatv("### {0}\n", def.getEnumClassName());
+
+  // Emit the summary if present.
+  if (!def.getSummary().empty())
+    os << "\n" << def.getSummary() << "\n";
+
+  // Emit case documentation.
+  std::vector<EnumAttrCase> cases = def.getAllCases();
+  os << "\n#### Cases:\n\n";
+  os << "| Symbol | Value | String |\n"
+     << "| :----: | :---: | ------ |\n";
+  for (const auto &it : cases) {
+    os << "| " << it.getSymbol() << " | `" << it.getValue() << "` | "
+        << it.getStr() << " |\n";
+  }
+
+  os << "\n";
+}
+
+static void emitEnumDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
+  std::vector<llvm::Record *> defs =
+      recordKeeper.getAllDerivedDefinitions("EnumAttr");
+
+  os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
+  for (const llvm::Record *def : defs) emitEnumDoc(EnumAttr(def), os);
+}
+
 //===----------------------------------------------------------------------===//
 // Dialect Documentation
 //===----------------------------------------------------------------------===//
@@ -413,7 +446,7 @@ static void maybeNest(bool nest, llvm::function_ref<void(raw_ostream &os)> fn,
 static void emitBlock(ArrayRef<Attribute> attributes, StringRef inputFilename,
                       ArrayRef<AttrDef> attrDefs, ArrayRef<OpDocGroup> ops,
                       ArrayRef<Type> types, ArrayRef<TypeDef> typeDefs,
-                      raw_ostream &os) {
+                      ArrayRef<EnumAttr> enums, raw_ostream &os) {
   if (!ops.empty()) {
     os << "## Operations\n\n";
     emitSourceLink(inputFilename, os);
@@ -459,13 +492,19 @@ static void emitBlock(ArrayRef<Attribute> attributes, StringRef inputFilename,
     for (const TypeDef &def : typeDefs)
       emitAttrOrTypeDefDoc(def, os);
   }
+
+  if (!enums.empty()) {
+    os << "## Enums\n\n";
+    for (const EnumAttr &def : enums)
+      emitEnumDoc(def, os);
+  }
 }
 
 static void emitDialectDoc(const Dialect &dialect, StringRef inputFilename,
                            ArrayRef<Attribute> attributes,
                            ArrayRef<AttrDef> attrDefs, ArrayRef<OpDocGroup> ops,
                            ArrayRef<Type> types, ArrayRef<TypeDef> typeDefs,
-                           raw_ostream &os) {
+                           ArrayRef<EnumAttr> enums, raw_ostream &os) {
   os << "# '" << dialect.getName() << "' Dialect\n\n";
   emitIfNotEmpty(dialect.getSummary(), os);
   emitIfNotEmpty(dialect.getDescription(), os);
@@ -475,7 +514,8 @@ static void emitDialectDoc(const Dialect &dialect, StringRef inputFilename,
   if (!r.match(dialect.getDescription()))
     os << "[TOC]\n\n";
 
-  emitBlock(attributes, inputFilename, attrDefs, ops, types, typeDefs, os);
+  emitBlock(attributes, inputFilename, attrDefs, ops, types, typeDefs, enums,
+            os);
 }
 
 static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
@@ -495,21 +535,30 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
       recordKeeper.getAllDerivedDefinitionsIfDefined("TypeDef");
   std::vector<Record *> attrDefDefs =
       recordKeeper.getAllDerivedDefinitionsIfDefined("AttrDef");
+  std::vector<Record *> enumDefs =
+      recordKeeper.getAllDerivedDefinitionsIfDefined("EnumAttrInfo");
 
   std::vector<Attribute> dialectAttrs;
   std::vector<AttrDef> dialectAttrDefs;
   std::vector<OpDocGroup> dialectOps;
   std::vector<Type> dialectTypes;
   std::vector<TypeDef> dialectTypeDefs;
+  std::vector<EnumAttr> dialectEnums;
 
   llvm::SmallDenseSet<Record *> seen;
-  auto addIfInDialect = [&](llvm::Record *record, const auto &def, auto &vec) {
-    if (seen.insert(record).second && def.getDialect() == *dialect) {
+  auto addIfNotSeen = [&](llvm::Record *record, const auto &def, auto &vec) {
+    if (seen.insert(record).second) {
       vec.push_back(def);
       return true;
     }
     return false;
   };
+  auto addIfInDialect = [&](llvm::Record *record, const auto &def, auto &vec) {
+    if (def.getDialect() == *dialect) {
+      return addIfNotSeen(record, def, vec);
+    }
+    return false;
+  };
 
   SmallDenseMap<Record *, OpDocGroup> opDocGroup;
 
@@ -539,6 +588,9 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
     addIfInDialect(def, TypeDef(def), dialectTypeDefs);
   for (Record *def : typeDefs)
     addIfInDialect(def, Type(def), dialectTypes);
+  dialectEnums.reserve(enumDefs.size());
+  for (Record *def : enumDefs)
+    addIfNotSeen(def, EnumAttr(def), dialectEnums);
 
   // Sort alphabetically ignorning dialect for ops and section name for
   // sections.
@@ -557,7 +609,7 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
   os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
   emitDialectDoc(*dialect, recordKeeper.getInputFilename(), dialectAttrs,
                  dialectAttrDefs, dialectOps, dialectTypes, dialectTypeDefs,
-                 os);
+                 dialectEnums, os);
   return false;
 }
 
@@ -587,6 +639,13 @@ static mlir::GenRegistration
                       return false;
                     });
 
+static mlir::GenRegistration
+    genEnumRegister("gen-enum-doc", "Generate dialect enum documentation",
+                    [](const RecordKeeper &records, raw_ostream &os) {
+                      emitEnumDoc(records, os);
+                      return false;
+                    });
+
 static mlir::GenRegistration
     genRegister("gen-dialect-doc", "Generate dialect documentation",
                 [](const RecordKeeper &records, raw_ostream &os) {

>From 2d36a479a76bd479450161c141a4c56ef79db9db Mon Sep 17 00:00:00 2001
From: tomnatan30 <tomnatan at google.com>
Date: Mon, 15 Jul 2024 12:41:09 +0000
Subject: [PATCH 2/4] fix clang format

---
 mlir/tools/mlir-tblgen/OpDocGen.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index d55414d7b95f8..cb3dc5b45d00c 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -229,8 +229,7 @@ static void emitOpDoc(const Operator &op, raw_ostream &os) {
         // Expandable description.
         // This appears as just the summary, but when clicked shows the full
         // description.
-        os << "<details>"
-           << "<summary>" << it.attr.getSummary() << "</summary>"
+        os << "<details>" << "<summary>" << it.attr.getSummary() << "</summary>"
            << "{{% markdown %}}" << description << "{{% /markdown %}}"
            << "</details>";
       } else {
@@ -400,7 +399,7 @@ static void emitEnumDoc(const EnumAttr &def, raw_ostream &os) {
      << "| :----: | :---: | ------ |\n";
   for (const auto &it : cases) {
     os << "| " << it.getSymbol() << " | `" << it.getValue() << "` | "
-        << it.getStr() << " |\n";
+       << it.getStr() << " |\n";
   }
 
   os << "\n";
@@ -411,7 +410,8 @@ static void emitEnumDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
       recordKeeper.getAllDerivedDefinitions("EnumAttr");
 
   os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
-  for (const llvm::Record *def : defs) emitEnumDoc(EnumAttr(def), os);
+  for (const llvm::Record *def : defs)
+    emitEnumDoc(EnumAttr(def), os);
 }
 
 //===----------------------------------------------------------------------===//

>From 1dc69162197e297b6dcbf8e94b833c065c6cb94d Mon Sep 17 00:00:00 2001
From: tomnatan30 <tomnatan at google.com>
Date: Mon, 15 Jul 2024 18:24:39 +0000
Subject: [PATCH 3/4] resolve review comments

---
 mlir/tools/mlir-tblgen/OpDocGen.cpp | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index cb3dc5b45d00c..11f5e18b61de1 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -394,12 +394,14 @@ static void emitEnumDoc(const EnumAttr &def, raw_ostream &os) {
 
   // Emit case documentation.
   std::vector<EnumAttrCase> cases = def.getAllCases();
-  os << "\n#### Cases:\n\n";
-  os << "| Symbol | Value | String |\n"
-     << "| :----: | :---: | ------ |\n";
-  for (const auto &it : cases) {
-    os << "| " << it.getSymbol() << " | `" << it.getValue() << "` | "
-       << it.getStr() << " |\n";
+  if (!cases.empty()) {
+    os << "\n#### Cases:\n\n";
+    os << "| Symbol | Value | String |\n"
+       << "| :----: | :---: | ------ |\n";
+    for (const auto &it : cases) {
+      os << "| " << it.getSymbol() << " | `" << it.getValue() << "` | "
+         << it.getStr() << " |\n";
+    }
   }
 
   os << "\n";
@@ -554,10 +556,7 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
     return false;
   };
   auto addIfInDialect = [&](llvm::Record *record, const auto &def, auto &vec) {
-    if (def.getDialect() == *dialect) {
-      return addIfNotSeen(record, def, vec);
-    }
-    return false;
+    return def.getDialect() == *dialect && addIfNotSeen(record, def, vec);
   };
 
   SmallDenseMap<Record *, OpDocGroup> opDocGroup;

>From 57d8feeee40d605b240cb015f1d3ef82a9c101b3 Mon Sep 17 00:00:00 2001
From: tomnatan30 <tomnatan at google.com>
Date: Mon, 15 Jul 2024 19:21:26 +0000
Subject: [PATCH 4/4] emit empty cases table if no cases

---
 mlir/tools/mlir-tblgen/OpDocGen.cpp | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index 11f5e18b61de1..71df80cd110f1 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -394,14 +394,12 @@ static void emitEnumDoc(const EnumAttr &def, raw_ostream &os) {
 
   // Emit case documentation.
   std::vector<EnumAttrCase> cases = def.getAllCases();
-  if (!cases.empty()) {
-    os << "\n#### Cases:\n\n";
-    os << "| Symbol | Value | String |\n"
-       << "| :----: | :---: | ------ |\n";
-    for (const auto &it : cases) {
-      os << "| " << it.getSymbol() << " | `" << it.getValue() << "` | "
-         << it.getStr() << " |\n";
-    }
+  os << "\n#### Cases:\n\n";
+  os << "| Symbol | Value | String |\n"
+     << "| :----: | :---: | ------ |\n";
+  for (const auto &it : cases) {
+    os << "| " << it.getSymbol() << " | `" << it.getValue() << "` | "
+       << it.getStr() << " |\n";
   }
 
   os << "\n";



More information about the Mlir-commits mailing list