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 "AttrOrTypeFormatGen.h" 10 #include "mlir/Support/LogicalResult.h" 11 #include "mlir/TableGen/AttrOrTypeDef.h" 12 #include "mlir/TableGen/Class.h" 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 "llvm/ADT/Sequence.h" 18 #include "llvm/ADT/SetVector.h" 19 #include "llvm/ADT/SmallSet.h" 20 #include "llvm/ADT/StringSet.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/TableGen/Error.h" 23 #include "llvm/TableGen/TableGenBackend.h" 24 25 #define DEBUG_TYPE "mlir-tblgen-attrortypedefgen" 26 27 using namespace mlir; 28 using namespace mlir::tblgen; 29 30 //===----------------------------------------------------------------------===// 31 // Utility Functions 32 //===----------------------------------------------------------------------===// 33 34 std::string mlir::tblgen::getParameterAccessorName(StringRef name) { 35 assert(!name.empty() && "parameter has empty name"); 36 auto ret = "get" + name.str(); 37 ret[3] = llvm::toUpper(ret[3]); // uppercase first letter of the name 38 return ret; 39 } 40 41 /// Find all the AttrOrTypeDef for the specified dialect. If no dialect 42 /// specified and can only find one dialect's defs, use that. 43 static void collectAllDefs(StringRef selectedDialect, 44 std::vector<llvm::Record *> records, 45 SmallVectorImpl<AttrOrTypeDef> &resultDefs) { 46 // Nothing to do if no defs were found. 47 if (records.empty()) 48 return; 49 50 auto defs = llvm::map_range( 51 records, [&](const llvm::Record *rec) { return AttrOrTypeDef(rec); }); 52 if (selectedDialect.empty()) { 53 // If a dialect was not specified, ensure that all found defs belong to the 54 // same dialect. 55 if (!llvm::is_splat(llvm::map_range( 56 defs, [](const auto &def) { return def.getDialect(); }))) { 57 llvm::PrintFatalError("defs belonging to more than one dialect. Must " 58 "select one via '--(attr|type)defs-dialect'"); 59 } 60 resultDefs.assign(defs.begin(), defs.end()); 61 } else { 62 // Otherwise, generate the defs that belong to the selected dialect. 63 auto dialectDefs = llvm::make_filter_range(defs, [&](const auto &def) { 64 return def.getDialect().getName().equals(selectedDialect); 65 }); 66 resultDefs.assign(dialectDefs.begin(), dialectDefs.end()); 67 } 68 } 69 70 //===----------------------------------------------------------------------===// 71 // DefGen 72 //===----------------------------------------------------------------------===// 73 74 namespace { 75 class DefGen { 76 public: 77 /// Create the attribute or type class. 78 DefGen(const AttrOrTypeDef &def); 79 80 void emitDecl(raw_ostream &os) const { 81 if (storageCls) { 82 NamespaceEmitter ns(os, def.getStorageNamespace()); 83 os << "struct " << def.getStorageClassName() << ";\n"; 84 } 85 defCls.writeDeclTo(os); 86 } 87 void emitDef(raw_ostream &os) const { 88 if (storageCls && def.genStorageClass()) { 89 NamespaceEmitter ns(os, def.getStorageNamespace()); 90 storageCls->writeDeclTo(os); // everything is inline 91 } 92 defCls.writeDefTo(os); 93 } 94 95 private: 96 /// Add traits from the TableGen definition to the class. 97 void createParentWithTraits(); 98 /// Emit top-level declarations: using declarations and any extra class 99 /// declarations. 100 void emitTopLevelDeclarations(); 101 /// Emit attribute or type builders. 102 void emitBuilders(); 103 /// Emit a verifier for the def. 104 void emitVerifier(); 105 /// Emit parsers and printers. 106 void emitParserPrinter(); 107 /// Emit parameter accessors, if required. 108 void emitAccessors(); 109 /// Emit interface methods. 110 void emitInterfaceMethods(); 111 112 //===--------------------------------------------------------------------===// 113 // Builder Emission 114 115 /// Emit the default builder `Attribute::get` 116 void emitDefaultBuilder(); 117 /// Emit the checked builder `Attribute::getChecked` 118 void emitCheckedBuilder(); 119 /// Emit a custom builder. 120 void emitCustomBuilder(const AttrOrTypeBuilder &builder); 121 /// Emit a checked custom builder. 122 void emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder); 123 124 //===--------------------------------------------------------------------===// 125 // Parser and Printer Emission 126 void emitParserPrinterBody(MethodBody &parser, MethodBody &printer); 127 128 //===--------------------------------------------------------------------===// 129 // Interface Method Emission 130 131 /// Emit methods for a trait. 132 void emitTraitMethods(const InterfaceTrait &trait); 133 /// Emit a trait method. 134 void emitTraitMethod(const InterfaceMethod &method); 135 136 //===--------------------------------------------------------------------===// 137 // Storage Class Emission 138 void emitStorageClass(); 139 /// Generate the storage class constructor. 140 void emitStorageConstructor(); 141 /// Emit the key type `KeyTy`. 142 void emitKeyType(); 143 /// Emit the equality comparison operator. 144 void emitEquals(); 145 /// Emit the key hash function. 146 void emitHashKey(); 147 /// Emit the function to construct the storage class. 148 void emitConstruct(); 149 150 //===--------------------------------------------------------------------===// 151 // Utility Function Declarations 152 153 /// Get the method parameters for a def builder, where the first several 154 /// parameters may be different. 155 SmallVector<MethodParameter> 156 getBuilderParams(std::initializer_list<MethodParameter> prefix) const; 157 158 //===--------------------------------------------------------------------===// 159 // Class fields 160 161 /// The attribute or type definition. 162 const AttrOrTypeDef &def; 163 /// The list of attribute or type parameters. 164 ArrayRef<AttrOrTypeParameter> params; 165 /// The attribute or type class. 166 Class defCls; 167 /// An optional attribute or type storage class. The storage class will 168 /// exist if and only if the def has more than zero parameters. 169 Optional<Class> storageCls; 170 171 /// The C++ base value of the def, either "Attribute" or "Type". 172 StringRef valueType; 173 /// The prefix/suffix of the TableGen def name, either "Attr" or "Type". 174 StringRef defType; 175 }; 176 } // namespace 177 178 DefGen::DefGen(const AttrOrTypeDef &def) 179 : def(def), params(def.getParameters()), defCls(def.getCppClassName()), 180 valueType(isa<AttrDef>(def) ? "Attribute" : "Type"), 181 defType(isa<AttrDef>(def) ? "Attr" : "Type") { 182 // If a storage class is needed, create one. 183 if (def.getNumParameters() > 0) 184 storageCls.emplace(def.getStorageClassName(), /*isStruct=*/true); 185 186 // Create the parent class with any indicated traits. 187 createParentWithTraits(); 188 // Emit top-level declarations. 189 emitTopLevelDeclarations(); 190 // Emit builders for defs with parameters 191 if (storageCls) 192 emitBuilders(); 193 // Emit the verifier. 194 if (storageCls && def.genVerifyDecl()) 195 emitVerifier(); 196 // Emit the mnemonic, if there is one, and any associated parser and printer. 197 if (def.getMnemonic()) 198 emitParserPrinter(); 199 // Emit accessors 200 if (def.genAccessors()) 201 emitAccessors(); 202 // Emit trait interface methods 203 emitInterfaceMethods(); 204 defCls.finalize(); 205 // Emit a storage class if one is needed 206 if (storageCls && def.genStorageClass()) 207 emitStorageClass(); 208 } 209 210 void DefGen::createParentWithTraits() { 211 ParentClass defParent(strfmt("::mlir::{0}::{1}Base", valueType, defType)); 212 defParent.addTemplateParam(def.getCppClassName()); 213 defParent.addTemplateParam(def.getCppBaseClassName()); 214 defParent.addTemplateParam(storageCls 215 ? strfmt("{0}::{1}", def.getStorageNamespace(), 216 def.getStorageClassName()) 217 : strfmt("::mlir::{0}Storage", valueType)); 218 for (auto &trait : def.getTraits()) { 219 defParent.addTemplateParam( 220 isa<NativeTrait>(&trait) 221 ? cast<NativeTrait>(&trait)->getFullyQualifiedTraitName() 222 : cast<InterfaceTrait>(&trait)->getFullyQualifiedTraitName()); 223 } 224 defCls.addParent(std::move(defParent)); 225 } 226 227 void DefGen::emitTopLevelDeclarations() { 228 // Inherit constructors from the attribute or type class. 229 defCls.declare<VisibilityDeclaration>(Visibility::Public); 230 defCls.declare<UsingDeclaration>("Base::Base"); 231 232 // Emit the extra declarations first in case there's a definition in there. 233 if (Optional<StringRef> extraDecl = def.getExtraDecls()) 234 defCls.declare<ExtraClassDeclaration>(*extraDecl); 235 } 236 237 void DefGen::emitBuilders() { 238 if (!def.skipDefaultBuilders()) { 239 emitDefaultBuilder(); 240 if (def.genVerifyDecl()) 241 emitCheckedBuilder(); 242 } 243 for (auto &builder : def.getBuilders()) { 244 emitCustomBuilder(builder); 245 if (def.genVerifyDecl()) 246 emitCheckedCustomBuilder(builder); 247 } 248 } 249 250 void DefGen::emitVerifier() { 251 defCls.declare<UsingDeclaration>("Base::getChecked"); 252 defCls.declareStaticMethod( 253 "::mlir::LogicalResult", "verify", 254 getBuilderParams({{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", 255 "emitError"}})); 256 } 257 258 void DefGen::emitParserPrinter() { 259 auto *mnemonic = defCls.addStaticMethod<Method::Constexpr>( 260 "::llvm::StringLiteral", "getMnemonic"); 261 mnemonic->body().indent() << strfmt("return {\"{0}\"};", *def.getMnemonic()); 262 // Declare the parser and printer, if needed. 263 if (!def.needsParserPrinter() && !def.hasGeneratedParser() && 264 !def.hasGeneratedPrinter()) 265 return; 266 267 // Declare the parser. 268 SmallVector<MethodParameter> parserParams; 269 parserParams.emplace_back("::mlir::AsmParser &", "parser"); 270 if (isa<AttrDef>(&def)) 271 parserParams.emplace_back("::mlir::Type", "type"); 272 auto *parser = defCls.addMethod( 273 strfmt("::mlir::{0}", valueType), "parse", 274 def.hasGeneratedParser() ? Method::Static : Method::StaticDeclaration, 275 std::move(parserParams)); 276 // Declare the printer. 277 auto props = 278 def.hasGeneratedPrinter() ? Method::Const : Method::ConstDeclaration; 279 Method *printer = 280 defCls.addMethod("void", "print", props, 281 MethodParameter("::mlir::AsmPrinter &", "printer")); 282 // Emit the bodies. 283 emitParserPrinterBody(parser->body(), printer->body()); 284 } 285 286 void DefGen::emitAccessors() { 287 for (auto ¶m : params) { 288 Method *m = defCls.addMethod( 289 param.getCppAccessorType(), getParameterAccessorName(param.getName()), 290 def.genStorageClass() ? Method::Const : Method::ConstDeclaration); 291 // Generate accessor definitions only if we also generate the storage 292 // class. Otherwise, let the user define the exact accessor definition. 293 if (!def.genStorageClass()) 294 continue; 295 auto scope = m->body().indent().scope("return getImpl()->", ";"); 296 if (isa<AttributeSelfTypeParameter>(param)) 297 m->body() << formatv("getType().cast<{0}>()", param.getCppType()); 298 else 299 m->body() << param.getName(); 300 } 301 } 302 303 void DefGen::emitInterfaceMethods() { 304 for (auto &traitDef : def.getTraits()) 305 if (auto *trait = dyn_cast<InterfaceTrait>(&traitDef)) 306 if (trait->shouldDeclareMethods()) 307 emitTraitMethods(*trait); 308 } 309 310 //===----------------------------------------------------------------------===// 311 // Builder Emission 312 313 SmallVector<MethodParameter> 314 DefGen::getBuilderParams(std::initializer_list<MethodParameter> prefix) const { 315 SmallVector<MethodParameter> builderParams; 316 builderParams.append(prefix.begin(), prefix.end()); 317 for (auto ¶m : params) 318 builderParams.emplace_back(param.getCppType(), param.getName()); 319 return builderParams; 320 } 321 322 void DefGen::emitDefaultBuilder() { 323 Method *m = defCls.addStaticMethod( 324 def.getCppClassName(), "get", 325 getBuilderParams({{"::mlir::MLIRContext *", "context"}})); 326 MethodBody &body = m->body().indent(); 327 auto scope = body.scope("return Base::get(context", ");"); 328 llvm::for_each(params, [&](auto ¶m) { body << ", " << param.getName(); }); 329 } 330 331 void DefGen::emitCheckedBuilder() { 332 Method *m = defCls.addStaticMethod( 333 def.getCppClassName(), "getChecked", 334 getBuilderParams( 335 {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}, 336 {"::mlir::MLIRContext *", "context"}})); 337 MethodBody &body = m->body().indent(); 338 auto scope = body.scope("return Base::getChecked(emitError, context", ");"); 339 llvm::for_each(params, [&](auto ¶m) { body << ", " << param.getName(); }); 340 } 341 342 static SmallVector<MethodParameter> 343 getCustomBuilderParams(std::initializer_list<MethodParameter> prefix, 344 const AttrOrTypeBuilder &builder) { 345 auto params = builder.getParameters(); 346 SmallVector<MethodParameter> builderParams; 347 builderParams.append(prefix.begin(), prefix.end()); 348 if (!builder.hasInferredContextParameter()) 349 builderParams.emplace_back("::mlir::MLIRContext *", "context"); 350 for (auto ¶m : params) { 351 builderParams.emplace_back(param.getCppType(), *param.getName(), 352 param.getDefaultValue()); 353 } 354 return builderParams; 355 } 356 357 void DefGen::emitCustomBuilder(const AttrOrTypeBuilder &builder) { 358 // Don't emit a body if there isn't one. 359 auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration; 360 Method *m = defCls.addMethod(def.getCppClassName(), "get", props, 361 getCustomBuilderParams({}, builder)); 362 if (!builder.getBody()) 363 return; 364 365 // Format the body and emit it. 366 FmtContext ctx; 367 ctx.addSubst("_get", "Base::get"); 368 if (!builder.hasInferredContextParameter()) 369 ctx.addSubst("_ctxt", "context"); 370 std::string bodyStr = tgfmt(*builder.getBody(), &ctx); 371 m->body().indent().getStream().printReindented(bodyStr); 372 } 373 374 /// Replace all instances of 'from' to 'to' in `str` and return the new string. 375 static std::string replaceInStr(std::string str, StringRef from, StringRef to) { 376 size_t pos = 0; 377 while ((pos = str.find(from.data(), pos, from.size())) != std::string::npos) 378 str.replace(pos, from.size(), to.data(), to.size()); 379 return str; 380 } 381 382 void DefGen::emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder) { 383 // Don't emit a body if there isn't one. 384 auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration; 385 Method *m = defCls.addMethod( 386 def.getCppClassName(), "getChecked", props, 387 getCustomBuilderParams( 388 {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}}, 389 builder)); 390 if (!builder.getBody()) 391 return; 392 393 // Format the body and emit it. Replace $_get(...) with 394 // Base::getChecked(emitError, ...) 395 FmtContext ctx; 396 if (!builder.hasInferredContextParameter()) 397 ctx.addSubst("_ctxt", "context"); 398 std::string bodyStr = replaceInStr(builder.getBody()->str(), "$_get(", 399 "Base::getChecked(emitError, "); 400 bodyStr = tgfmt(bodyStr, &ctx); 401 m->body().indent().getStream().printReindented(bodyStr); 402 } 403 404 //===----------------------------------------------------------------------===// 405 // Parser and Printer Emission 406 407 void DefGen::emitParserPrinterBody(MethodBody &parser, MethodBody &printer) { 408 Optional<StringRef> parserCode = def.getParserCode(); 409 Optional<StringRef> printerCode = def.getPrinterCode(); 410 Optional<StringRef> asmFormat = def.getAssemblyFormat(); 411 // Verify the parser-printer specification first. 412 if (asmFormat && (parserCode || printerCode)) { 413 PrintFatalError(def.getLoc(), 414 def.getName() + ": assembly format cannot be specified at " 415 "the same time as printer or parser code"); 416 } 417 // Specified code cannot be empty. 418 if (parserCode && parserCode->empty()) 419 PrintFatalError(def.getLoc(), def.getName() + ": parser cannot be empty"); 420 if (printerCode && printerCode->empty()) 421 PrintFatalError(def.getLoc(), def.getName() + ": printer cannot be empty"); 422 // Assembly format requires accessors to be generated. 423 if (asmFormat && !def.genAccessors()) { 424 PrintFatalError(def.getLoc(), 425 def.getName() + 426 ": the generated printer from 'assemblyFormat' " 427 "requires 'genAccessors' to be true"); 428 } 429 430 // Generate the parser and printer bodies. 431 if (asmFormat) 432 return generateAttrOrTypeFormat(def, parser, printer); 433 434 FmtContext ctx = FmtContext( 435 {{"_parser", "parser"}, {"_printer", "printer"}, {"_type", "type"}}); 436 if (parserCode) { 437 ctx.addSubst("_ctxt", "parser.getContext()"); 438 parser.indent().getStream().printReindented(tgfmt(*parserCode, &ctx).str()); 439 } 440 if (printerCode) { 441 ctx.addSubst("_ctxt", "printer.getContext()"); 442 printer.indent().getStream().printReindented( 443 tgfmt(*printerCode, &ctx).str()); 444 } 445 } 446 447 //===----------------------------------------------------------------------===// 448 // Interface Method Emission 449 450 void DefGen::emitTraitMethods(const InterfaceTrait &trait) { 451 // Get the set of methods that should always be declared. 452 auto alwaysDeclaredMethods = trait.getAlwaysDeclaredMethods(); 453 StringSet<> alwaysDeclared; 454 alwaysDeclared.insert(alwaysDeclaredMethods.begin(), 455 alwaysDeclaredMethods.end()); 456 457 Interface iface = trait.getInterface(); // causes strange bugs if elided 458 for (auto &method : iface.getMethods()) { 459 // Don't declare if the method has a body. Or if the method has a default 460 // implementation and the def didn't request that it always be declared. 461 if (method.getBody() || (method.getDefaultImplementation() && 462 !alwaysDeclared.count(method.getName()))) 463 continue; 464 emitTraitMethod(method); 465 } 466 } 467 468 void DefGen::emitTraitMethod(const InterfaceMethod &method) { 469 // All interface methods are declaration-only. 470 auto props = 471 method.isStatic() ? Method::StaticDeclaration : Method::ConstDeclaration; 472 SmallVector<MethodParameter> params; 473 for (auto ¶m : method.getArguments()) 474 params.emplace_back(param.type, param.name); 475 defCls.addMethod(method.getReturnType(), method.getName(), props, 476 std::move(params)); 477 } 478 479 //===----------------------------------------------------------------------===// 480 // Storage Class Emission 481 482 void DefGen::emitStorageConstructor() { 483 Constructor *ctor = 484 storageCls->addConstructor<Method::Inline>(getBuilderParams({})); 485 if (auto *attrDef = dyn_cast<AttrDef>(&def)) { 486 // For attributes, a parameter marked with AttributeSelfTypeParameter is 487 // the type initializer that must be passed to the parent constructor. 488 const auto isSelfType = [](const AttrOrTypeParameter ¶m) { 489 return isa<AttributeSelfTypeParameter>(param); 490 }; 491 auto *selfTypeParam = llvm::find_if(params, isSelfType); 492 if (std::count_if(selfTypeParam, params.end(), isSelfType) > 1) { 493 PrintFatalError(def.getLoc(), 494 "Only one attribute parameter can be marked as " 495 "AttributeSelfTypeParameter"); 496 } 497 // Alternatively, if a type builder was specified, use that instead. 498 std::string attrStorageInit = 499 selfTypeParam == params.end() ? "" : selfTypeParam->getName().str(); 500 if (attrDef->getTypeBuilder()) { 501 FmtContext ctx; 502 for (auto ¶m : params) 503 ctx.addSubst(strfmt("_{0}", param.getName()), param.getName()); 504 attrStorageInit = tgfmt(*attrDef->getTypeBuilder(), &ctx); 505 } 506 ctor->addMemberInitializer("::mlir::AttributeStorage", 507 std::move(attrStorageInit)); 508 // Initialize members that aren't the attribute's type. 509 for (auto ¶m : params) 510 if (selfTypeParam == params.end() || *selfTypeParam != param) 511 ctor->addMemberInitializer(param.getName(), param.getName()); 512 } else { 513 for (auto ¶m : params) 514 ctor->addMemberInitializer(param.getName(), param.getName()); 515 } 516 } 517 518 void DefGen::emitKeyType() { 519 std::string keyType("std::tuple<"); 520 llvm::raw_string_ostream os(keyType); 521 llvm::interleaveComma(params, os, 522 [&](auto ¶m) { os << param.getCppType(); }); 523 os << '>'; 524 storageCls->declare<UsingDeclaration>("KeyTy", std::move(os.str())); 525 } 526 527 void DefGen::emitEquals() { 528 Method *eq = storageCls->addConstMethod<Method::Inline>( 529 "bool", "operator==", MethodParameter("const KeyTy &", "tblgenKey")); 530 auto &body = eq->body().indent(); 531 auto scope = body.scope("return (", ");"); 532 const auto eachFn = [&](auto it) { 533 FmtContext ctx({{"_lhs", isa<AttributeSelfTypeParameter>(it.value()) 534 ? "getType()" 535 : it.value().getName()}, 536 {"_rhs", strfmt("std::get<{0}>(tblgenKey)", it.index())}}); 537 Optional<StringRef> comparator = it.value().getComparator(); 538 body << tgfmt(comparator ? *comparator : "$_lhs == $_rhs", &ctx); 539 }; 540 llvm::interleave(llvm::enumerate(params), body, eachFn, ") && ("); 541 } 542 543 void DefGen::emitHashKey() { 544 Method *hash = storageCls->addStaticInlineMethod( 545 "::llvm::hash_code", "hashKey", 546 MethodParameter("const KeyTy &", "tblgenKey")); 547 auto &body = hash->body().indent(); 548 auto scope = body.scope("return ::llvm::hash_combine(", ");"); 549 llvm::interleaveComma(llvm::enumerate(params), body, [&](auto it) { 550 body << llvm::formatv("std::get<{0}>(tblgenKey)", it.index()); 551 }); 552 } 553 554 void DefGen::emitConstruct() { 555 Method *construct = storageCls->addMethod<Method::Inline>( 556 strfmt("{0} *", def.getStorageClassName()), "construct", 557 def.hasStorageCustomConstructor() ? Method::StaticDeclaration 558 : Method::Static, 559 MethodParameter(strfmt("::mlir::{0}StorageAllocator &", valueType), 560 "allocator"), 561 MethodParameter("const KeyTy &", "tblgenKey")); 562 if (!def.hasStorageCustomConstructor()) { 563 auto &body = construct->body().indent(); 564 for (const auto &it : llvm::enumerate(params)) { 565 body << formatv("auto {0} = std::get<{1}>(tblgenKey);\n", 566 it.value().getName(), it.index()); 567 } 568 // Use the parameters' custom allocator code, if provided. 569 FmtContext ctx = FmtContext().addSubst("_allocator", "allocator"); 570 for (auto ¶m : params) { 571 if (Optional<StringRef> allocCode = param.getAllocator()) { 572 ctx.withSelf(param.getName()).addSubst("_dst", param.getName()); 573 body << tgfmt(*allocCode, &ctx) << '\n'; 574 } 575 } 576 auto scope = 577 body.scope(strfmt("return new (allocator.allocate<{0}>()) {0}(", 578 def.getStorageClassName()), 579 ");"); 580 llvm::interleaveComma(params, body, 581 [&](auto ¶m) { body << param.getName(); }); 582 } 583 } 584 585 void DefGen::emitStorageClass() { 586 // Add the appropriate parent class. 587 storageCls->addParent(strfmt("::mlir::{0}Storage", valueType)); 588 // Add the constructor. 589 emitStorageConstructor(); 590 // Declare the key type. 591 emitKeyType(); 592 // Add the comparison method. 593 emitEquals(); 594 // Emit the key hash method. 595 emitHashKey(); 596 // Emit the storage constructor. Just declare it if the user wants to define 597 // it themself. 598 emitConstruct(); 599 // Emit the storage class members as public, at the very end of the struct. 600 storageCls->finalize(); 601 for (auto ¶m : params) 602 if (!isa<AttributeSelfTypeParameter>(param)) 603 storageCls->declare<Field>(param.getCppType(), param.getName()); 604 } 605 606 //===----------------------------------------------------------------------===// 607 // DefGenerator 608 //===----------------------------------------------------------------------===// 609 610 namespace { 611 /// This struct is the base generator used when processing tablegen interfaces. 612 class DefGenerator { 613 public: 614 bool emitDecls(StringRef selectedDialect); 615 bool emitDefs(StringRef selectedDialect); 616 617 protected: 618 DefGenerator(std::vector<llvm::Record *> &&defs, raw_ostream &os, 619 StringRef defType, StringRef valueType, bool isAttrGenerator, 620 bool needsDialectParserPrinter) 621 : defRecords(std::move(defs)), os(os), defType(defType), 622 valueType(valueType), isAttrGenerator(isAttrGenerator), 623 needsDialectParserPrinter(needsDialectParserPrinter) {} 624 625 /// Emit the list of def type names. 626 void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs); 627 /// Emit the code to dispatch between different defs during parsing/printing. 628 void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs); 629 630 /// The set of def records to emit. 631 std::vector<llvm::Record *> defRecords; 632 /// The attribute or type class to emit. 633 /// The stream to emit to. 634 raw_ostream &os; 635 /// The prefix of the tablegen def name, e.g. Attr or Type. 636 StringRef defType; 637 /// The C++ base value type of the def, e.g. Attribute or Type. 638 StringRef valueType; 639 /// Flag indicating if this generator is for Attributes. False if the 640 /// generator is for types. 641 bool isAttrGenerator; 642 /// Track if we need to emit the printAttribute/parseAttribute 643 /// implementations. 644 bool needsDialectParserPrinter; 645 }; 646 647 /// A specialized generator for AttrDefs. 648 struct AttrDefGenerator : public DefGenerator { 649 AttrDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os) 650 : DefGenerator(records.getAllDerivedDefinitions("AttrDef"), os, "Attr", 651 "Attribute", 652 /*isAttrGenerator=*/true, 653 /*needsDialectParserPrinter=*/ 654 !records.getAllDerivedDefinitions("DialectAttr").empty()) { 655 } 656 }; 657 /// A specialized generator for TypeDefs. 658 struct TypeDefGenerator : public DefGenerator { 659 TypeDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os) 660 : DefGenerator(records.getAllDerivedDefinitions("TypeDef"), os, "Type", 661 "Type", /*isAttrGenerator=*/false, 662 /*needsDialectParserPrinter=*/ 663 !records.getAllDerivedDefinitions("DialectType").empty()) { 664 } 665 }; 666 } // namespace 667 668 //===----------------------------------------------------------------------===// 669 // GEN: Declarations 670 //===----------------------------------------------------------------------===// 671 672 /// Print this above all the other declarations. Contains type declarations used 673 /// later on. 674 static const char *const typeDefDeclHeader = R"( 675 namespace mlir { 676 class AsmParser; 677 class AsmPrinter; 678 } // namespace mlir 679 )"; 680 681 bool DefGenerator::emitDecls(StringRef selectedDialect) { 682 emitSourceFileHeader((defType + "Def Declarations").str(), os); 683 IfDefScope scope("GET_" + defType.upper() + "DEF_CLASSES", os); 684 685 // Output the common "header". 686 os << typeDefDeclHeader; 687 688 SmallVector<AttrOrTypeDef, 16> defs; 689 collectAllDefs(selectedDialect, defRecords, defs); 690 if (defs.empty()) 691 return false; 692 { 693 NamespaceEmitter nsEmitter(os, defs.front().getDialect()); 694 695 // Declare all the def classes first (in case they reference each other). 696 for (const AttrOrTypeDef &def : defs) 697 os << "class " << def.getCppClassName() << ";\n"; 698 699 // Emit the declarations. 700 for (const AttrOrTypeDef &def : defs) 701 DefGen(def).emitDecl(os); 702 } 703 // Emit the TypeID explicit specializations to have a single definition for 704 // each of these. 705 for (const AttrOrTypeDef &def : defs) 706 if (!def.getDialect().getCppNamespace().empty()) 707 os << "DECLARE_EXPLICIT_TYPE_ID(" << def.getDialect().getCppNamespace() 708 << "::" << def.getCppClassName() << ")\n"; 709 710 return false; 711 } 712 713 //===----------------------------------------------------------------------===// 714 // GEN: Def List 715 //===----------------------------------------------------------------------===// 716 717 void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) { 718 IfDefScope scope("GET_" + defType.upper() + "DEF_LIST", os); 719 auto interleaveFn = [&](const AttrOrTypeDef &def) { 720 os << def.getDialect().getCppNamespace() << "::" << def.getCppClassName(); 721 }; 722 llvm::interleave(defs, os, interleaveFn, ",\n"); 723 os << "\n"; 724 } 725 726 //===----------------------------------------------------------------------===// 727 // GEN: Definitions 728 //===----------------------------------------------------------------------===// 729 730 /// The code block for default attribute parser/printer dispatch boilerplate. 731 /// {0}: the dialect fully qualified class name. 732 static const char *const dialectDefaultAttrPrinterParserDispatch = R"( 733 /// Parse an attribute registered to this dialect. 734 ::mlir::Attribute {0}::parseAttribute(::mlir::DialectAsmParser &parser, 735 ::mlir::Type type) const {{ 736 ::llvm::SMLoc typeLoc = parser.getCurrentLocation(); 737 ::llvm::StringRef attrTag; 738 if (::mlir::failed(parser.parseKeyword(&attrTag))) 739 return {{}; 740 {{ 741 ::mlir::Attribute attr; 742 auto parseResult = generatedAttributeParser(parser, attrTag, type, attr); 743 if (parseResult.hasValue()) 744 return attr; 745 } 746 parser.emitError(typeLoc) << "unknown attribute `" 747 << attrTag << "` in dialect `" << getNamespace() << "`"; 748 return {{}; 749 } 750 /// Print an attribute registered to this dialect. 751 void {0}::printAttribute(::mlir::Attribute attr, 752 ::mlir::DialectAsmPrinter &printer) const {{ 753 if (::mlir::succeeded(generatedAttributePrinter(attr, printer))) 754 return; 755 } 756 )"; 757 758 /// The code block for default type parser/printer dispatch boilerplate. 759 /// {0}: the dialect fully qualified class name. 760 static const char *const dialectDefaultTypePrinterParserDispatch = R"( 761 /// Parse a type registered to this dialect. 762 ::mlir::Type {0}::parseType(::mlir::DialectAsmParser &parser) const {{ 763 ::llvm::SMLoc typeLoc = parser.getCurrentLocation(); 764 ::llvm::StringRef mnemonic; 765 if (parser.parseKeyword(&mnemonic)) 766 return ::mlir::Type(); 767 ::mlir::Type genType; 768 auto parseResult = generatedTypeParser(parser, mnemonic, genType); 769 if (parseResult.hasValue()) 770 return genType; 771 parser.emitError(typeLoc) << "unknown type `" 772 << mnemonic << "` in dialect `" << getNamespace() << "`"; 773 return {{}; 774 } 775 /// Print a type registered to this dialect. 776 void {0}::printType(::mlir::Type type, 777 ::mlir::DialectAsmPrinter &printer) const {{ 778 if (::mlir::succeeded(generatedTypePrinter(type, printer))) 779 return; 780 } 781 )"; 782 783 /// Emit the dialect printer/parser dispatcher. User's code should call these 784 /// functions from their dialect's print/parse methods. 785 void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) { 786 if (llvm::none_of(defs, [](const AttrOrTypeDef &def) { 787 return def.getMnemonic().hasValue(); 788 })) { 789 return; 790 } 791 // Declare the parser. 792 SmallVector<MethodParameter> params = {{"::mlir::AsmParser &", "parser"}, 793 {"::llvm::StringRef", "mnemonic"}}; 794 if (isAttrGenerator) 795 params.emplace_back("::mlir::Type", "type"); 796 params.emplace_back(strfmt("::mlir::{0} &", valueType), "value"); 797 Method parse("::mlir::OptionalParseResult", 798 strfmt("generated{0}Parser", valueType), Method::StaticInline, 799 std::move(params)); 800 // Declare the printer. 801 Method printer("::mlir::LogicalResult", 802 strfmt("generated{0}Printer", valueType), Method::StaticInline, 803 {{strfmt("::mlir::{0}", valueType), "def"}, 804 {"::mlir::AsmPrinter &", "printer"}}); 805 806 // The parser dispatch is just a list of if-elses, matching on the mnemonic 807 // and calling the def's parse function. 808 const char *const getValueForMnemonic = 809 R"( if (mnemonic == {0}::getMnemonic()) {{ 810 value = {0}::{1}; 811 return ::mlir::success(!!value); 812 } 813 )"; 814 // The printer dispatch uses llvm::TypeSwitch to find and call the correct 815 // printer. 816 printer.body() << " return ::llvm::TypeSwitch<::mlir::" << valueType 817 << ", ::mlir::LogicalResult>(def)"; 818 const char *const printValue = R"( .Case<{0}>([&](auto t) {{ 819 printer << {0}::getMnemonic();{1} 820 return ::mlir::success(); 821 }) 822 )"; 823 for (auto &def : defs) { 824 if (!def.getMnemonic()) 825 continue; 826 std::string defClass = strfmt( 827 "{0}::{1}", def.getDialect().getCppNamespace(), def.getCppClassName()); 828 // If the def has no parameters or parser code, invoke a normal `get`. 829 std::string parseOrGet = 830 def.needsParserPrinter() || def.hasGeneratedParser() 831 ? strfmt("parse(parser{0})", isAttrGenerator ? ", type" : "") 832 : "get(parser.getContext())"; 833 parse.body() << llvm::formatv(getValueForMnemonic, defClass, parseOrGet); 834 835 // If the def has no parameters and no printer, just print the mnemonic. 836 StringRef printDef = ""; 837 if (def.needsParserPrinter() || def.hasGeneratedPrinter()) 838 printDef = "\nt.print(printer);"; 839 printer.body() << llvm::formatv(printValue, defClass, printDef); 840 } 841 parse.body() << " return {};"; 842 printer.body() << " .Default([](auto) { return ::mlir::failure(); });"; 843 844 raw_indented_ostream indentedOs(os); 845 parse.writeDeclTo(indentedOs); 846 printer.writeDeclTo(indentedOs); 847 } 848 849 bool DefGenerator::emitDefs(StringRef selectedDialect) { 850 emitSourceFileHeader((defType + "Def Definitions").str(), os); 851 852 SmallVector<AttrOrTypeDef, 16> defs; 853 collectAllDefs(selectedDialect, defRecords, defs); 854 if (defs.empty()) 855 return false; 856 emitTypeDefList(defs); 857 858 IfDefScope scope("GET_" + defType.upper() + "DEF_CLASSES", os); 859 emitParsePrintDispatch(defs); 860 for (const AttrOrTypeDef &def : defs) { 861 { 862 NamespaceEmitter ns(os, def.getDialect()); 863 DefGen gen(def); 864 gen.emitDef(os); 865 } 866 // Emit the TypeID explicit specializations to have a single symbol def. 867 if (!def.getDialect().getCppNamespace().empty()) 868 os << "DEFINE_EXPLICIT_TYPE_ID(" << def.getDialect().getCppNamespace() 869 << "::" << def.getCppClassName() << ")\n"; 870 } 871 872 Dialect firstDialect = defs.front().getDialect(); 873 // Emit the default parser/printer for Attributes if the dialect asked for 874 // it. 875 if (valueType == "Attribute" && needsDialectParserPrinter && 876 firstDialect.useDefaultAttributePrinterParser()) { 877 NamespaceEmitter nsEmitter(os, firstDialect); 878 os << llvm::formatv(dialectDefaultAttrPrinterParserDispatch, 879 firstDialect.getCppClassName()); 880 } 881 882 // Emit the default parser/printer for Types if the dialect asked for it. 883 if (valueType == "Type" && needsDialectParserPrinter && 884 firstDialect.useDefaultTypePrinterParser()) { 885 NamespaceEmitter nsEmitter(os, firstDialect); 886 os << llvm::formatv(dialectDefaultTypePrinterParserDispatch, 887 firstDialect.getCppClassName()); 888 } 889 890 return false; 891 } 892 893 //===----------------------------------------------------------------------===// 894 // GEN: Registration hooks 895 //===----------------------------------------------------------------------===// 896 897 //===----------------------------------------------------------------------===// 898 // AttrDef 899 900 static llvm::cl::OptionCategory attrdefGenCat("Options for -gen-attrdef-*"); 901 static llvm::cl::opt<std::string> 902 attrDialect("attrdefs-dialect", 903 llvm::cl::desc("Generate attributes for this dialect"), 904 llvm::cl::cat(attrdefGenCat), llvm::cl::CommaSeparated); 905 906 static mlir::GenRegistration 907 genAttrDefs("gen-attrdef-defs", "Generate AttrDef definitions", 908 [](const llvm::RecordKeeper &records, raw_ostream &os) { 909 AttrDefGenerator generator(records, os); 910 return generator.emitDefs(attrDialect); 911 }); 912 static mlir::GenRegistration 913 genAttrDecls("gen-attrdef-decls", "Generate AttrDef declarations", 914 [](const llvm::RecordKeeper &records, raw_ostream &os) { 915 AttrDefGenerator generator(records, os); 916 return generator.emitDecls(attrDialect); 917 }); 918 919 //===----------------------------------------------------------------------===// 920 // TypeDef 921 922 static llvm::cl::OptionCategory typedefGenCat("Options for -gen-typedef-*"); 923 static llvm::cl::opt<std::string> 924 typeDialect("typedefs-dialect", 925 llvm::cl::desc("Generate types for this dialect"), 926 llvm::cl::cat(typedefGenCat), llvm::cl::CommaSeparated); 927 928 static mlir::GenRegistration 929 genTypeDefs("gen-typedef-defs", "Generate TypeDef definitions", 930 [](const llvm::RecordKeeper &records, raw_ostream &os) { 931 TypeDefGenerator generator(records, os); 932 return generator.emitDefs(typeDialect); 933 }); 934 static mlir::GenRegistration 935 genTypeDecls("gen-typedef-decls", "Generate TypeDef declarations", 936 [](const llvm::RecordKeeper &records, raw_ostream &os) { 937 TypeDefGenerator generator(records, os); 938 return generator.emitDecls(typeDialect); 939 }); 940