1 //===- AttrOrTypeDefGen.cpp - MLIR AttrOrType 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 #include "mlir/Support/LogicalResult.h" 10 #include "mlir/TableGen/AttrOrTypeDef.h" 11 #include "mlir/TableGen/CodeGenHelpers.h" 12 #include "mlir/TableGen/Format.h" 13 #include "mlir/TableGen/GenInfo.h" 14 #include "llvm/ADT/Sequence.h" 15 #include "llvm/ADT/SmallSet.h" 16 #include "llvm/Support/CommandLine.h" 17 #include "llvm/TableGen/Error.h" 18 #include "llvm/TableGen/TableGenBackend.h" 19 20 #define DEBUG_TYPE "mlir-tblgen-attrortypedefgen" 21 22 using namespace mlir; 23 using namespace mlir::tblgen; 24 25 /// Find all the AttrOrTypeDef for the specified dialect. If no dialect 26 /// specified and can only find one dialect's defs, use that. 27 static void collectAllDefs(StringRef selectedDialect, 28 std::vector<llvm::Record *> records, 29 SmallVectorImpl<AttrOrTypeDef> &resultDefs) { 30 auto defs = llvm::map_range( 31 records, [&](const llvm::Record *rec) { return AttrOrTypeDef(rec); }); 32 if (defs.empty()) 33 return; 34 35 StringRef dialectName; 36 if (selectedDialect.empty()) { 37 if (defs.empty()) 38 return; 39 40 Dialect dialect(nullptr); 41 for (const AttrOrTypeDef &typeDef : defs) { 42 if (!dialect) { 43 dialect = typeDef.getDialect(); 44 } else if (dialect != typeDef.getDialect()) { 45 llvm::PrintFatalError("defs belonging to more than one dialect. Must " 46 "select one via '--(attr|type)defs-dialect'"); 47 } 48 } 49 50 dialectName = dialect.getName(); 51 } else { 52 dialectName = selectedDialect; 53 } 54 55 for (const AttrOrTypeDef &def : defs) 56 if (def.getDialect().getName().equals(dialectName)) 57 resultDefs.push_back(def); 58 } 59 60 //===----------------------------------------------------------------------===// 61 // ParamCommaFormatter 62 //===----------------------------------------------------------------------===// 63 64 namespace { 65 66 /// Pass an instance of this class to llvm::formatv() to emit a comma separated 67 /// list of parameters in the format by 'EmitFormat'. 68 class ParamCommaFormatter : public llvm::detail::format_adapter { 69 public: 70 /// Choose the output format 71 enum EmitFormat { 72 /// Emit "parameter1Type parameter1Name, parameter2Type parameter2Name, 73 /// [...]". 74 TypeNamePairs, 75 76 /// Emit "parameter1(parameter1), parameter2(parameter2), [...]". 77 TypeNameInitializer, 78 79 /// Emit "param1Name, param2Name, [...]". 80 JustParams, 81 }; 82 83 ParamCommaFormatter(EmitFormat emitFormat, 84 ArrayRef<AttrOrTypeParameter> params, 85 bool prependComma = true) 86 : emitFormat(emitFormat), params(params), prependComma(prependComma) {} 87 88 /// llvm::formatv will call this function when using an instance as a 89 /// replacement value. 90 void format(raw_ostream &os, StringRef options) override { 91 if (!params.empty() && prependComma) 92 os << ", "; 93 94 switch (emitFormat) { 95 case EmitFormat::TypeNamePairs: 96 interleaveComma(params, os, [&](const AttrOrTypeParameter &p) { 97 emitTypeNamePair(p, os); 98 }); 99 break; 100 case EmitFormat::TypeNameInitializer: 101 interleaveComma(params, os, [&](const AttrOrTypeParameter &p) { 102 emitTypeNameInitializer(p, os); 103 }); 104 break; 105 case EmitFormat::JustParams: 106 interleaveComma(params, os, 107 [&](const AttrOrTypeParameter &p) { os << p.getName(); }); 108 break; 109 } 110 } 111 112 private: 113 // Emit "paramType paramName". 114 static void emitTypeNamePair(const AttrOrTypeParameter ¶m, 115 raw_ostream &os) { 116 os << param.getCppType() << " " << param.getName(); 117 } 118 // Emit "paramName(paramName)" 119 void emitTypeNameInitializer(const AttrOrTypeParameter ¶m, 120 raw_ostream &os) { 121 os << param.getName() << "(" << param.getName() << ")"; 122 } 123 124 EmitFormat emitFormat; 125 ArrayRef<AttrOrTypeParameter> params; 126 bool prependComma; 127 }; 128 129 } // end anonymous namespace 130 131 //===----------------------------------------------------------------------===// 132 // DefGenerator 133 //===----------------------------------------------------------------------===// 134 135 namespace { 136 /// This struct is the base generator used when processing tablegen interfaces. 137 class DefGenerator { 138 public: 139 bool emitDecls(StringRef selectedDialect); 140 bool emitDefs(StringRef selectedDialect); 141 142 protected: 143 DefGenerator(std::vector<llvm::Record *> &&defs, raw_ostream &os) 144 : defRecords(std::move(defs)), os(os), isAttrGenerator(false) {} 145 146 /// Emit the declaration of a single def. 147 void emitDefDecl(const AttrOrTypeDef &def); 148 /// Emit the list of def type names. 149 void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs); 150 /// Emit the code to dispatch between different defs during parsing/printing. 151 void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs); 152 /// Emit the definition of a single def. 153 void emitDefDef(const AttrOrTypeDef &def); 154 /// Emit the storage class for the given def. 155 void emitStorageClass(const AttrOrTypeDef &def); 156 /// Emit the parser/printer for the given def. 157 void emitParsePrint(const AttrOrTypeDef &def); 158 159 /// The set of def records to emit. 160 std::vector<llvm::Record *> defRecords; 161 /// The stream to emit to. 162 raw_ostream &os; 163 /// The prefix of the tablegen def name, e.g. Attr or Type. 164 StringRef defTypePrefix; 165 /// The C++ base value type of the def, e.g. Attribute or Type. 166 StringRef valueType; 167 /// Flag indicating if this generator is for Attributes. False if the 168 /// generator is for types. 169 bool isAttrGenerator; 170 }; 171 172 /// A specialized generator for AttrDefs. 173 struct AttrDefGenerator : public DefGenerator { 174 AttrDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os) 175 : DefGenerator(records.getAllDerivedDefinitions("AttrDef"), os) { 176 isAttrGenerator = true; 177 defTypePrefix = "Attr"; 178 valueType = "Attribute"; 179 } 180 }; 181 /// A specialized generator for TypeDefs. 182 struct TypeDefGenerator : public DefGenerator { 183 TypeDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os) 184 : DefGenerator(records.getAllDerivedDefinitions("TypeDef"), os) { 185 defTypePrefix = "Type"; 186 valueType = "Type"; 187 } 188 }; 189 } // end anonymous namespace 190 191 //===----------------------------------------------------------------------===// 192 // GEN: Declarations 193 //===----------------------------------------------------------------------===// 194 195 /// Print this above all the other declarations. Contains type declarations used 196 /// later on. 197 static const char *const typeDefDeclHeader = R"( 198 namespace mlir { 199 class DialectAsmParser; 200 class DialectAsmPrinter; 201 } // namespace mlir 202 )"; 203 204 /// The code block for the start of a typeDef class declaration -- singleton 205 /// case. 206 /// 207 /// {0}: The name of the def class. 208 /// {1}: The name of the type base class. 209 /// {2}: The name of the base value type, e.g. Attribute or Type. 210 /// {3}: The tablegen record type prefix, e.g. Attr or Type. 211 static const char *const defDeclSingletonBeginStr = R"( 212 class {0} : public ::mlir::{2}::{3}Base<{0}, {1}, ::mlir::{2}Storage> {{ 213 public: 214 /// Inherit some necessary constructors from '{3}Base'. 215 using Base::Base; 216 )"; 217 218 /// The code block for the start of a typeDef class declaration -- parametric 219 /// case. 220 /// 221 /// {0}: The name of the typeDef class. 222 /// {1}: The name of the type base class. 223 /// {2}: The typeDef storage class namespace. 224 /// {3}: The storage class name. 225 /// {4}: The name of the base value type, e.g. Attribute or Type. 226 /// {5}: The tablegen record type prefix, e.g. Attr or Type. 227 static const char *const defDeclParametricBeginStr = R"( 228 namespace {2} { 229 struct {3}; 230 } // end namespace {2} 231 class {0} : public ::mlir::{4}::{5}Base<{0}, {1}, 232 {2}::{3}> {{ 233 public: 234 /// Inherit some necessary constructors from '{5}Base'. 235 using Base::Base; 236 237 )"; 238 239 /// The code snippet for print/parse of an Attribute/Type. 240 /// 241 /// {0}: The name of the base value type, e.g. Attribute or Type. 242 /// {1}: Extra parser parameters. 243 static const char *const defDeclParsePrintStr = R"( 244 static ::mlir::{0} parse(::mlir::MLIRContext *context, 245 ::mlir::DialectAsmParser &parser{1}); 246 void print(::mlir::DialectAsmPrinter &printer) const; 247 )"; 248 249 /// The code block for the verify method declaration. 250 /// 251 /// {0}: List of parameters, parameters style. 252 static const char *const defDeclVerifyStr = R"( 253 using Base::getChecked; 254 static ::mlir::LogicalResult verify(::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError{0}); 255 )"; 256 257 /// Emit the builders for the given def. 258 static void emitBuilderDecls(const AttrOrTypeDef &def, raw_ostream &os, 259 ParamCommaFormatter ¶mTypes) { 260 StringRef typeClass = def.getCppClassName(); 261 bool genCheckedMethods = def.genVerifyDecl(); 262 if (!def.skipDefaultBuilders()) { 263 os << llvm::formatv( 264 " static {0} get(::mlir::MLIRContext *context{1});\n", typeClass, 265 paramTypes); 266 if (genCheckedMethods) { 267 os << llvm::formatv(" static {0} " 268 "getChecked(llvm::function_ref<::mlir::" 269 "InFlightDiagnostic()> emitError, " 270 "::mlir::MLIRContext *context{1});\n", 271 typeClass, paramTypes); 272 } 273 } 274 275 // Generate the builders specified by the user. 276 for (const AttrOrTypeBuilder &builder : def.getBuilders()) { 277 std::string paramStr; 278 llvm::raw_string_ostream paramOS(paramStr); 279 llvm::interleaveComma( 280 builder.getParameters(), paramOS, 281 [&](const AttrOrTypeBuilder::Parameter ¶m) { 282 // Note: AttrOrTypeBuilder parameters are guaranteed to have names. 283 paramOS << param.getCppType() << " " << *param.getName(); 284 if (Optional<StringRef> defaultParamValue = param.getDefaultValue()) 285 paramOS << " = " << *defaultParamValue; 286 }); 287 paramOS.flush(); 288 289 // Generate the `get` variant of the builder. 290 os << " static " << typeClass << " get("; 291 if (!builder.hasInferredContextParameter()) { 292 os << "::mlir::MLIRContext *context"; 293 if (!paramStr.empty()) 294 os << ", "; 295 } 296 os << paramStr << ");\n"; 297 298 // Generate the `getChecked` variant of the builder. 299 if (genCheckedMethods) { 300 os << " static " << typeClass 301 << " getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> " 302 "emitError"; 303 if (!builder.hasInferredContextParameter()) 304 os << ", ::mlir::MLIRContext *context"; 305 if (!paramStr.empty()) 306 os << ", "; 307 os << paramStr << ");\n"; 308 } 309 } 310 } 311 312 void DefGenerator::emitDefDecl(const AttrOrTypeDef &def) { 313 SmallVector<AttrOrTypeParameter, 4> params; 314 def.getParameters(params); 315 316 // Emit the beginning string template: either the singleton or parametric 317 // template. 318 if (def.getNumParameters() == 0) { 319 os << formatv(defDeclSingletonBeginStr, def.getCppClassName(), 320 def.getCppBaseClassName(), valueType, defTypePrefix); 321 } else { 322 os << formatv(defDeclParametricBeginStr, def.getCppClassName(), 323 def.getCppBaseClassName(), def.getStorageNamespace(), 324 def.getStorageClassName(), valueType, defTypePrefix); 325 } 326 327 // Emit the extra declarations first in case there's a definition in there. 328 if (Optional<StringRef> extraDecl = def.getExtraDecls()) 329 os << *extraDecl << "\n"; 330 331 ParamCommaFormatter emitTypeNamePairsAfterComma( 332 ParamCommaFormatter::EmitFormat::TypeNamePairs, params); 333 if (!params.empty()) { 334 emitBuilderDecls(def, os, emitTypeNamePairsAfterComma); 335 336 // Emit the verify invariants declaration. 337 if (def.genVerifyDecl()) 338 os << llvm::formatv(defDeclVerifyStr, emitTypeNamePairsAfterComma); 339 } 340 341 // Emit the mnenomic, if specified. 342 if (auto mnenomic = def.getMnemonic()) { 343 os << " static constexpr ::llvm::StringLiteral getMnemonic() {\n" 344 << " return ::llvm::StringLiteral(\"" << mnenomic << "\");\n" 345 << " }\n"; 346 347 // If mnemonic specified, emit print/parse declarations. 348 if (def.getParserCode() || def.getPrinterCode() || !params.empty()) { 349 os << llvm::formatv(defDeclParsePrintStr, valueType, 350 isAttrGenerator ? ", ::mlir::Type type" : ""); 351 } 352 } 353 354 if (def.genAccessors()) { 355 SmallVector<AttrOrTypeParameter, 4> parameters; 356 def.getParameters(parameters); 357 358 for (AttrOrTypeParameter ¶meter : parameters) { 359 SmallString<16> name = parameter.getName(); 360 name[0] = llvm::toUpper(name[0]); 361 os << formatv(" {0} get{1}() const;\n", parameter.getCppType(), name); 362 } 363 } 364 365 // End the decl. 366 os << " };\n"; 367 } 368 369 bool DefGenerator::emitDecls(StringRef selectedDialect) { 370 emitSourceFileHeader((defTypePrefix + "Def Declarations").str(), os); 371 IfDefScope scope("GET_" + defTypePrefix.upper() + "DEF_CLASSES", os); 372 373 // Output the common "header". 374 os << typeDefDeclHeader; 375 376 SmallVector<AttrOrTypeDef, 16> defs; 377 collectAllDefs(selectedDialect, defRecords, defs); 378 if (defs.empty()) 379 return false; 380 381 NamespaceEmitter nsEmitter(os, defs.front().getDialect()); 382 383 // Declare all the def classes first (in case they reference each other). 384 for (const AttrOrTypeDef &def : defs) 385 os << " class " << def.getCppClassName() << ";\n"; 386 387 // Emit the declarations. 388 for (const AttrOrTypeDef &def : defs) 389 emitDefDecl(def); 390 return false; 391 } 392 393 //===----------------------------------------------------------------------===// 394 // GEN: Def List 395 //===----------------------------------------------------------------------===// 396 397 void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) { 398 IfDefScope scope("GET_" + defTypePrefix.upper() + "DEF_LIST", os); 399 auto interleaveFn = [&](const AttrOrTypeDef &def) { 400 os << def.getDialect().getCppNamespace() << "::" << def.getCppClassName(); 401 }; 402 llvm::interleave(defs, os, interleaveFn, ",\n"); 403 os << "\n"; 404 } 405 406 //===----------------------------------------------------------------------===// 407 // GEN: Definitions 408 //===----------------------------------------------------------------------===// 409 410 /// The code block used to start the auto-generated parser function. 411 /// 412 /// {0}: The name of the base value type, e.g. Attribute or Type. 413 /// {1}: Additional parser parameters. 414 static const char *const defParserDispatchStartStr = R"( 415 static ::mlir::OptionalParseResult generated{0}Parser(::mlir::MLIRContext *context, 416 ::mlir::DialectAsmParser &parser, 417 ::llvm::StringRef mnemonic{1}, 418 ::mlir::{0} &value) {{ 419 )"; 420 421 /// The code block used to start the auto-generated printer function. 422 /// 423 /// {0}: The name of the base value type, e.g. Attribute or Type. 424 static const char *const defPrinterDispatchStartStr = R"( 425 static ::mlir::LogicalResult generated{0}Printer( 426 ::mlir::{0} def, ::mlir::DialectAsmPrinter &printer) {{ 427 return ::llvm::TypeSwitch<::mlir::{0}, ::mlir::LogicalResult>(def) 428 )"; 429 430 /// Beginning of storage class. 431 /// {0}: Storage class namespace. 432 /// {1}: Storage class c++ name. 433 /// {2}: Parameters parameters. 434 /// {3}: Parameter initializer string. 435 /// {4}: Parameter types. 436 /// {5}: The name of the base value type, e.g. Attribute or Type. 437 static const char *const defStorageClassBeginStr = R"( 438 namespace {0} {{ 439 struct {1} : public ::mlir::{5}Storage {{ 440 {1} ({2}) 441 : {3} {{ } 442 443 /// The hash key is a tuple of the parameter types. 444 using KeyTy = std::tuple<{4}>; 445 )"; 446 447 /// The storage class' constructor template. 448 /// 449 /// {0}: storage class name. 450 /// {1}: The name of the base value type, e.g. Attribute or Type. 451 static const char *const defStorageClassConstructorBeginStr = R"( 452 /// Define a construction method for creating a new instance of this 453 /// storage. 454 static {0} *construct(::mlir::{1}StorageAllocator &allocator, 455 const KeyTy &key) {{ 456 )"; 457 458 /// The storage class' constructor return template. 459 /// 460 /// {0}: storage class name. 461 /// {1}: list of parameters. 462 static const char *const defStorageClassConstructorEndStr = R"( 463 return new (allocator.allocate<{0}>()) 464 {0}({1}); 465 } 466 )"; 467 468 /// Use tgfmt to emit custom allocation code for each parameter, if necessary. 469 static void emitStorageParameterAllocation(const AttrOrTypeDef &def, 470 raw_ostream &os) { 471 SmallVector<AttrOrTypeParameter> parameters; 472 def.getParameters(parameters); 473 FmtContext fmtCtxt = FmtContext().addSubst("_allocator", "allocator"); 474 for (AttrOrTypeParameter ¶meter : parameters) { 475 if (Optional<StringRef> allocCode = parameter.getAllocator()) { 476 fmtCtxt.withSelf(parameter.getName()); 477 fmtCtxt.addSubst("_dst", parameter.getName()); 478 os << " " << tgfmt(*allocCode, &fmtCtxt) << "\n"; 479 } 480 } 481 } 482 483 /// Builds a code block that initializes the attribute storage of 'def'. 484 /// Attribute initialization is separated from Type initialization given that 485 /// the Attribute also needs to initialize its self-type, which has multiple 486 /// means of initialization. 487 static std::string buildAttributeStorageParamInitializer( 488 const AttrOrTypeDef &def, ArrayRef<AttrOrTypeParameter> parameters) { 489 std::string paramInitializer; 490 llvm::raw_string_ostream paramOS(paramInitializer); 491 paramOS << "::mlir::AttributeStorage("; 492 493 // If this is an attribute, we need to check for value type initialization. 494 Optional<size_t> selfParamIndex; 495 for (auto it : llvm::enumerate(parameters)) { 496 const auto *selfParam = dyn_cast<AttributeSelfTypeParameter>(&it.value()); 497 if (!selfParam) 498 continue; 499 if (selfParamIndex) { 500 llvm::PrintFatalError(def.getLoc(), 501 "Only one attribute parameter can be marked as " 502 "AttributeSelfTypeParameter"); 503 } 504 paramOS << selfParam->getName(); 505 selfParamIndex = it.index(); 506 } 507 508 // If we didn't find a self param, but the def has a type builder we use that 509 // to construct the type. 510 if (!selfParamIndex) { 511 const AttrDef &attrDef = cast<AttrDef>(def); 512 if (Optional<StringRef> typeBuilder = attrDef.getTypeBuilder()) { 513 FmtContext fmtContext; 514 for (const AttrOrTypeParameter ¶m : parameters) 515 fmtContext.addSubst(("_" + param.getName()).str(), param.getName()); 516 paramOS << tgfmt(*typeBuilder, &fmtContext); 517 } 518 } 519 paramOS << ")"; 520 521 // Append the parameters to the initializer. 522 for (auto it : llvm::enumerate(parameters)) 523 if (it.index() != selfParamIndex) 524 paramOS << llvm::formatv(", {0}({0})", it.value().getName()); 525 526 return paramOS.str(); 527 } 528 529 void DefGenerator::emitStorageClass(const AttrOrTypeDef &def) { 530 SmallVector<AttrOrTypeParameter, 4> params; 531 def.getParameters(params); 532 533 // Collect the parameter types. 534 auto parameterTypes = 535 llvm::map_range(params, [](const AttrOrTypeParameter ¶meter) { 536 return parameter.getCppType(); 537 }); 538 std::string parameterTypeList = llvm::join(parameterTypes, ", "); 539 540 // Collect the parameter initializer. 541 std::string paramInitializer; 542 if (isAttrGenerator) { 543 paramInitializer = buildAttributeStorageParamInitializer(def, params); 544 545 } else { 546 llvm::raw_string_ostream initOS(paramInitializer); 547 llvm::interleaveComma(params, initOS, [&](const AttrOrTypeParameter &it) { 548 initOS << llvm::formatv("{0}({0})", it.getName()); 549 }); 550 } 551 552 // * Emit most of the storage class up until the hashKey body. 553 os << formatv( 554 defStorageClassBeginStr, def.getStorageNamespace(), 555 def.getStorageClassName(), 556 ParamCommaFormatter(ParamCommaFormatter::EmitFormat::TypeNamePairs, 557 params, /*prependComma=*/false), 558 paramInitializer, parameterTypeList, valueType); 559 560 // * Emit the comparison method. 561 os << " bool operator==(const KeyTy &key) const {\n"; 562 for (auto it : llvm::enumerate(params)) { 563 os << " if (!("; 564 565 // Build the comparator context. 566 bool isSelfType = isa<AttributeSelfTypeParameter>(it.value()); 567 FmtContext context; 568 context.addSubst("_lhs", isSelfType ? "getType()" : it.value().getName()) 569 .addSubst("_rhs", "std::get<" + Twine(it.index()) + ">(key)"); 570 571 // Use the parameter specified comparator if possible, otherwise default to 572 // operator==. 573 Optional<StringRef> comparator = it.value().getComparator(); 574 os << tgfmt(comparator ? *comparator : "$_lhs == $_rhs", &context); 575 os << "))\n return false;\n"; 576 } 577 os << " return true;\n }\n"; 578 579 // * Emit the haskKey method. 580 os << " static ::llvm::hash_code hashKey(const KeyTy &key) {\n"; 581 582 // Extract each parameter from the key. 583 os << " return ::llvm::hash_combine("; 584 llvm::interleaveComma( 585 llvm::seq<unsigned>(0, params.size()), os, 586 [&](unsigned it) { os << "std::get<" << it << ">(key)"; }); 587 os << ");\n }\n"; 588 589 // * Emit the construct method. 590 591 // If user wants to build the storage constructor themselves, declare it 592 // here and then they can write the definition elsewhere. 593 if (def.hasStorageCustomConstructor()) { 594 os << llvm::formatv(" static {0} *construct(::mlir::{1}StorageAllocator " 595 "&allocator, const KeyTy &key);\n", 596 def.getStorageClassName(), valueType); 597 598 // Otherwise, generate one. 599 } else { 600 // First, unbox the parameters. 601 os << formatv(defStorageClassConstructorBeginStr, def.getStorageClassName(), 602 valueType); 603 for (unsigned i = 0, e = params.size(); i < e; ++i) { 604 os << formatv(" auto {0} = std::get<{1}>(key);\n", 605 params[i].getName(), i); 606 } 607 608 // Second, reassign the parameter variables with allocation code, if it's 609 // specified. 610 emitStorageParameterAllocation(def, os); 611 612 // Last, return an allocated copy. 613 auto parameterNames = llvm::map_range( 614 params, [](const auto ¶m) { return param.getName(); }); 615 os << formatv(defStorageClassConstructorEndStr, def.getStorageClassName(), 616 llvm::join(parameterNames, ", ")); 617 } 618 619 // * Emit the parameters as storage class members. 620 for (const AttrOrTypeParameter ¶meter : params) { 621 // Attribute value types are not stored as fields in the storage. 622 if (!isa<AttributeSelfTypeParameter>(parameter)) 623 os << " " << parameter.getCppType() << " " << parameter.getName() 624 << ";\n"; 625 } 626 os << " };\n"; 627 628 os << "} // namespace " << def.getStorageNamespace() << "\n"; 629 } 630 631 void DefGenerator::emitParsePrint(const AttrOrTypeDef &def) { 632 // Emit the printer code, if specified. 633 if (Optional<StringRef> printerCode = def.getPrinterCode()) { 634 // Both the mnenomic and printerCode must be defined (for parity with 635 // parserCode). 636 os << "void " << def.getCppClassName() 637 << "::print(::mlir::DialectAsmPrinter &printer) const {\n"; 638 if (printerCode->empty()) { 639 // If no code specified, emit error. 640 PrintFatalError(def.getLoc(), 641 def.getName() + 642 ": printer (if specified) must have non-empty code"); 643 } 644 FmtContext fmtCtxt = FmtContext().addSubst("_printer", "printer"); 645 os << tgfmt(*printerCode, &fmtCtxt) << "\n}\n"; 646 } 647 648 // Emit the parser code, if specified. 649 if (Optional<StringRef> parserCode = def.getParserCode()) { 650 FmtContext fmtCtxt; 651 fmtCtxt.addSubst("_parser", "parser").addSubst("_ctxt", "context"); 652 653 // The mnenomic must be defined so the dispatcher knows how to dispatch. 654 os << llvm::formatv("::mlir::{0} {1}::parse(::mlir::MLIRContext *context, " 655 "::mlir::DialectAsmParser &parser", 656 valueType, def.getCppClassName()); 657 if (isAttrGenerator) { 658 // Attributes also accept a type parameter instead of a context. 659 os << ", ::mlir::Type type"; 660 fmtCtxt.addSubst("_type", "type"); 661 } 662 os << ") {\n"; 663 664 if (parserCode->empty()) { 665 PrintFatalError(def.getLoc(), 666 def.getName() + 667 ": parser (if specified) must have non-empty code"); 668 } 669 os << tgfmt(*parserCode, &fmtCtxt) << "\n}\n"; 670 } 671 } 672 673 /// Replace all instances of 'from' to 'to' in `str` and return the new string. 674 static std::string replaceInStr(std::string str, StringRef from, StringRef to) { 675 size_t pos = 0; 676 while ((pos = str.find(from.data(), pos, from.size())) != std::string::npos) 677 str.replace(pos, from.size(), to.data(), to.size()); 678 return str; 679 } 680 681 /// Emit the builders for the given def. 682 static void emitBuilderDefs(const AttrOrTypeDef &def, raw_ostream &os, 683 ArrayRef<AttrOrTypeParameter> params) { 684 bool genCheckedMethods = def.genVerifyDecl(); 685 StringRef className = def.getCppClassName(); 686 if (!def.skipDefaultBuilders()) { 687 os << llvm::formatv( 688 "{0} {0}::get(::mlir::MLIRContext *context{1}) {{\n" 689 " return Base::get(context{2});\n}\n", 690 className, 691 ParamCommaFormatter(ParamCommaFormatter::EmitFormat::TypeNamePairs, 692 params), 693 ParamCommaFormatter(ParamCommaFormatter::EmitFormat::JustParams, 694 params)); 695 if (genCheckedMethods) { 696 os << llvm::formatv( 697 "{0} {0}::getChecked(" 698 "llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, " 699 "::mlir::MLIRContext *context{1}) {{\n" 700 " return Base::getChecked(emitError, context{2});\n}\n", 701 className, 702 ParamCommaFormatter(ParamCommaFormatter::EmitFormat::TypeNamePairs, 703 params), 704 ParamCommaFormatter(ParamCommaFormatter::EmitFormat::JustParams, 705 params)); 706 } 707 } 708 709 auto builderFmtCtx = 710 FmtContext().addSubst("_ctxt", "context").addSubst("_get", "Base::get"); 711 auto inferredCtxBuilderFmtCtx = FmtContext().addSubst("_get", "Base::get"); 712 auto checkedBuilderFmtCtx = FmtContext().addSubst("_ctxt", "context"); 713 714 // Generate the builders specified by the user. 715 for (const AttrOrTypeBuilder &builder : def.getBuilders()) { 716 Optional<StringRef> body = builder.getBody(); 717 if (!body) 718 continue; 719 std::string paramStr; 720 llvm::raw_string_ostream paramOS(paramStr); 721 llvm::interleaveComma(builder.getParameters(), paramOS, 722 [&](const AttrOrTypeBuilder::Parameter ¶m) { 723 // Note: AttrOrTypeBuilder parameters are guaranteed 724 // to have names. 725 paramOS << param.getCppType() << " " 726 << *param.getName(); 727 }); 728 paramOS.flush(); 729 730 // Emit the `get` variant of the builder. 731 os << llvm::formatv("{0} {0}::get(", className); 732 if (!builder.hasInferredContextParameter()) { 733 os << "::mlir::MLIRContext *context"; 734 if (!paramStr.empty()) 735 os << ", "; 736 os << llvm::formatv("{0}) {{\n {1};\n}\n", paramStr, 737 tgfmt(*body, &builderFmtCtx).str()); 738 } else { 739 os << llvm::formatv("{0}) {{\n {1};\n}\n", paramStr, 740 tgfmt(*body, &inferredCtxBuilderFmtCtx).str()); 741 } 742 743 // Emit the `getChecked` variant of the builder. 744 if (genCheckedMethods) { 745 os << llvm::formatv("{0} " 746 "{0}::getChecked(llvm::function_ref<::mlir::" 747 "InFlightDiagnostic()> emitErrorFn", 748 className); 749 std::string checkedBody = 750 replaceInStr(body->str(), "$_get(", "Base::getChecked(emitErrorFn, "); 751 if (!builder.hasInferredContextParameter()) { 752 os << ", ::mlir::MLIRContext *context"; 753 checkedBody = tgfmt(checkedBody, &checkedBuilderFmtCtx).str(); 754 } 755 if (!paramStr.empty()) 756 os << ", "; 757 os << llvm::formatv("{0}) {{\n {1};\n}\n", paramStr, checkedBody); 758 } 759 } 760 } 761 762 /// Print all the def-specific definition code. 763 void DefGenerator::emitDefDef(const AttrOrTypeDef &def) { 764 NamespaceEmitter ns(os, def.getDialect()); 765 766 SmallVector<AttrOrTypeParameter, 4> parameters; 767 def.getParameters(parameters); 768 if (!parameters.empty()) { 769 // Emit the storage class, if requested and necessary. 770 if (def.genStorageClass()) 771 emitStorageClass(def); 772 773 // Emit the builders for this def. 774 emitBuilderDefs(def, os, parameters); 775 776 // Generate accessor definitions only if we also generate the storage class. 777 // Otherwise, let the user define the exact accessor definition. 778 if (def.genAccessors() && def.genStorageClass()) { 779 for (const AttrOrTypeParameter ¶m : parameters) { 780 SmallString<32> paramStorageName; 781 if (isa<AttributeSelfTypeParameter>(param)) { 782 Twine("getType().cast<" + param.getCppType() + ">()") 783 .toVector(paramStorageName); 784 } else { 785 paramStorageName = param.getName(); 786 } 787 788 SmallString<16> name = param.getName(); 789 name[0] = llvm::toUpper(name[0]); 790 os << formatv("{0} {3}::get{1}() const {{ return getImpl()->{2}; }\n", 791 param.getCppType(), name, paramStorageName, 792 def.getCppClassName()); 793 } 794 } 795 } 796 797 // If mnemonic is specified maybe print definitions for the parser and printer 798 // code, if they're specified. 799 if (def.getMnemonic()) 800 emitParsePrint(def); 801 } 802 803 /// Emit the dialect printer/parser dispatcher. User's code should call these 804 /// functions from their dialect's print/parse methods. 805 void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) { 806 if (llvm::none_of(defs, [](const AttrOrTypeDef &def) { 807 return def.getMnemonic().hasValue(); 808 })) { 809 return; 810 } 811 812 // The parser dispatch is just a list of if-elses, matching on the mnemonic 813 // and calling the def's parse function. 814 os << llvm::formatv(defParserDispatchStartStr, valueType, 815 isAttrGenerator ? ", ::mlir::Type type" : ""); 816 for (const AttrOrTypeDef &def : defs) { 817 if (def.getMnemonic()) { 818 os << formatv(" if (mnemonic == {0}::{1}::getMnemonic()) { \n" 819 " value = {0}::{1}::", 820 def.getDialect().getCppNamespace(), def.getCppClassName()); 821 822 // If the def has no parameters and no parser code, just invoke a normal 823 // `get`. 824 if (def.getNumParameters() == 0 && !def.getParserCode()) { 825 os << "get(context);\n return ::mlir::success(!!value);\n }\n"; 826 continue; 827 } 828 829 os << "parse(context, parser" << (isAttrGenerator ? ", type" : "") 830 << ");\n return ::mlir::success(!!value);\n }\n"; 831 } 832 } 833 os << " return {};\n"; 834 os << "}\n\n"; 835 836 // The printer dispatch uses llvm::TypeSwitch to find and call the correct 837 // printer. 838 os << llvm::formatv(defPrinterDispatchStartStr, valueType); 839 for (const AttrOrTypeDef &def : defs) { 840 Optional<StringRef> mnemonic = def.getMnemonic(); 841 if (!mnemonic) 842 continue; 843 844 StringRef cppNamespace = def.getDialect().getCppNamespace(); 845 StringRef cppClassName = def.getCppClassName(); 846 os << formatv(" .Case<{0}::{1}>([&]({0}::{1} t) {{\n ", 847 cppNamespace, cppClassName); 848 849 // If the def has no parameters and no printer, just print the mnemonic. 850 if (def.getNumParameters() == 0 && !def.getPrinterCode()) { 851 os << formatv("printer << {0}::{1}::getMnemonic();", cppNamespace, 852 cppClassName); 853 } else { 854 os << "t.print(printer);"; 855 } 856 os << "\n return ::mlir::success();\n })\n"; 857 } 858 os << llvm::formatv( 859 " .Default([](::mlir::{0}) {{ return ::mlir::failure(); });\n}\n\n", 860 valueType); 861 } 862 863 bool DefGenerator::emitDefs(StringRef selectedDialect) { 864 emitSourceFileHeader((defTypePrefix + "Def Definitions").str(), os); 865 866 SmallVector<AttrOrTypeDef, 16> defs; 867 collectAllDefs(selectedDialect, defRecords, defs); 868 if (defs.empty()) 869 return false; 870 emitTypeDefList(defs); 871 872 IfDefScope scope("GET_" + defTypePrefix.upper() + "DEF_CLASSES", os); 873 emitParsePrintDispatch(defs); 874 for (const AttrOrTypeDef &def : defs) 875 emitDefDef(def); 876 877 return false; 878 } 879 880 //===----------------------------------------------------------------------===// 881 // GEN: Registration hooks 882 //===----------------------------------------------------------------------===// 883 884 //===----------------------------------------------------------------------===// 885 // AttrDef 886 887 static llvm::cl::OptionCategory attrdefGenCat("Options for -gen-attrdef-*"); 888 static llvm::cl::opt<std::string> 889 attrDialect("attrdefs-dialect", 890 llvm::cl::desc("Generate attributes for this dialect"), 891 llvm::cl::cat(attrdefGenCat), llvm::cl::CommaSeparated); 892 893 static mlir::GenRegistration 894 genAttrDefs("gen-attrdef-defs", "Generate AttrDef definitions", 895 [](const llvm::RecordKeeper &records, raw_ostream &os) { 896 AttrDefGenerator generator(records, os); 897 return generator.emitDefs(attrDialect); 898 }); 899 static mlir::GenRegistration 900 genAttrDecls("gen-attrdef-decls", "Generate AttrDef declarations", 901 [](const llvm::RecordKeeper &records, raw_ostream &os) { 902 AttrDefGenerator generator(records, os); 903 return generator.emitDecls(attrDialect); 904 }); 905 906 //===----------------------------------------------------------------------===// 907 // TypeDef 908 909 static llvm::cl::OptionCategory typedefGenCat("Options for -gen-typedef-*"); 910 static llvm::cl::opt<std::string> 911 typeDialect("typedefs-dialect", 912 llvm::cl::desc("Generate types for this dialect"), 913 llvm::cl::cat(typedefGenCat), llvm::cl::CommaSeparated); 914 915 static mlir::GenRegistration 916 genTypeDefs("gen-typedef-defs", "Generate TypeDef definitions", 917 [](const llvm::RecordKeeper &records, raw_ostream &os) { 918 TypeDefGenerator generator(records, os); 919 return generator.emitDefs(typeDialect); 920 }); 921 static mlir::GenRegistration 922 genTypeDecls("gen-typedef-decls", "Generate TypeDef declarations", 923 [](const llvm::RecordKeeper &records, raw_ostream &os) { 924 TypeDefGenerator generator(records, os); 925 return generator.emitDecls(typeDialect); 926 }); 927