1320 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "AttrOrTypeFormatGen.h"10#include "CppGenUtilities.h"11#include "mlir/TableGen/AttrOrTypeDef.h"12#include "mlir/TableGen/Class.h"13#include "mlir/TableGen/Format.h"14#include "mlir/TableGen/GenInfo.h"15#include "mlir/TableGen/Interfaces.h"16#include "llvm/ADT/StringSet.h"17#include "llvm/Support/CommandLine.h"18#include "llvm/TableGen/CodeGenHelpers.h"19#include "llvm/TableGen/Error.h"20#include "llvm/TableGen/TableGenBackend.h"21 22#define DEBUG_TYPE "mlir-tblgen-attrortypedefgen"23 24using namespace mlir;25using namespace mlir::tblgen;26using llvm::Record;27using llvm::RecordKeeper;28 29//===----------------------------------------------------------------------===//30// Utility Functions31//===----------------------------------------------------------------------===//32 33/// Find all the AttrOrTypeDef for the specified dialect. If no dialect34/// specified and can only find one dialect's defs, use that.35static void collectAllDefs(StringRef selectedDialect,36 ArrayRef<const Record *> records,37 SmallVectorImpl<AttrOrTypeDef> &resultDefs) {38 // Nothing to do if no defs were found.39 if (records.empty())40 return;41 42 auto defs = llvm::map_range(43 records, [&](const Record *rec) { return AttrOrTypeDef(rec); });44 if (selectedDialect.empty()) {45 // If a dialect was not specified, ensure that all found defs belong to the46 // same dialect.47 if (!llvm::all_equal(llvm::map_range(48 defs, [](const auto &def) { return def.getDialect(); }))) {49 llvm::PrintFatalError("defs belonging to more than one dialect. Must "50 "select one via '--(attr|type)defs-dialect'");51 }52 resultDefs.assign(defs.begin(), defs.end());53 } else {54 // Otherwise, generate the defs that belong to the selected dialect.55 auto dialectDefs = llvm::make_filter_range(defs, [&](const auto &def) {56 return def.getDialect().getName() == selectedDialect;57 });58 resultDefs.assign(dialectDefs.begin(), dialectDefs.end());59 }60}61 62//===----------------------------------------------------------------------===//63// DefGen64//===----------------------------------------------------------------------===//65 66namespace {67class DefGen {68public:69 /// Create the attribute or type class.70 DefGen(const AttrOrTypeDef &def);71 72 void emitDecl(raw_ostream &os) const {73 if (storageCls && def.genStorageClass()) {74 llvm::NamespaceEmitter ns(os, def.getStorageNamespace());75 os << "struct " << def.getStorageClassName() << ";\n";76 }77 defCls.writeDeclTo(os);78 }79 void emitDef(raw_ostream &os) const {80 if (storageCls && def.genStorageClass()) {81 llvm::NamespaceEmitter ns(os, def.getStorageNamespace());82 storageCls->writeDeclTo(os); // everything is inline83 }84 defCls.writeDefTo(os);85 }86 87private:88 /// Add traits from the TableGen definition to the class.89 void createParentWithTraits();90 /// Emit top-level declarations: using declarations and any extra class91 /// declarations.92 void emitTopLevelDeclarations();93 /// Emit the function that returns the type or attribute name.94 void emitName();95 /// Emit the dialect name as a static member variable.96 void emitDialectName();97 /// Emit attribute or type builders.98 void emitBuilders();99 /// Emit a verifier declaration for custom verification (impl. provided by100 /// the users).101 void emitVerifierDecl();102 /// Emit a verifier that checks type constraints.103 void emitInvariantsVerifierImpl();104 /// Emit an entry poiunt for verification that calls the invariants and105 /// custom verifier.106 void emitInvariantsVerifier(bool hasImpl, bool hasCustomVerifier);107 /// Emit parsers and printers.108 void emitParserPrinter();109 /// Emit parameter accessors, if required.110 void emitAccessors();111 /// Emit interface methods.112 void emitInterfaceMethods();113 114 //===--------------------------------------------------------------------===//115 // Builder Emission116 117 /// Emit the default builder `Attribute::get`118 void emitDefaultBuilder();119 /// Emit the checked builder `Attribute::getChecked`120 void emitCheckedBuilder();121 /// Emit a custom builder.122 void emitCustomBuilder(const AttrOrTypeBuilder &builder);123 /// Emit a checked custom builder.124 void emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder);125 126 //===--------------------------------------------------------------------===//127 // Interface Method Emission128 129 /// Emit methods for a trait.130 void emitTraitMethods(const InterfaceTrait &trait);131 /// Emit a trait method.132 void emitTraitMethod(const InterfaceMethod &method);133 /// Generate a using declaration for a trait method.134 void genTraitMethodUsingDecl(const InterfaceTrait &trait,135 const InterfaceMethod &method);136 137 //===--------------------------------------------------------------------===//138 // OpAsm{Type,Attr}Interface Default Method Emission139 140 /// Emit 'getAlias' method using mnemonic as alias.141 void emitMnemonicAliasMethod();142 143 //===--------------------------------------------------------------------===//144 // Storage Class Emission145 void emitStorageClass();146 /// Generate the storage class constructor.147 void emitStorageConstructor();148 /// Emit the key type `KeyTy`.149 void emitKeyType();150 /// Emit the equality comparison operator.151 void emitEquals();152 /// Emit the key hash function.153 void emitHashKey();154 /// Emit the function to construct the storage class.155 void emitConstruct();156 157 //===--------------------------------------------------------------------===//158 // Utility Function Declarations159 160 /// Get the method parameters for a def builder, where the first several161 /// parameters may be different.162 SmallVector<MethodParameter>163 getBuilderParams(std::initializer_list<MethodParameter> prefix) const;164 165 //===--------------------------------------------------------------------===//166 // Class fields167 168 /// The attribute or type definition.169 const AttrOrTypeDef &def;170 /// The list of attribute or type parameters.171 ArrayRef<AttrOrTypeParameter> params;172 /// The attribute or type class.173 Class defCls;174 /// An optional attribute or type storage class. The storage class will175 /// exist if and only if the def has more than zero parameters.176 std::optional<Class> storageCls;177 178 /// The C++ base value of the def, either "Attribute" or "Type".179 StringRef valueType;180 /// The prefix/suffix of the TableGen def name, either "Attr" or "Type".181 StringRef defType;182 183 /// The set of using declarations for trait methods.184 llvm::StringSet<> interfaceUsingNames;185};186} // namespace187 188DefGen::DefGen(const AttrOrTypeDef &def)189 : def(def), params(def.getParameters()), defCls(def.getCppClassName()),190 valueType(isa<AttrDef>(def) ? "Attribute" : "Type"),191 defType(isa<AttrDef>(def) ? "Attr" : "Type") {192 // Check that all parameters have names.193 for (const AttrOrTypeParameter ¶m : def.getParameters())194 if (param.isAnonymous())195 llvm::PrintFatalError("all parameters must have a name");196 197 // If a storage class is needed, create one.198 if (def.getNumParameters() > 0)199 storageCls.emplace(def.getStorageClassName(), /*isStruct=*/true);200 201 // Create the parent class with any indicated traits.202 createParentWithTraits();203 // Emit top-level declarations.204 emitTopLevelDeclarations();205 // Emit builders for defs with parameters206 if (storageCls)207 emitBuilders();208 // Emit the type name.209 emitName();210 // Emit the dialect name.211 emitDialectName();212 // Emit verification of type constraints.213 bool genVerifyInvariantsImpl = def.genVerifyInvariantsImpl();214 if (storageCls && genVerifyInvariantsImpl)215 emitInvariantsVerifierImpl();216 // Emit the custom verifier (written by the user).217 bool genVerifyDecl = def.genVerifyDecl();218 if (storageCls && genVerifyDecl)219 emitVerifierDecl();220 // Emit the "verifyInvariants" function if there is any verification at all.221 if (storageCls)222 emitInvariantsVerifier(genVerifyInvariantsImpl, genVerifyDecl);223 // Emit the mnemonic, if there is one, and any associated parser and printer.224 if (def.getMnemonic())225 emitParserPrinter();226 // Emit accessors227 if (def.genAccessors())228 emitAccessors();229 // Emit trait interface methods230 emitInterfaceMethods();231 // Emit OpAsm{Type,Attr}Interface default methods232 if (def.genMnemonicAlias())233 emitMnemonicAliasMethod();234 defCls.finalize();235 // Emit a storage class if one is needed236 if (storageCls && def.genStorageClass())237 emitStorageClass();238}239 240void DefGen::createParentWithTraits() {241 ParentClass defParent(strfmt("::mlir::{0}::{1}Base", valueType, defType));242 defParent.addTemplateParam(def.getCppClassName());243 defParent.addTemplateParam(def.getCppBaseClassName());244 defParent.addTemplateParam(storageCls245 ? strfmt("{0}::{1}", def.getStorageNamespace(),246 def.getStorageClassName())247 : strfmt("::mlir::{0}Storage", valueType));248 SmallVector<std::string> traitNames =249 llvm::to_vector(llvm::map_range(def.getTraits(), [](auto &trait) {250 return isa<NativeTrait>(&trait)251 ? cast<NativeTrait>(&trait)->getFullyQualifiedTraitName()252 : cast<InterfaceTrait>(&trait)->getFullyQualifiedTraitName();253 }));254 for (auto &traitName : traitNames)255 defParent.addTemplateParam(traitName);256 257 // Add OpAsmInterface::Trait if we automatically generate mnemonic alias258 // method.259 std::string opAsmInterfaceTraitName =260 strfmt("::mlir::OpAsm{0}Interface::Trait", defType);261 if (def.genMnemonicAlias() &&262 !llvm::is_contained(traitNames, opAsmInterfaceTraitName)) {263 defParent.addTemplateParam(opAsmInterfaceTraitName);264 }265 defCls.addParent(std::move(defParent));266}267 268/// Include declarations specified on NativeTrait269static std::string formatExtraDeclarations(const AttrOrTypeDef &def) {270 SmallVector<StringRef> extraDeclarations;271 // Include extra class declarations from NativeTrait272 for (const auto &trait : def.getTraits()) {273 if (auto *attrOrTypeTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {274 StringRef value = attrOrTypeTrait->getExtraConcreteClassDeclaration();275 if (value.empty())276 continue;277 extraDeclarations.push_back(value);278 }279 }280 if (std::optional<StringRef> extraDecl = def.getExtraDecls()) {281 extraDeclarations.push_back(*extraDecl);282 }283 return llvm::join(extraDeclarations, "\n");284}285 286/// Extra class definitions have a `$cppClass` substitution that is to be287/// replaced by the C++ class name.288static std::string formatExtraDefinitions(const AttrOrTypeDef &def) {289 SmallVector<StringRef> extraDefinitions;290 // Include extra class definitions from NativeTrait291 for (const auto &trait : def.getTraits()) {292 if (auto *attrOrTypeTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {293 StringRef value = attrOrTypeTrait->getExtraConcreteClassDefinition();294 if (value.empty())295 continue;296 extraDefinitions.push_back(value);297 }298 }299 if (std::optional<StringRef> extraDef = def.getExtraDefs()) {300 extraDefinitions.push_back(*extraDef);301 }302 FmtContext ctx = FmtContext().addSubst("cppClass", def.getCppClassName());303 return tgfmt(llvm::join(extraDefinitions, "\n"), &ctx).str();304}305 306void DefGen::emitTopLevelDeclarations() {307 // Inherit constructors from the attribute or type class.308 defCls.declare<VisibilityDeclaration>(Visibility::Public);309 defCls.declare<UsingDeclaration>("Base::Base");310 311 // Emit the extra declarations first in case there's a definition in there.312 std::string extraDecl = formatExtraDeclarations(def);313 std::string extraDef = formatExtraDefinitions(def);314 defCls.declare<ExtraClassDeclaration>(std::move(extraDecl),315 std::move(extraDef));316}317 318void DefGen::emitName() {319 StringRef name;320 if (auto *attrDef = dyn_cast<AttrDef>(&def)) {321 name = attrDef->getAttrName();322 } else {323 auto *typeDef = cast<TypeDef>(&def);324 name = typeDef->getTypeName();325 }326 std::string nameDecl =327 strfmt("static constexpr ::llvm::StringLiteral name = \"{0}\";\n", name);328 defCls.declare<ExtraClassDeclaration>(std::move(nameDecl));329}330 331void DefGen::emitDialectName() {332 std::string decl =333 strfmt("static constexpr ::llvm::StringLiteral dialectName = \"{0}\";\n",334 def.getDialect().getName());335 defCls.declare<ExtraClassDeclaration>(std::move(decl));336}337 338void DefGen::emitBuilders() {339 if (!def.skipDefaultBuilders()) {340 emitDefaultBuilder();341 if (def.genVerifyDecl() || def.genVerifyInvariantsImpl())342 emitCheckedBuilder();343 }344 for (auto &builder : def.getBuilders()) {345 emitCustomBuilder(builder);346 if (def.genVerifyDecl() || def.genVerifyInvariantsImpl())347 emitCheckedCustomBuilder(builder);348 }349}350 351void DefGen::emitVerifierDecl() {352 defCls.declareStaticMethod(353 "::llvm::LogicalResult", "verify",354 getBuilderParams({{"::llvm::function_ref<::mlir::InFlightDiagnostic()>",355 "emitError"}}));356}357 358static const char *const patternParameterVerificationCode = R"(359if (!({0})) {360 emitError() << "failed to verify '{1}': {2}";361 return ::mlir::failure();362}363)";364 365void DefGen::emitInvariantsVerifierImpl() {366 SmallVector<MethodParameter> builderParams = getBuilderParams(367 {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}});368 Method *verifier =369 defCls.addMethod("::llvm::LogicalResult", "verifyInvariantsImpl",370 Method::Static, builderParams);371 verifier->body().indent();372 373 // Generate verification for each parameter that is a type constraint.374 for (auto it : llvm::enumerate(def.getParameters())) {375 const AttrOrTypeParameter ¶m = it.value();376 std::optional<Constraint> constraint = param.getConstraint();377 // No verification needed for parameters that are not type constraints.378 if (!constraint.has_value())379 continue;380 FmtContext ctx;381 // Note: Skip over the first method parameter (`emitError`).382 ctx.withSelf(builderParams[it.index() + 1].getName());383 std::string condition = tgfmt(constraint->getConditionTemplate(), &ctx);384 verifier->body() << formatv(patternParameterVerificationCode, condition,385 param.getName(), constraint->getSummary())386 << "\n";387 }388 verifier->body() << "return ::mlir::success();";389}390 391void DefGen::emitInvariantsVerifier(bool hasImpl, bool hasCustomVerifier) {392 if (!hasImpl && !hasCustomVerifier)393 return;394 defCls.declare<UsingDeclaration>("Base::getChecked");395 SmallVector<MethodParameter> builderParams = getBuilderParams(396 {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}});397 Method *verifier =398 defCls.addMethod("::llvm::LogicalResult", "verifyInvariants",399 Method::Static, builderParams);400 verifier->body().indent();401 402 auto emitVerifierCall = [&](StringRef name) {403 verifier->body() << strfmt("if (::mlir::failed({0}(", name);404 llvm::interleaveComma(405 llvm::map_range(builderParams,406 [](auto ¶m) { return param.getName(); }),407 verifier->body());408 verifier->body() << ")))\n";409 verifier->body() << " return ::mlir::failure();\n";410 };411 412 if (hasImpl) {413 // Call the verifier that checks the type constraints.414 emitVerifierCall("verifyInvariantsImpl");415 }416 if (hasCustomVerifier) {417 // Call the custom verifier that is provided by the user.418 emitVerifierCall("verify");419 }420 verifier->body() << "return ::mlir::success();";421}422 423void DefGen::emitParserPrinter() {424 auto *mnemonic = defCls.addStaticMethod<Method::Constexpr>(425 "::llvm::StringLiteral", "getMnemonic");426 mnemonic->body().indent() << strfmt("return {\"{0}\"};", *def.getMnemonic());427 428 // Declare the parser and printer, if needed.429 bool hasAssemblyFormat = def.getAssemblyFormat().has_value();430 if (!def.hasCustomAssemblyFormat() && !hasAssemblyFormat)431 return;432 433 // Declare the parser.434 SmallVector<MethodParameter> parserParams;435 parserParams.emplace_back("::mlir::AsmParser &", "odsParser");436 if (isa<AttrDef>(&def))437 parserParams.emplace_back("::mlir::Type", "odsType");438 auto *parser = defCls.addMethod(strfmt("::mlir::{0}", valueType), "parse",439 hasAssemblyFormat ? Method::Static440 : Method::StaticDeclaration,441 std::move(parserParams));442 // Declare the printer.443 auto props = hasAssemblyFormat ? Method::Const : Method::ConstDeclaration;444 Method *printer =445 defCls.addMethod("void", "print", props,446 MethodParameter("::mlir::AsmPrinter &", "odsPrinter"));447 // Emit the bodies if we are using the declarative format.448 if (hasAssemblyFormat)449 return generateAttrOrTypeFormat(def, parser->body(), printer->body());450}451 452void DefGen::emitAccessors() {453 for (auto ¶m : params) {454 Method *m = defCls.addMethod(455 param.getCppAccessorType(), param.getAccessorName(),456 def.genStorageClass() ? Method::Const : Method::ConstDeclaration);457 // Generate accessor definitions only if we also generate the storage458 // class. Otherwise, let the user define the exact accessor definition.459 if (!def.genStorageClass())460 continue;461 m->body().indent() << "return getImpl()->" << param.getName() << ";";462 }463}464 465void DefGen::emitInterfaceMethods() {466 for (auto &traitDef : def.getTraits())467 if (auto *trait = dyn_cast<InterfaceTrait>(&traitDef))468 if (trait->shouldDeclareMethods())469 emitTraitMethods(*trait);470}471 472//===----------------------------------------------------------------------===//473// Builder Emission474//===----------------------------------------------------------------------===//475 476SmallVector<MethodParameter>477DefGen::getBuilderParams(std::initializer_list<MethodParameter> prefix) const {478 SmallVector<MethodParameter> builderParams;479 builderParams.append(prefix.begin(), prefix.end());480 for (auto ¶m : params)481 builderParams.emplace_back(param.getCppType(), param.getName());482 return builderParams;483}484 485void DefGen::emitDefaultBuilder() {486 Method *m = defCls.addStaticMethod(487 def.getCppClassName(), "get",488 getBuilderParams({{"::mlir::MLIRContext *", "context"}}));489 MethodBody &body = m->body().indent();490 auto scope = body.scope("return Base::get(context", ");");491 for (const auto ¶m : params)492 body << ", std::move(" << param.getName() << ")";493}494 495void DefGen::emitCheckedBuilder() {496 Method *m = defCls.addStaticMethod(497 def.getCppClassName(), "getChecked",498 getBuilderParams(499 {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"},500 {"::mlir::MLIRContext *", "context"}}));501 MethodBody &body = m->body().indent();502 auto scope = body.scope("return Base::getChecked(emitError, context", ");");503 for (const auto ¶m : params)504 body << ", std::move(" << param.getName() << ")";505}506 507static SmallVector<MethodParameter>508getCustomBuilderParams(std::initializer_list<MethodParameter> prefix,509 const AttrOrTypeBuilder &builder) {510 auto params = builder.getParameters();511 SmallVector<MethodParameter> builderParams;512 builderParams.append(prefix.begin(), prefix.end());513 if (!builder.hasInferredContextParameter())514 builderParams.emplace_back("::mlir::MLIRContext *", "context");515 for (auto ¶m : params) {516 builderParams.emplace_back(param.getCppType(), *param.getName(),517 param.getDefaultValue());518 }519 return builderParams;520}521 522static std::string getSignature(const Method &m) {523 std::string signature;524 llvm::raw_string_ostream os(signature);525 raw_indented_ostream indentedOs(os);526 m.writeDeclTo(indentedOs);527 return signature;528}529 530static void emitDuplicatedBuilderError(const Method ¤tMethod,531 StringRef methodName,532 const Class &defCls,533 const AttrOrTypeDef &def) {534 535 // Try to search for method that makes `get` redundant.536 auto loc = def.getDef()->getFieldLoc("builders");537 for (auto &method : defCls.getMethods()) {538 if (method->getName() == methodName &&539 method->makesRedundant(currentMethod)) {540 PrintError(loc, llvm::Twine("builder `") + methodName +541 "` conflicts with an existing builder. ");542 PrintFatalNote(llvm::Twine("A new builder with signature:\n") +543 getSignature(currentMethod) +544 "\nis shadowed by an existing builder with signature:\n" +545 getSignature(*method) +546 "\nPlease remove one of the conflicting "547 "definitions.");548 }549 }550 551 // This code shouldn't be reached, but leaving this here for potential future552 // use.553 PrintFatalError(loc, "Failed to generate builder " + methodName);554}555 556void DefGen::emitCustomBuilder(const AttrOrTypeBuilder &builder) {557 // Don't emit a body if there isn't one.558 auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration;559 StringRef returnType = def.getCppClassName();560 if (std::optional<StringRef> builderReturnType = builder.getReturnType())561 returnType = *builderReturnType;562 563 llvm::StringRef methodName = "get";564 const auto parameters = getCustomBuilderParams({}, builder);565 Method *m = defCls.addMethod(returnType, methodName, props, parameters);566 567 // If method is pruned, report error and terminate.568 if (!m) {569 auto curMethod = Method(returnType, methodName, props, parameters);570 emitDuplicatedBuilderError(curMethod, methodName, defCls, def);571 }572 573 if (!builder.getBody())574 return;575 576 // Format the body and emit it.577 FmtContext ctx;578 ctx.addSubst("_get", "Base::get");579 if (!builder.hasInferredContextParameter())580 ctx.addSubst("_ctxt", "context");581 std::string bodyStr = tgfmt(*builder.getBody(), &ctx);582 m->body().indent().getStream().printReindented(bodyStr);583}584 585/// Replace all instances of 'from' to 'to' in `str` and return the new string.586static std::string replaceInStr(std::string str, StringRef from, StringRef to) {587 size_t pos = 0;588 while ((pos = str.find(from.data(), pos, from.size())) != std::string::npos)589 str.replace(pos, from.size(), to.data(), to.size());590 return str;591}592 593void DefGen::emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder) {594 // Don't emit a body if there isn't one.595 auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration;596 StringRef returnType = def.getCppClassName();597 if (std::optional<StringRef> builderReturnType = builder.getReturnType())598 returnType = *builderReturnType;599 600 llvm::StringRef methodName = "getChecked";601 auto parameters = getCustomBuilderParams(602 {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}},603 builder);604 Method *m = defCls.addMethod(returnType, methodName, props, parameters);605 606 // If method is pruned, report error and terminate.607 if (!m) {608 auto curMethod = Method(returnType, methodName, props, parameters);609 emitDuplicatedBuilderError(curMethod, methodName, defCls, def);610 }611 612 if (!builder.getBody())613 return;614 615 // Format the body and emit it. Replace $_get(...) with616 // Base::getChecked(emitError, ...)617 FmtContext ctx;618 if (!builder.hasInferredContextParameter())619 ctx.addSubst("_ctxt", "context");620 std::string bodyStr = replaceInStr(builder.getBody()->str(), "$_get(",621 "Base::getChecked(emitError, ");622 bodyStr = tgfmt(bodyStr, &ctx);623 m->body().indent().getStream().printReindented(bodyStr);624}625 626//===----------------------------------------------------------------------===//627// Interface Method Emission628//===----------------------------------------------------------------------===//629 630void DefGen::emitTraitMethods(const InterfaceTrait &trait) {631 // Get the set of methods that should always be declared.632 auto alwaysDeclaredMethods = trait.getAlwaysDeclaredMethods();633 StringSet<> alwaysDeclared;634 alwaysDeclared.insert_range(alwaysDeclaredMethods);635 636 Interface iface = trait.getInterface(); // causes strange bugs if elided637 for (auto &method : iface.getMethods()) {638 // Don't declare if the method has a body. Or if the method has a default639 // implementation and the def didn't request that it always be declared.640 if (method.getBody())641 continue;642 if (method.getDefaultImplementation() &&643 !alwaysDeclared.count(method.getName())) {644 genTraitMethodUsingDecl(trait, method);645 continue;646 }647 emitTraitMethod(method);648 }649}650 651void DefGen::emitTraitMethod(const InterfaceMethod &method) {652 // All interface methods are declaration-only.653 auto props =654 method.isStatic() ? Method::StaticDeclaration : Method::ConstDeclaration;655 SmallVector<MethodParameter> params;656 for (auto ¶m : method.getArguments())657 params.emplace_back(param.type, param.name);658 defCls.addMethod(method.getReturnType(), method.getName(), props,659 std::move(params));660}661 662void DefGen::genTraitMethodUsingDecl(const InterfaceTrait &trait,663 const InterfaceMethod &method) {664 std::string name = (llvm::Twine(trait.getFullyQualifiedTraitName()) + "<" +665 def.getCppClassName() + ">::" + method.getName())666 .str();667 if (interfaceUsingNames.insert(name).second)668 defCls.declare<UsingDeclaration>(std::move(name));669}670 671//===----------------------------------------------------------------------===//672// OpAsm{Type,Attr}Interface Default Method Emission673 674void DefGen::emitMnemonicAliasMethod() {675 // If the mnemonic is not set, there is nothing to do.676 if (!def.getMnemonic())677 return;678 679 // Emit the mnemonic alias method.680 SmallVector<MethodParameter> params{{"::llvm::raw_ostream &", "os"}};681 Method *m = defCls.addMethod<Method::Const>("::mlir::OpAsmAliasResult",682 "getAlias", std::move(params));683 m->body().indent() << strfmt("os << \"{0}\";\n", *def.getMnemonic())684 << "return ::mlir::OpAsmAliasResult::OverridableAlias;\n";685}686 687//===----------------------------------------------------------------------===//688// Storage Class Emission689//===----------------------------------------------------------------------===//690 691void DefGen::emitStorageConstructor() {692 Constructor *ctor =693 storageCls->addConstructor<Method::Inline>(getBuilderParams({}));694 for (auto ¶m : params) {695 std::string movedValue = ("std::move(" + param.getName() + ")").str();696 ctor->addMemberInitializer(param.getName(), movedValue);697 }698}699 700void DefGen::emitKeyType() {701 std::string keyType("std::tuple<");702 llvm::raw_string_ostream os(keyType);703 llvm::interleaveComma(params, os,704 [&](auto ¶m) { os << param.getCppType(); });705 os << '>';706 storageCls->declare<UsingDeclaration>("KeyTy", std::move(os.str()));707 708 // Add a method to construct the key type from the storage.709 Method *m = storageCls->addConstMethod<Method::Inline>("KeyTy", "getAsKey");710 m->body().indent() << "return KeyTy(";711 llvm::interleaveComma(params, m->body().indent(),712 [&](auto ¶m) { m->body() << param.getName(); });713 m->body() << ");";714}715 716void DefGen::emitEquals() {717 Method *eq = storageCls->addConstMethod<Method::Inline>(718 "bool", "operator==", MethodParameter("const KeyTy &", "tblgenKey"));719 auto &body = eq->body().indent();720 auto scope = body.scope("return (", ");");721 const auto eachFn = [&](auto it) {722 FmtContext ctx({{"_lhs", it.value().getName()},723 {"_rhs", strfmt("std::get<{0}>(tblgenKey)", it.index())}});724 body << tgfmt(it.value().getComparator(), &ctx);725 };726 llvm::interleave(llvm::enumerate(params), body, eachFn, ") && (");727}728 729void DefGen::emitHashKey() {730 Method *hash = storageCls->addStaticInlineMethod(731 "::llvm::hash_code", "hashKey",732 MethodParameter("const KeyTy &", "tblgenKey"));733 auto &body = hash->body().indent();734 auto scope = body.scope("return ::llvm::hash_combine(", ");");735 llvm::interleaveComma(llvm::enumerate(params), body, [&](auto it) {736 body << llvm::formatv("std::get<{0}>(tblgenKey)", it.index());737 });738}739 740void DefGen::emitConstruct() {741 Method *construct = storageCls->addMethod(742 strfmt("{0} *", def.getStorageClassName()), "construct",743 def.hasStorageCustomConstructor() ? Method::StaticDeclaration744 : Method::StaticInline,745 MethodParameter(strfmt("::mlir::{0}StorageAllocator &", valueType),746 "allocator"),747 MethodParameter("KeyTy &&", "tblgenKey"));748 if (!def.hasStorageCustomConstructor()) {749 auto &body = construct->body().indent();750 for (const auto &it : llvm::enumerate(params)) {751 body << formatv("auto {0} = std::move(std::get<{1}>(tblgenKey));\n",752 it.value().getName(), it.index());753 }754 // Use the parameters' custom allocator code, if provided.755 FmtContext ctx = FmtContext().addSubst("_allocator", "allocator");756 for (auto ¶m : params) {757 if (std::optional<StringRef> allocCode = param.getAllocator()) {758 ctx.withSelf(param.getName()).addSubst("_dst", param.getName());759 body << tgfmt(*allocCode, &ctx) << '\n';760 }761 }762 auto scope =763 body.scope(strfmt("return new (allocator.allocate<{0}>()) {0}(",764 def.getStorageClassName()),765 ");");766 llvm::interleaveComma(params, body, [&](auto ¶m) {767 body << "std::move(" << param.getName() << ")";768 });769 }770}771 772void DefGen::emitStorageClass() {773 // Add the appropriate parent class.774 storageCls->addParent(strfmt("::mlir::{0}Storage", valueType));775 // Add the constructor.776 emitStorageConstructor();777 // Declare the key type.778 emitKeyType();779 // Add the comparison method.780 emitEquals();781 // Emit the key hash method.782 emitHashKey();783 // Emit the storage constructor. Just declare it if the user wants to define784 // it themself.785 emitConstruct();786 // Emit the storage class members as public, at the very end of the struct.787 storageCls->finalize();788 for (auto ¶m : params) {789 if (param.getCppType().contains("APInt") && !param.hasCustomComparator()) {790 PrintFatalError(791 def.getLoc(),792 "Using a raw APInt parameter without a custom comparator is "793 "not supported because an assert in the equality operator is "794 "triggered when the two APInts have different bit widths. This can "795 "lead to unexpected crashes. Use an `APIntParameter` or "796 "provide a custom comparator.");797 }798 storageCls->declare<Field>(param.getCppType(), param.getName());799 }800}801 802//===----------------------------------------------------------------------===//803// DefGenerator804//===----------------------------------------------------------------------===//805 806namespace {807/// This struct is the base generator used when processing tablegen interfaces.808class DefGenerator {809public:810 bool emitDecls(StringRef selectedDialect);811 bool emitDefs(StringRef selectedDialect);812 813protected:814 DefGenerator(ArrayRef<const Record *> defs, raw_ostream &os,815 StringRef defType, StringRef valueType, bool isAttrGenerator)816 : defRecords(defs), os(os), defType(defType), valueType(valueType),817 isAttrGenerator(isAttrGenerator) {818 // Sort by occurrence in file.819 llvm::sort(defRecords, [](const Record *lhs, const Record *rhs) {820 return lhs->getID() < rhs->getID();821 });822 }823 824 /// Emit the list of def type names.825 void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs);826 /// Emit the code to dispatch between different defs during parsing/printing.827 void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs);828 829 /// The set of def records to emit.830 std::vector<const Record *> defRecords;831 /// The attribute or type class to emit.832 /// The stream to emit to.833 raw_ostream &os;834 /// The prefix of the tablegen def name, e.g. Attr or Type.835 StringRef defType;836 /// The C++ base value type of the def, e.g. Attribute or Type.837 StringRef valueType;838 /// Flag indicating if this generator is for Attributes. False if the839 /// generator is for types.840 bool isAttrGenerator;841};842 843/// A specialized generator for AttrDefs.844struct AttrDefGenerator : public DefGenerator {845 AttrDefGenerator(const RecordKeeper &records, raw_ostream &os)846 : DefGenerator(records.getAllDerivedDefinitionsIfDefined("AttrDef"), os,847 "Attr", "Attribute", /*isAttrGenerator=*/true) {}848};849/// A specialized generator for TypeDefs.850struct TypeDefGenerator : public DefGenerator {851 TypeDefGenerator(const RecordKeeper &records, raw_ostream &os)852 : DefGenerator(records.getAllDerivedDefinitionsIfDefined("TypeDef"), os,853 "Type", "Type", /*isAttrGenerator=*/false) {}854};855} // namespace856 857//===----------------------------------------------------------------------===//858// GEN: Declarations859//===----------------------------------------------------------------------===//860 861/// Print this above all the other declarations. Contains type declarations used862/// later on.863static const char *const typeDefDeclHeader = R"(864namespace mlir {865class AsmParser;866class AsmPrinter;867} // namespace mlir868)";869 870bool DefGenerator::emitDecls(StringRef selectedDialect) {871 emitSourceFileHeader((defType + "Def Declarations").str(), os);872 llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "DEF_CLASSES");873 874 // Output the common "header".875 os << typeDefDeclHeader;876 877 SmallVector<AttrOrTypeDef, 16> defs;878 collectAllDefs(selectedDialect, defRecords, defs);879 if (defs.empty())880 return false;881 {882 DialectNamespaceEmitter nsEmitter(os, defs.front().getDialect());883 884 // Declare all the def classes first (in case they reference each other).885 for (const AttrOrTypeDef &def : defs) {886 tblgen::emitSummaryAndDescComments(os, def.getSummary(),887 def.getDescription());888 os << "class " << def.getCppClassName() << ";\n";889 }890 891 // Emit the declarations.892 for (const AttrOrTypeDef &def : defs)893 DefGen(def).emitDecl(os);894 }895 // Emit the TypeID explicit specializations to have a single definition for896 // each of these.897 for (const AttrOrTypeDef &def : defs)898 if (!def.getDialect().getCppNamespace().empty())899 os << "MLIR_DECLARE_EXPLICIT_TYPE_ID("900 << def.getDialect().getCppNamespace() << "::" << def.getCppClassName()901 << ")\n";902 903 return false;904}905 906//===----------------------------------------------------------------------===//907// GEN: Def List908//===----------------------------------------------------------------------===//909 910void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) {911 llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "DEF_LIST");912 auto interleaveFn = [&](const AttrOrTypeDef &def) {913 os << def.getDialect().getCppNamespace() << "::" << def.getCppClassName();914 };915 llvm::interleave(defs, os, interleaveFn, ",\n");916 os << "\n";917}918 919//===----------------------------------------------------------------------===//920// GEN: Definitions921//===----------------------------------------------------------------------===//922 923/// The code block for default attribute parser/printer dispatch boilerplate.924/// {0}: the dialect fully qualified class name.925/// {1}: the optional code for the dynamic attribute parser dispatch.926/// {2}: the optional code for the dynamic attribute printer dispatch.927static const char *const dialectDefaultAttrPrinterParserDispatch = R"(928/// Parse an attribute registered to this dialect.929::mlir::Attribute {0}::parseAttribute(::mlir::DialectAsmParser &parser,930 ::mlir::Type type) const {{931 ::llvm::SMLoc typeLoc = parser.getCurrentLocation();932 ::llvm::StringRef attrTag;933 {{934 ::mlir::Attribute attr;935 auto parseResult = generatedAttributeParser(parser, &attrTag, type, attr);936 if (parseResult.has_value())937 return attr;938 }939 {1}940 parser.emitError(typeLoc) << "unknown attribute `"941 << attrTag << "` in dialect `" << getNamespace() << "`";942 return {{};943}944/// Print an attribute registered to this dialect.945void {0}::printAttribute(::mlir::Attribute attr,946 ::mlir::DialectAsmPrinter &printer) const {{947 if (::mlir::succeeded(generatedAttributePrinter(attr, printer)))948 return;949 {2}950}951)";952 953/// The code block for dynamic attribute parser dispatch boilerplate.954static const char *const dialectDynamicAttrParserDispatch = R"(955 {956 ::mlir::Attribute genAttr;957 auto parseResult = parseOptionalDynamicAttr(attrTag, parser, genAttr);958 if (parseResult.has_value()) {959 if (::mlir::succeeded(parseResult.value()))960 return genAttr;961 return Attribute();962 }963 }964)";965 966/// The code block for dynamic type printer dispatch boilerplate.967static const char *const dialectDynamicAttrPrinterDispatch = R"(968 if (::mlir::succeeded(printIfDynamicAttr(attr, printer)))969 return;970)";971 972/// The code block for default type parser/printer dispatch boilerplate.973/// {0}: the dialect fully qualified class name.974/// {1}: the optional code for the dynamic type parser dispatch.975/// {2}: the optional code for the dynamic type printer dispatch.976static const char *const dialectDefaultTypePrinterParserDispatch = R"(977/// Parse a type registered to this dialect.978::mlir::Type {0}::parseType(::mlir::DialectAsmParser &parser) const {{979 ::llvm::SMLoc typeLoc = parser.getCurrentLocation();980 ::llvm::StringRef mnemonic;981 ::mlir::Type genType;982 auto parseResult = generatedTypeParser(parser, &mnemonic, genType);983 if (parseResult.has_value())984 return genType;985 {1}986 parser.emitError(typeLoc) << "unknown type `"987 << mnemonic << "` in dialect `" << getNamespace() << "`";988 return {{};989}990/// Print a type registered to this dialect.991void {0}::printType(::mlir::Type type,992 ::mlir::DialectAsmPrinter &printer) const {{993 if (::mlir::succeeded(generatedTypePrinter(type, printer)))994 return;995 {2}996}997)";998 999/// The code block for dynamic type parser dispatch boilerplate.1000static const char *const dialectDynamicTypeParserDispatch = R"(1001 {1002 auto parseResult = parseOptionalDynamicType(mnemonic, parser, genType);1003 if (parseResult.has_value()) {1004 if (::mlir::succeeded(parseResult.value()))1005 return genType;1006 return ::mlir::Type();1007 }1008 }1009)";1010 1011/// The code block for dynamic type printer dispatch boilerplate.1012static const char *const dialectDynamicTypePrinterDispatch = R"(1013 if (::mlir::succeeded(printIfDynamicType(type, printer)))1014 return;1015)";1016 1017/// Emit the dialect printer/parser dispatcher. User's code should call these1018/// functions from their dialect's print/parse methods.1019void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) {1020 if (llvm::none_of(defs, [](const AttrOrTypeDef &def) {1021 return def.getMnemonic().has_value();1022 })) {1023 return;1024 }1025 // Declare the parser.1026 SmallVector<MethodParameter> params = {{"::mlir::AsmParser &", "parser"},1027 {"::llvm::StringRef *", "mnemonic"}};1028 if (isAttrGenerator)1029 params.emplace_back("::mlir::Type", "type");1030 params.emplace_back(strfmt("::mlir::{0} &", valueType), "value");1031 Method parse("::mlir::OptionalParseResult",1032 strfmt("generated{0}Parser", valueType), Method::StaticInline,1033 std::move(params));1034 // Declare the printer.1035 Method printer("::llvm::LogicalResult",1036 strfmt("generated{0}Printer", valueType), Method::StaticInline,1037 {{strfmt("::mlir::{0}", valueType), "def"},1038 {"::mlir::AsmPrinter &", "printer"}});1039 1040 // The parser dispatch uses a KeywordSwitch, matching on the mnemonic and1041 // calling the def's parse function.1042 parse.body() << " return "1043 "::mlir::AsmParser::KeywordSwitch<::mlir::"1044 "OptionalParseResult>(parser)\n";1045 const char *const getValueForMnemonic =1046 R"( .Case({0}::getMnemonic(), [&](llvm::StringRef, llvm::SMLoc) {{1047 value = {0}::{1};1048 return ::mlir::success(!!value);1049 })1050)";1051 1052 // The printer dispatch uses llvm::TypeSwitch to find and call the correct1053 // printer.1054 printer.body() << " return ::llvm::TypeSwitch<::mlir::" << valueType1055 << ", ::llvm::LogicalResult>(def)";1056 const char *const printValue = R"( .Case<{0}>([&](auto t) {{1057 printer << {0}::getMnemonic();{1}1058 return ::mlir::success();1059 })1060)";1061 for (auto &def : defs) {1062 if (!def.getMnemonic())1063 continue;1064 bool hasParserPrinterDecl =1065 def.hasCustomAssemblyFormat() || def.getAssemblyFormat();1066 std::string defClass = strfmt(1067 "{0}::{1}", def.getDialect().getCppNamespace(), def.getCppClassName());1068 1069 // If the def has no parameters or parser code, invoke a normal `get`.1070 std::string parseOrGet =1071 hasParserPrinterDecl1072 ? strfmt("parse(parser{0})", isAttrGenerator ? ", type" : "")1073 : "get(parser.getContext())";1074 parse.body() << llvm::formatv(getValueForMnemonic, defClass, parseOrGet);1075 1076 // If the def has no parameters and no printer, just print the mnemonic.1077 StringRef printDef = "";1078 if (hasParserPrinterDecl)1079 printDef = "\nt.print(printer);";1080 printer.body() << llvm::formatv(printValue, defClass, printDef);1081 }1082 parse.body() << " .Default([&](llvm::StringRef keyword, llvm::SMLoc) {\n"1083 " *mnemonic = keyword;\n"1084 " return std::nullopt;\n"1085 " });";1086 printer.body() << " .Default([](auto) { return ::mlir::failure(); });";1087 1088 raw_indented_ostream indentedOs(os);1089 parse.writeDeclTo(indentedOs);1090 printer.writeDeclTo(indentedOs);1091}1092 1093bool DefGenerator::emitDefs(StringRef selectedDialect) {1094 emitSourceFileHeader((defType + "Def Definitions").str(), os);1095 1096 SmallVector<AttrOrTypeDef, 16> defs;1097 collectAllDefs(selectedDialect, defRecords, defs);1098 if (defs.empty())1099 return false;1100 emitTypeDefList(defs);1101 1102 llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "DEF_CLASSES");1103 emitParsePrintDispatch(defs);1104 for (const AttrOrTypeDef &def : defs) {1105 {1106 DialectNamespaceEmitter ns(os, def.getDialect());1107 DefGen gen(def);1108 gen.emitDef(os);1109 }1110 // Emit the TypeID explicit specializations to have a single symbol def.1111 if (!def.getDialect().getCppNamespace().empty())1112 os << "MLIR_DEFINE_EXPLICIT_TYPE_ID("1113 << def.getDialect().getCppNamespace() << "::" << def.getCppClassName()1114 << ")\n";1115 }1116 1117 Dialect firstDialect = defs.front().getDialect();1118 1119 // Emit the default parser/printer for Attributes if the dialect asked for it.1120 if (isAttrGenerator && firstDialect.useDefaultAttributePrinterParser()) {1121 DialectNamespaceEmitter nsEmitter(os, firstDialect);1122 if (firstDialect.isExtensible()) {1123 os << llvm::formatv(dialectDefaultAttrPrinterParserDispatch,1124 firstDialect.getCppClassName(),1125 dialectDynamicAttrParserDispatch,1126 dialectDynamicAttrPrinterDispatch);1127 } else {1128 os << llvm::formatv(dialectDefaultAttrPrinterParserDispatch,1129 firstDialect.getCppClassName(), "", "");1130 }1131 }1132 1133 // Emit the default parser/printer for Types if the dialect asked for it.1134 if (!isAttrGenerator && firstDialect.useDefaultTypePrinterParser()) {1135 DialectNamespaceEmitter nsEmitter(os, firstDialect);1136 if (firstDialect.isExtensible()) {1137 os << llvm::formatv(dialectDefaultTypePrinterParserDispatch,1138 firstDialect.getCppClassName(),1139 dialectDynamicTypeParserDispatch,1140 dialectDynamicTypePrinterDispatch);1141 } else {1142 os << llvm::formatv(dialectDefaultTypePrinterParserDispatch,1143 firstDialect.getCppClassName(), "", "");1144 }1145 }1146 1147 return false;1148}1149 1150//===----------------------------------------------------------------------===//1151// Constraints1152//===----------------------------------------------------------------------===//1153 1154/// Find all type constraints for which a C++ function should be generated.1155static std::vector<Constraint> getAllCppConstraints(const RecordKeeper &records,1156 StringRef constraintKind) {1157 std::vector<Constraint> result;1158 for (const Record *def :1159 records.getAllDerivedDefinitionsIfDefined(constraintKind)) {1160 // Ignore constraints defined outside of the top-level file.1161 if (llvm::SrcMgr.FindBufferContainingLoc(def->getLoc()[0]) !=1162 llvm::SrcMgr.getMainFileID())1163 continue;1164 Constraint constr(def);1165 // Generate C++ function only if "cppFunctionName" is set.1166 if (!constr.getCppFunctionName())1167 continue;1168 result.push_back(constr);1169 }1170 return result;1171}1172 1173static std::vector<Constraint>1174getAllCppTypeConstraints(const RecordKeeper &records) {1175 return getAllCppConstraints(records, "TypeConstraint");1176}1177 1178static std::vector<Constraint>1179getAllCppAttrConstraints(const RecordKeeper &records) {1180 return getAllCppConstraints(records, "AttrConstraint");1181}1182 1183/// Emit the declarations for the given constraints, of the form:1184/// `bool <constraintCppFunctionName>(<parameterTypeName> <parameterName>);`1185static void emitConstraintDecls(ArrayRef<Constraint> constraints,1186 raw_ostream &os, StringRef parameterTypeName,1187 StringRef parameterName) {1188 static const char *const constraintDecl = "bool {0}({1} {2});\n";1189 for (Constraint constr : constraints)1190 os << strfmt(constraintDecl, *constr.getCppFunctionName(),1191 parameterTypeName, parameterName);1192}1193 1194static void emitTypeConstraintDecls(const RecordKeeper &records,1195 raw_ostream &os) {1196 emitConstraintDecls(getAllCppTypeConstraints(records), os, "::mlir::Type",1197 "type");1198}1199 1200static void emitAttrConstraintDecls(const RecordKeeper &records,1201 raw_ostream &os) {1202 emitConstraintDecls(getAllCppAttrConstraints(records), os,1203 "::mlir::Attribute", "attr");1204}1205 1206/// Emit the definitions for the given constraints, of the form:1207/// `bool <constraintCppFunctionName>(<parameterTypeName> <parameterName>) {1208/// return (<condition>); }`1209/// where `<condition>` is the condition template with the `self` variable1210/// replaced with the `selfName` parameter.1211static void emitConstraintDefs(ArrayRef<Constraint> constraints,1212 raw_ostream &os, StringRef parameterTypeName,1213 StringRef selfName) {1214 static const char *const constraintDef = R"(1215bool {0}({1} {2}) {1216return ({3});1217}1218)";1219 1220 for (Constraint constr : constraints) {1221 FmtContext ctx;1222 ctx.withSelf(selfName);1223 std::string condition = tgfmt(constr.getConditionTemplate(), &ctx);1224 os << strfmt(constraintDef, *constr.getCppFunctionName(), parameterTypeName,1225 selfName, condition);1226 }1227}1228 1229static void emitTypeConstraintDefs(const RecordKeeper &records,1230 raw_ostream &os) {1231 emitConstraintDefs(getAllCppTypeConstraints(records), os, "::mlir::Type",1232 "type");1233}1234 1235static void emitAttrConstraintDefs(const RecordKeeper &records,1236 raw_ostream &os) {1237 emitConstraintDefs(getAllCppAttrConstraints(records), os, "::mlir::Attribute",1238 "attr");1239}1240 1241//===----------------------------------------------------------------------===//1242// GEN: Registration hooks1243//===----------------------------------------------------------------------===//1244 1245//===----------------------------------------------------------------------===//1246// AttrDef1247//===----------------------------------------------------------------------===//1248 1249static llvm::cl::OptionCategory attrdefGenCat("Options for -gen-attrdef-*");1250static llvm::cl::opt<std::string>1251 attrDialect("attrdefs-dialect",1252 llvm::cl::desc("Generate attributes for this dialect"),1253 llvm::cl::cat(attrdefGenCat), llvm::cl::CommaSeparated);1254 1255static mlir::GenRegistration1256 genAttrDefs("gen-attrdef-defs", "Generate AttrDef definitions",1257 [](const RecordKeeper &records, raw_ostream &os) {1258 AttrDefGenerator generator(records, os);1259 return generator.emitDefs(attrDialect);1260 });1261static mlir::GenRegistration1262 genAttrDecls("gen-attrdef-decls", "Generate AttrDef declarations",1263 [](const RecordKeeper &records, raw_ostream &os) {1264 AttrDefGenerator generator(records, os);1265 return generator.emitDecls(attrDialect);1266 });1267 1268static mlir::GenRegistration1269 genAttrConstrDefs("gen-attr-constraint-defs",1270 "Generate attribute constraint definitions",1271 [](const RecordKeeper &records, raw_ostream &os) {1272 emitAttrConstraintDefs(records, os);1273 return false;1274 });1275static mlir::GenRegistration1276 genAttrConstrDecls("gen-attr-constraint-decls",1277 "Generate attribute constraint declarations",1278 [](const RecordKeeper &records, raw_ostream &os) {1279 emitAttrConstraintDecls(records, os);1280 return false;1281 });1282 1283//===----------------------------------------------------------------------===//1284// TypeDef1285//===----------------------------------------------------------------------===//1286 1287static llvm::cl::OptionCategory typedefGenCat("Options for -gen-typedef-*");1288static llvm::cl::opt<std::string>1289 typeDialect("typedefs-dialect",1290 llvm::cl::desc("Generate types for this dialect"),1291 llvm::cl::cat(typedefGenCat), llvm::cl::CommaSeparated);1292 1293static mlir::GenRegistration1294 genTypeDefs("gen-typedef-defs", "Generate TypeDef definitions",1295 [](const RecordKeeper &records, raw_ostream &os) {1296 TypeDefGenerator generator(records, os);1297 return generator.emitDefs(typeDialect);1298 });1299static mlir::GenRegistration1300 genTypeDecls("gen-typedef-decls", "Generate TypeDef declarations",1301 [](const RecordKeeper &records, raw_ostream &os) {1302 TypeDefGenerator generator(records, os);1303 return generator.emitDecls(typeDialect);1304 });1305 1306static mlir::GenRegistration1307 genTypeConstrDefs("gen-type-constraint-defs",1308 "Generate type constraint definitions",1309 [](const RecordKeeper &records, raw_ostream &os) {1310 emitTypeConstraintDefs(records, os);1311 return false;1312 });1313static mlir::GenRegistration1314 genTypeConstrDecls("gen-type-constraint-decls",1315 "Generate type constraint declarations",1316 [](const RecordKeeper &records, raw_ostream &os) {1317 emitTypeConstraintDecls(records, os);1318 return false;1319 });1320