1616#include " OpGenHelpers.h"
1717#include " mlir/Support/IndentedOstream.h"
1818#include " mlir/TableGen/AttrOrTypeDef.h"
19+ #include " mlir/TableGen/Attribute.h"
1920#include " mlir/TableGen/GenInfo.h"
2021#include " mlir/TableGen/Operator.h"
2122#include " llvm/ADT/DenseMap.h"
3738// Commandline Options
3839// ===----------------------------------------------------------------------===//
3940static llvm::cl::OptionCategory
40- docCat (" Options for -gen-(attrdef|typedef|op|dialect)-doc" );
41+ docCat (" Options for -gen-(attrdef|typedef|enum| op|dialect)-doc" );
4142llvm::cl::opt<std::string>
4243 stripPrefix (" strip-prefix" ,
4344 llvm::cl::desc (" Strip prefix of the fully qualified names" ),
@@ -228,8 +229,7 @@ static void emitOpDoc(const Operator &op, raw_ostream &os) {
228229 // Expandable description.
229230 // This appears as just the summary, but when clicked shows the full
230231 // description.
231- os << " <details>"
232- << " <summary>" << it.attr .getSummary () << " </summary>"
232+ os << " <details>" << " <summary>" << it.attr .getSummary () << " </summary>"
233233 << " {{% markdown %}}" << description << " {{% /markdown %}}"
234234 << " </details>" ;
235235 } else {
@@ -381,6 +381,39 @@ static void emitAttrOrTypeDefDoc(const RecordKeeper &recordKeeper,
381381 emitAttrOrTypeDefDoc (AttrOrTypeDef (def), os);
382382}
383383
384+ // ===----------------------------------------------------------------------===//
385+ // Enum Documentation
386+ // ===----------------------------------------------------------------------===//
387+
388+ static void emitEnumDoc (const EnumAttr &def, raw_ostream &os) {
389+ os << llvm::formatv (" ### {0}\n " , def.getEnumClassName ());
390+
391+ // Emit the summary if present.
392+ if (!def.getSummary ().empty ())
393+ os << " \n " << def.getSummary () << " \n " ;
394+
395+ // Emit case documentation.
396+ std::vector<EnumAttrCase> cases = def.getAllCases ();
397+ os << " \n #### Cases:\n\n " ;
398+ os << " | Symbol | Value | String |\n "
399+ << " | :----: | :---: | ------ |\n " ;
400+ for (const auto &it : cases) {
401+ os << " | " << it.getSymbol () << " | `" << it.getValue () << " ` | "
402+ << it.getStr () << " |\n " ;
403+ }
404+
405+ os << " \n " ;
406+ }
407+
408+ static void emitEnumDoc (const RecordKeeper &recordKeeper, raw_ostream &os) {
409+ std::vector<llvm::Record *> defs =
410+ recordKeeper.getAllDerivedDefinitions (" EnumAttr" );
411+
412+ os << " <!-- Autogenerated by mlir-tblgen; don't manually edit -->\n " ;
413+ for (const llvm::Record *def : defs)
414+ emitEnumDoc (EnumAttr (def), os);
415+ }
416+
384417// ===----------------------------------------------------------------------===//
385418// Dialect Documentation
386419// ===----------------------------------------------------------------------===//
@@ -413,7 +446,7 @@ static void maybeNest(bool nest, llvm::function_ref<void(raw_ostream &os)> fn,
413446static void emitBlock (ArrayRef<Attribute> attributes, StringRef inputFilename,
414447 ArrayRef<AttrDef> attrDefs, ArrayRef<OpDocGroup> ops,
415448 ArrayRef<Type> types, ArrayRef<TypeDef> typeDefs,
416- raw_ostream &os) {
449+ ArrayRef<EnumAttr> enums, raw_ostream &os) {
417450 if (!ops.empty ()) {
418451 os << " ## Operations\n\n " ;
419452 emitSourceLink (inputFilename, os);
@@ -459,13 +492,19 @@ static void emitBlock(ArrayRef<Attribute> attributes, StringRef inputFilename,
459492 for (const TypeDef &def : typeDefs)
460493 emitAttrOrTypeDefDoc (def, os);
461494 }
495+
496+ if (!enums.empty ()) {
497+ os << " ## Enums\n\n " ;
498+ for (const EnumAttr &def : enums)
499+ emitEnumDoc (def, os);
500+ }
462501}
463502
464503static void emitDialectDoc (const Dialect &dialect, StringRef inputFilename,
465504 ArrayRef<Attribute> attributes,
466505 ArrayRef<AttrDef> attrDefs, ArrayRef<OpDocGroup> ops,
467506 ArrayRef<Type> types, ArrayRef<TypeDef> typeDefs,
468- raw_ostream &os) {
507+ ArrayRef<EnumAttr> enums, raw_ostream &os) {
469508 os << " # '" << dialect.getName () << " ' Dialect\n\n " ;
470509 emitIfNotEmpty (dialect.getSummary (), os);
471510 emitIfNotEmpty (dialect.getDescription (), os);
@@ -475,7 +514,8 @@ static void emitDialectDoc(const Dialect &dialect, StringRef inputFilename,
475514 if (!r.match (dialect.getDescription ()))
476515 os << " [TOC]\n\n " ;
477516
478- emitBlock (attributes, inputFilename, attrDefs, ops, types, typeDefs, os);
517+ emitBlock (attributes, inputFilename, attrDefs, ops, types, typeDefs, enums,
518+ os);
479519}
480520
481521static bool emitDialectDoc (const RecordKeeper &recordKeeper, raw_ostream &os) {
@@ -495,21 +535,27 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
495535 recordKeeper.getAllDerivedDefinitionsIfDefined (" TypeDef" );
496536 std::vector<Record *> attrDefDefs =
497537 recordKeeper.getAllDerivedDefinitionsIfDefined (" AttrDef" );
538+ std::vector<Record *> enumDefs =
539+ recordKeeper.getAllDerivedDefinitionsIfDefined (" EnumAttrInfo" );
498540
499541 std::vector<Attribute> dialectAttrs;
500542 std::vector<AttrDef> dialectAttrDefs;
501543 std::vector<OpDocGroup> dialectOps;
502544 std::vector<Type> dialectTypes;
503545 std::vector<TypeDef> dialectTypeDefs;
546+ std::vector<EnumAttr> dialectEnums;
504547
505548 llvm::SmallDenseSet<Record *> seen;
506- auto addIfInDialect = [&](llvm::Record *record, const auto &def, auto &vec) {
507- if (seen.insert (record).second && def. getDialect () == *dialect ) {
549+ auto addIfNotSeen = [&](llvm::Record *record, const auto &def, auto &vec) {
550+ if (seen.insert (record).second ) {
508551 vec.push_back (def);
509552 return true ;
510553 }
511554 return false ;
512555 };
556+ auto addIfInDialect = [&](llvm::Record *record, const auto &def, auto &vec) {
557+ return def.getDialect () == *dialect && addIfNotSeen (record, def, vec);
558+ };
513559
514560 SmallDenseMap<Record *, OpDocGroup> opDocGroup;
515561
@@ -539,6 +585,9 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
539585 addIfInDialect (def, TypeDef (def), dialectTypeDefs);
540586 for (Record *def : typeDefs)
541587 addIfInDialect (def, Type (def), dialectTypes);
588+ dialectEnums.reserve (enumDefs.size ());
589+ for (Record *def : enumDefs)
590+ addIfNotSeen (def, EnumAttr (def), dialectEnums);
542591
543592 // Sort alphabetically ignorning dialect for ops and section name for
544593 // sections.
@@ -557,7 +606,7 @@ static bool emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
557606 os << " <!-- Autogenerated by mlir-tblgen; don't manually edit -->\n " ;
558607 emitDialectDoc (*dialect, recordKeeper.getInputFilename (), dialectAttrs,
559608 dialectAttrDefs, dialectOps, dialectTypes, dialectTypeDefs,
560- os);
609+ dialectEnums, os);
561610 return false ;
562611}
563612
@@ -587,6 +636,13 @@ static mlir::GenRegistration
587636 return false ;
588637 });
589638
639+ static mlir::GenRegistration
640+ genEnumRegister (" gen-enum-doc" , " Generate dialect enum documentation" ,
641+ [](const RecordKeeper &records, raw_ostream &os) {
642+ emitEnumDoc (records, os);
643+ return false ;
644+ });
645+
590646static mlir::GenRegistration
591647 genRegister (" gen-dialect-doc" , " Generate dialect documentation" ,
592648 [](const RecordKeeper &records, raw_ostream &os) {
0 commit comments