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 { 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 { // 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..71df80cd110f1 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 stripPrefix("strip-prefix", llvm::cl::desc("Strip prefix of the fully qualified names"), @@ -228,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 << "
" - << "" << it.attr.getSummary() << "" + os << "
" << "" << it.attr.getSummary() << "" << "{{% markdown %}}" << description << "{{% /markdown %}}" << "
"; } else { @@ -381,6 +381,39 @@ 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 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 defs = + recordKeeper.getAllDerivedDefinitions("EnumAttr"); + + os << "\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 fn, static void emitBlock(ArrayRef attributes, StringRef inputFilename, ArrayRef attrDefs, ArrayRef ops, ArrayRef types, ArrayRef typeDefs, - raw_ostream &os) { + ArrayRef enums, raw_ostream &os) { if (!ops.empty()) { os << "## Operations\n\n"; emitSourceLink(inputFilename, os); @@ -459,13 +492,19 @@ static void emitBlock(ArrayRef 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 attributes, ArrayRef attrDefs, ArrayRef ops, ArrayRef types, ArrayRef typeDefs, - raw_ostream &os) { + ArrayRef 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,27 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) { recordKeeper.getAllDerivedDefinitionsIfDefined("TypeDef"); std::vector attrDefDefs = recordKeeper.getAllDerivedDefinitionsIfDefined("AttrDef"); + std::vector enumDefs = + recordKeeper.getAllDerivedDefinitionsIfDefined("EnumAttrInfo"); std::vector dialectAttrs; std::vector dialectAttrDefs; std::vector dialectOps; std::vector dialectTypes; std::vector dialectTypeDefs; + std::vector dialectEnums; llvm::SmallDenseSet 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) { + return def.getDialect() == *dialect && addIfNotSeen(record, def, vec); + }; SmallDenseMap opDocGroup; @@ -539,6 +585,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 +606,7 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) { os << "\n"; emitDialectDoc(*dialect, recordKeeper.getInputFilename(), dialectAttrs, dialectAttrDefs, dialectOps, dialectTypes, dialectTypeDefs, - os); + dialectEnums, os); return false; } @@ -587,6 +636,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) {