1 //===- DialectGen.cpp - MLIR dialect definitions generator ----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // DialectGen uses the description of dialects to generate C++ definitions. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "mlir/TableGen/CodeGenHelpers.h" 14 #include "mlir/TableGen/Format.h" 15 #include "mlir/TableGen/GenInfo.h" 16 #include "mlir/TableGen/Interfaces.h" 17 #include "mlir/TableGen/OpClass.h" 18 #include "mlir/TableGen/OpTrait.h" 19 #include "mlir/TableGen/Operator.h" 20 #include "llvm/ADT/Sequence.h" 21 #include "llvm/ADT/StringExtras.h" 22 #include "llvm/Support/CommandLine.h" 23 #include "llvm/Support/Signals.h" 24 #include "llvm/TableGen/Error.h" 25 #include "llvm/TableGen/Record.h" 26 #include "llvm/TableGen/TableGenBackend.h" 27 28 #define DEBUG_TYPE "mlir-tblgen-opdefgen" 29 30 using namespace mlir; 31 using namespace mlir::tblgen; 32 33 static llvm::cl::OptionCategory dialectGenCat("Options for -gen-dialect-*"); 34 static llvm::cl::opt<std::string> 35 selectedDialect("dialect", llvm::cl::desc("The dialect to gen for"), 36 llvm::cl::cat(dialectGenCat), llvm::cl::CommaSeparated); 37 38 /// Utility iterator used for filtering records for a specific dialect. 39 namespace { 40 using DialectFilterIterator = 41 llvm::filter_iterator<ArrayRef<llvm::Record *>::iterator, 42 std::function<bool(const llvm::Record *)>>; 43 } // end anonymous namespace 44 45 /// Given a set of records for a T, filter the ones that correspond to 46 /// the given dialect. 47 template <typename T> 48 static iterator_range<DialectFilterIterator> 49 filterForDialect(ArrayRef<llvm::Record *> records, Dialect &dialect) { 50 auto filterFn = [&](const llvm::Record *record) { 51 return T(record).getDialect() == dialect; 52 }; 53 return {DialectFilterIterator(records.begin(), records.end(), filterFn), 54 DialectFilterIterator(records.end(), records.end(), filterFn)}; 55 } 56 57 //===----------------------------------------------------------------------===// 58 // GEN: Dialect declarations 59 //===----------------------------------------------------------------------===// 60 61 /// The code block for the start of a dialect class declaration. 62 /// 63 /// {0}: The name of the dialect class. 64 /// {1}: The dialect namespace. 65 /// {2}: initialization code that is emitted in the ctor body before calling 66 /// initialize() 67 static const char *const dialectDeclBeginStr = R"( 68 class {0} : public ::mlir::Dialect { 69 explicit {0}(::mlir::MLIRContext *context) 70 : ::mlir::Dialect(getDialectNamespace(), context, 71 ::mlir::TypeID::get<{0}>()) {{ 72 {2} 73 initialize(); 74 } 75 void initialize(); 76 friend class ::mlir::MLIRContext; 77 public: 78 static constexpr ::llvm::StringLiteral getDialectNamespace() { 79 return ::llvm::StringLiteral("{1}"); 80 } 81 )"; 82 83 /// Registration for a single dependent dialect: to be inserted in the ctor 84 /// above for each dependent dialect. 85 const char *const dialectRegistrationTemplate = R"( 86 getContext()->getOrLoadDialect<{0}>(); 87 )"; 88 89 /// The code block for the attribute parser/printer hooks. 90 static const char *const attrParserDecl = R"( 91 /// Parse an attribute registered to this dialect. 92 ::mlir::Attribute parseAttribute(::mlir::DialectAsmParser &parser, 93 ::mlir::Type type) const override; 94 95 /// Print an attribute registered to this dialect. 96 void printAttribute(::mlir::Attribute attr, 97 ::mlir::DialectAsmPrinter &os) const override; 98 )"; 99 100 /// The code block for the type parser/printer hooks. 101 static const char *const typeParserDecl = R"( 102 /// Parse a type registered to this dialect. 103 ::mlir::Type parseType(::mlir::DialectAsmParser &parser) const override; 104 105 /// Print a type registered to this dialect. 106 void printType(::mlir::Type type, 107 ::mlir::DialectAsmPrinter &os) const override; 108 )"; 109 110 /// The code block for the constant materializer hook. 111 static const char *const constantMaterializerDecl = R"( 112 /// Materialize a single constant operation from a given attribute value with 113 /// the desired resultant type. 114 ::mlir::Operation *materializeConstant(::mlir::OpBuilder &builder, 115 ::mlir::Attribute value, 116 ::mlir::Type type, 117 ::mlir::Location loc) override; 118 )"; 119 120 /// The code block for the operation attribute verifier hook. 121 static const char *const opAttrVerifierDecl = R"( 122 /// Provides a hook for verifying dialect attributes attached to the given 123 /// op. 124 ::mlir::LogicalResult verifyOperationAttribute( 125 ::mlir::Operation *op, ::mlir::NamedAttribute attribute) override; 126 )"; 127 128 /// The code block for the region argument attribute verifier hook. 129 static const char *const regionArgAttrVerifierDecl = R"( 130 /// Provides a hook for verifying dialect attributes attached to the given 131 /// op's region argument. 132 ::mlir::LogicalResult verifyRegionArgAttribute( 133 ::mlir::Operation *op, unsigned regionIndex, unsigned argIndex, 134 ::mlir::NamedAttribute attribute) override; 135 )"; 136 137 /// The code block for the region result attribute verifier hook. 138 static const char *const regionResultAttrVerifierDecl = R"( 139 /// Provides a hook for verifying dialect attributes attached to the given 140 /// op's region result. 141 ::mlir::LogicalResult verifyRegionResultAttribute( 142 ::mlir::Operation *op, unsigned regionIndex, unsigned resultIndex, 143 ::mlir::NamedAttribute attribute) override; 144 )"; 145 146 /// The code block for the op interface fallback hook. 147 static const char *const operationInterfaceFallbackDecl = R"( 148 /// Provides a hook for op interface. 149 void *getRegisteredInterfaceForOp(mlir::TypeID interfaceID, 150 mlir::OperationName opName) override; 151 )"; 152 153 /// Generate the declaration for the given dialect class. 154 static void emitDialectDecl(Dialect &dialect, 155 iterator_range<DialectFilterIterator> dialectAttrs, 156 iterator_range<DialectFilterIterator> dialectTypes, 157 raw_ostream &os) { 158 /// Build the list of dependent dialects 159 std::string dependentDialectRegistrations; 160 { 161 llvm::raw_string_ostream dialectsOs(dependentDialectRegistrations); 162 for (StringRef dependentDialect : dialect.getDependentDialects()) 163 dialectsOs << llvm::formatv(dialectRegistrationTemplate, 164 dependentDialect); 165 } 166 167 // Emit all nested namespaces. 168 NamespaceEmitter nsEmitter(os, dialect); 169 170 // Emit the start of the decl. 171 std::string cppName = dialect.getCppClassName(); 172 os << llvm::formatv(dialectDeclBeginStr, cppName, dialect.getName(), 173 dependentDialectRegistrations); 174 175 // Check for any attributes/types registered to this dialect. If there are, 176 // add the hooks for parsing/printing. 177 if (!dialectAttrs.empty()) 178 os << attrParserDecl; 179 if (!dialectTypes.empty()) 180 os << typeParserDecl; 181 182 // Add the decls for the various features of the dialect. 183 if (dialect.hasConstantMaterializer()) 184 os << constantMaterializerDecl; 185 if (dialect.hasOperationAttrVerify()) 186 os << opAttrVerifierDecl; 187 if (dialect.hasRegionArgAttrVerify()) 188 os << regionArgAttrVerifierDecl; 189 if (dialect.hasRegionResultAttrVerify()) 190 os << regionResultAttrVerifierDecl; 191 if (dialect.hasOperationInterfaceFallback()) 192 os << operationInterfaceFallbackDecl; 193 if (llvm::Optional<StringRef> extraDecl = dialect.getExtraClassDeclaration()) 194 os << *extraDecl; 195 196 // End the dialect decl. 197 os << "};\n"; 198 } 199 200 static bool emitDialectDecls(const llvm::RecordKeeper &recordKeeper, 201 raw_ostream &os) { 202 emitSourceFileHeader("Dialect Declarations", os); 203 204 auto defs = recordKeeper.getAllDerivedDefinitions("Dialect"); 205 if (defs.empty()) 206 return false; 207 208 // Select the dialect to gen for. 209 const llvm::Record *dialectDef = nullptr; 210 if (defs.size() == 1 && selectedDialect.getNumOccurrences() == 0) { 211 dialectDef = defs.front(); 212 } else if (selectedDialect.getNumOccurrences() == 0) { 213 llvm::errs() << "when more than 1 dialect is present, one must be selected " 214 "via '-dialect'"; 215 return true; 216 } else { 217 auto dialectIt = llvm::find_if(defs, [](const llvm::Record *def) { 218 return Dialect(def).getName() == selectedDialect; 219 }); 220 if (dialectIt == defs.end()) { 221 llvm::errs() << "selected dialect with '-dialect' does not exist"; 222 return true; 223 } 224 dialectDef = *dialectIt; 225 } 226 227 auto attrDefs = recordKeeper.getAllDerivedDefinitions("DialectAttr"); 228 auto typeDefs = recordKeeper.getAllDerivedDefinitions("DialectType"); 229 Dialect dialect(dialectDef); 230 emitDialectDecl(dialect, filterForDialect<Attribute>(attrDefs, dialect), 231 filterForDialect<Type>(typeDefs, dialect), os); 232 return false; 233 } 234 235 //===----------------------------------------------------------------------===// 236 // GEN: Dialect registration hooks 237 //===----------------------------------------------------------------------===// 238 239 static mlir::GenRegistration 240 genDialectDecls("gen-dialect-decls", "Generate dialect declarations", 241 [](const llvm::RecordKeeper &records, raw_ostream &os) { 242 return emitDialectDecls(records, os); 243 }); 244