brintos

brintos / llvm-project-archived public Read only

0
0
Text · 50.5 KiB · 2a513c3 Raw
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 &param : 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 &param = 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 &param) { 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 &param : 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 &param : 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 &param : 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 &param : 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 &param : 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 &currentMethod,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 &param : 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 &param : 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 &param) { 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 &param) { 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 &param : 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 &param) {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 &param : 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