github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/tools/mlir-tblgen/OpDocGen.cpp (about) 1 //===- OpDocGen.cpp - MLIR operation documentation generator --------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 // 18 // OpDocGen uses the description of operations to generate documentation for the 19 // operations. 20 // 21 //===----------------------------------------------------------------------===// 22 23 #include "mlir/TableGen/GenInfo.h" 24 #include "mlir/TableGen/Operator.h" 25 #include "llvm/ADT/StringExtras.h" 26 #include "llvm/Support/FormatVariadic.h" 27 #include "llvm/Support/Signals.h" 28 #include "llvm/TableGen/Error.h" 29 #include "llvm/TableGen/Record.h" 30 #include "llvm/TableGen/TableGenBackend.h" 31 32 using namespace llvm; 33 using namespace mlir; 34 35 using mlir::tblgen::Operator; 36 37 // Emit the description by aligning the text to the left per line (e.g., 38 // removing the minimum indentation across the block). 39 // 40 // This expects that the description in the tablegen file is already formatted 41 // in a way the user wanted but has some additional indenting due to being 42 // nested in the op definition. 43 static void emitDescription(StringRef description, raw_ostream &os) { 44 // Determine the minimum number of spaces in a line. 45 size_t min_indent = -1; 46 StringRef remaining = description; 47 while (!remaining.empty()) { 48 auto split = remaining.split('\n'); 49 size_t indent = split.first.find_first_not_of(" \t"); 50 if (indent != StringRef::npos) 51 min_indent = std::min(indent, min_indent); 52 remaining = split.second; 53 } 54 55 // Print out the description indented. 56 os << "\n"; 57 remaining = description; 58 bool printed = false; 59 while (!remaining.empty()) { 60 auto split = remaining.split('\n'); 61 if (split.second.empty()) { 62 // Skip last line with just spaces. 63 if (split.first.ltrim().empty()) 64 break; 65 } 66 // Print empty new line without spaces if line only has spaces, unless no 67 // text has been emitted before. 68 if (split.first.ltrim().empty()) { 69 if (printed) 70 os << "\n"; 71 } else { 72 os << split.first.substr(min_indent) << "\n"; 73 printed = true; 74 } 75 remaining = split.second; 76 } 77 } 78 79 static void emitOpDoc(const RecordKeeper &recordKeeper, raw_ostream &os) { 80 const auto &defs = recordKeeper.getAllDerivedDefinitions("Op"); 81 os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n"; 82 83 // TODO: Group by dialect. 84 // TODO: Add docs for types used (maybe dialect specific ones?) and link 85 // between use and def. 86 os << "# Operation definition\n"; 87 for (auto *def : defs) { 88 Operator op(def); 89 os << "## " << op.getOperationName() << " (" << op.getQualCppClassName() 90 << ")"; 91 92 // Emit summary & description of operator. 93 if (op.hasSummary()) 94 os << "\n" << op.getSummary() << "\n"; 95 os << "\n### Description:\n"; 96 if (op.hasDescription()) 97 emitDescription(op.getDescription(), os); 98 99 // Emit operands & type of operand. All operands are numbered, some may be 100 // named too. 101 os << "\n### Operands:\n"; 102 for (const auto &operand : op.getOperands()) { 103 os << "1. "; 104 if (!operand.name.empty()) 105 os << "`" << operand.name << "`: "; 106 else 107 os << "«unnamed»: "; 108 os << operand.constraint.getDescription() << "\n"; 109 } 110 111 // Emit attributes. 112 // TODO: Attributes are only documented by TableGen name, with no further 113 // info. This should be improved. 114 os << "\n### Attributes:\n"; 115 if (op.getNumAttributes() > 0) { 116 os << "| Attribute | MLIR Type | Description |\n" 117 << "| :-------: | :-------: | ----------- |\n"; 118 } 119 for (auto namedAttr : op.getAttributes()) { 120 os << "| `" << namedAttr.name << "` | `" 121 << namedAttr.attr.getStorageType() << "` | " 122 << namedAttr.attr.getDescription() << " attribute |\n"; 123 } 124 125 // Emit results. 126 os << "\n### Results:\n"; 127 for (unsigned i = 0, e = op.getNumResults(); i < e; ++i) { 128 os << "1. "; 129 auto name = op.getResultName(i); 130 if (name.empty()) 131 os << "«unnamed»: "; 132 else 133 os << "`" << name << "`: "; 134 os << op.getResultTypeConstraint(i).getDescription() << "\n"; 135 } 136 137 os << "\n"; 138 } 139 } 140 141 static mlir::GenRegistration 142 genRegister("gen-op-doc", "Generate operation documentation", 143 [](const RecordKeeper &records, raw_ostream &os) { 144 emitOpDoc(records, os); 145 return false; 146 });