Add support for enum doc gen (#98885)

This commit is contained in:
Tom Natan 2024-07-16 09:18:49 +01:00 committed by GitHub
parent 4eb30cfb34
commit f091848504
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 86 additions and 9 deletions

View File

@ -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";

View File

@ -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"),
@ -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 << "<details>"
<< "<summary>" << it.attr.getSummary() << "</summary>"
os << "<details>" << "<summary>" << it.attr.getSummary() << "</summary>"
<< "{{% markdown %}}" << description << "{{% /markdown %}}"
<< "</details>";
} 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<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,27 @@ 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) {
return def.getDialect() == *dialect && addIfNotSeen(record, def, vec);
};
SmallDenseMap<Record *, OpDocGroup> 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 << "<!-- 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 +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) {