brintos

brintos / llvm-project-archived public Read only

0
0
Text · 27.8 KiB · ab8d534 Raw
720 lines · cpp
1//===- OpInterfacesGen.cpp - MLIR op interface utility 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// OpInterfacesGen generates definitions for operation interfaces.10//11//===----------------------------------------------------------------------===//12 13#include "CppGenUtilities.h"14#include "DocGenUtilities.h"15#include "mlir/TableGen/Format.h"16#include "mlir/TableGen/GenInfo.h"17#include "mlir/TableGen/Interfaces.h"18#include "llvm/ADT/SmallVector.h"19#include "llvm/ADT/StringExtras.h"20#include "llvm/Support/FormatVariadic.h"21#include "llvm/Support/raw_ostream.h"22#include "llvm/TableGen/CodeGenHelpers.h"23#include "llvm/TableGen/Error.h"24#include "llvm/TableGen/Record.h"25#include "llvm/TableGen/TableGenBackend.h"26 27using namespace mlir;28using llvm::Record;29using llvm::RecordKeeper;30using mlir::tblgen::Interface;31using mlir::tblgen::InterfaceMethod;32using mlir::tblgen::OpInterface;33 34/// Emit a string corresponding to a C++ type, followed by a space if necessary.35static raw_ostream &emitCPPType(StringRef type, raw_ostream &os) {36  type = type.trim();37  os << type;38  if (type.back() != '&' && type.back() != '*')39    os << " ";40  return os;41}42 43/// Emit the method name and argument list for the given method. If 'addThisArg'44/// is true, then an argument is added to the beginning of the argument list for45/// the concrete value.46static void emitMethodNameAndArgs(const InterfaceMethod &method, StringRef name,47                                  raw_ostream &os, StringRef valueType,48                                  bool addThisArg, bool addConst) {49  os << name << '(';50  if (addThisArg) {51    if (addConst)52      os << "const ";53    os << "const Concept *impl, ";54    emitCPPType(valueType, os)55        << "tablegen_opaque_val" << (method.arg_empty() ? "" : ", ");56  }57  llvm::interleaveComma(method.getArguments(), os,58                        [&](const InterfaceMethod::Argument &arg) {59                          os << arg.type << " " << arg.name;60                        });61  os << ')';62  if (addConst)63    os << " const";64}65 66/// Get an array of all OpInterface definitions but exclude those subclassing67/// "DeclareOpInterfaceMethods".68static std::vector<const Record *>69getAllInterfaceDefinitions(const RecordKeeper &records, StringRef name) {70  std::vector<const Record *> defs =71      records.getAllDerivedDefinitions((name + "Interface").str());72 73  std::string declareName = ("Declare" + name + "InterfaceMethods").str();74  llvm::erase_if(defs, [&](const Record *def) {75    // Ignore any "declare methods" interfaces.76    if (def->isSubClassOf(declareName))77      return true;78    // Ignore interfaces defined outside of the top-level file.79    return llvm::SrcMgr.FindBufferContainingLoc(def->getLoc()[0]) !=80           llvm::SrcMgr.getMainFileID();81  });82  return defs;83}84 85namespace {86/// This struct is the base generator used when processing tablegen interfaces.87class InterfaceGenerator {88public:89  bool emitInterfaceDefs();90  bool emitInterfaceDecls();91  bool emitInterfaceDocs();92 93protected:94  InterfaceGenerator(std::vector<const Record *> &&defs, raw_ostream &os)95      : defs(std::move(defs)), os(os) {}96 97  void emitConceptDecl(const Interface &interface);98  void emitModelDecl(const Interface &interface);99  void emitModelMethodsDef(const Interface &interface);100  void forwardDeclareInterface(const Interface &interface);101  void emitInterfaceDecl(const Interface &interface);102  void emitInterfaceTraitDecl(const Interface &interface);103 104  /// The set of interface records to emit.105  std::vector<const Record *> defs;106  // The stream to emit to.107  raw_ostream &os;108  /// The C++ value type of the interface, e.g. Operation*.109  StringRef valueType;110  /// The C++ base interface type.111  StringRef interfaceBaseType;112  /// The name of the typename for the value template.113  StringRef valueTemplate;114  /// The name of the substituion variable for the value.115  StringRef substVar;116  /// The format context to use for methods.117  tblgen::FmtContext nonStaticMethodFmt;118  tblgen::FmtContext traitMethodFmt;119  tblgen::FmtContext extraDeclsFmt;120};121 122/// A specialized generator for attribute interfaces.123struct AttrInterfaceGenerator : public InterfaceGenerator {124  AttrInterfaceGenerator(const RecordKeeper &records, raw_ostream &os)125      : InterfaceGenerator(getAllInterfaceDefinitions(records, "Attr"), os) {126    valueType = "::mlir::Attribute";127    interfaceBaseType = "AttributeInterface";128    valueTemplate = "ConcreteAttr";129    substVar = "_attr";130    StringRef castCode = "(::llvm::cast<ConcreteAttr>(tablegen_opaque_val))";131    nonStaticMethodFmt.addSubst(substVar, castCode).withSelf(castCode);132    traitMethodFmt.addSubst(substVar,133                            "(*static_cast<const ConcreteAttr *>(this))");134    extraDeclsFmt.addSubst(substVar, "(*this)");135  }136};137/// A specialized generator for operation interfaces.138struct OpInterfaceGenerator : public InterfaceGenerator {139  OpInterfaceGenerator(const RecordKeeper &records, raw_ostream &os)140      : InterfaceGenerator(getAllInterfaceDefinitions(records, "Op"), os) {141    valueType = "::mlir::Operation *";142    interfaceBaseType = "OpInterface";143    valueTemplate = "ConcreteOp";144    substVar = "_op";145    StringRef castCode = "(llvm::cast<ConcreteOp>(tablegen_opaque_val))";146    nonStaticMethodFmt.addSubst("_this", "impl")147        .addSubst(substVar, castCode)148        .withSelf(castCode);149    traitMethodFmt.addSubst(substVar, "(*static_cast<ConcreteOp *>(this))");150    extraDeclsFmt.addSubst(substVar, "(*this)");151  }152};153/// A specialized generator for type interfaces.154struct TypeInterfaceGenerator : public InterfaceGenerator {155  TypeInterfaceGenerator(const RecordKeeper &records, raw_ostream &os)156      : InterfaceGenerator(getAllInterfaceDefinitions(records, "Type"), os) {157    valueType = "::mlir::Type";158    interfaceBaseType = "TypeInterface";159    valueTemplate = "ConcreteType";160    substVar = "_type";161    StringRef castCode = "(::llvm::cast<ConcreteType>(tablegen_opaque_val))";162    nonStaticMethodFmt.addSubst(substVar, castCode).withSelf(castCode);163    traitMethodFmt.addSubst(substVar,164                            "(*static_cast<const ConcreteType *>(this))");165    extraDeclsFmt.addSubst(substVar, "(*this)");166  }167};168} // namespace169 170//===----------------------------------------------------------------------===//171// GEN: Interface definitions172//===----------------------------------------------------------------------===//173 174static void emitInterfaceMethodDoc(const InterfaceMethod &method,175                                   raw_ostream &os, StringRef prefix = "") {176  if (std::optional<StringRef> description = method.getDescription())177    tblgen::emitDescriptionComment(*description, os, prefix);178}179static void emitInterfaceDefMethods(StringRef interfaceQualName,180                                    const Interface &interface,181                                    StringRef valueType, const Twine &implValue,182                                    raw_ostream &os, bool isOpInterface) {183  for (auto &method : interface.getMethods()) {184    emitInterfaceMethodDoc(method, os);185    emitCPPType(method.getReturnType(), os);186    os << interfaceQualName << "::";187    emitMethodNameAndArgs(method, method.getName(), os, valueType,188                          /*addThisArg=*/false,189                          /*addConst=*/!isOpInterface);190 191    // Forward to the method on the concrete operation type.192    os << " {\n      return " << implValue << "->" << method.getUniqueName()193       << '(';194    if (!method.isStatic()) {195      os << implValue << ", ";196      os << (isOpInterface ? "getOperation()" : "*this");197      os << (method.arg_empty() ? "" : ", ");198    }199    llvm::interleaveComma(200        method.getArguments(), os,201        [&](const InterfaceMethod::Argument &arg) { os << arg.name; });202    os << ");\n  }\n";203  }204}205 206static void emitInterfaceDef(const Interface &interface, StringRef valueType,207                             raw_ostream &os) {208  std::string interfaceQualNameStr = interface.getFullyQualifiedName();209  StringRef interfaceQualName = interfaceQualNameStr;210  interfaceQualName.consume_front("::");211 212  // Insert the method definitions.213  bool isOpInterface = isa<OpInterface>(interface);214  emitInterfaceDefMethods(interfaceQualName, interface, valueType, "getImpl()",215                          os, isOpInterface);216 217  // Insert the method definitions for base classes.218  for (auto &base : interface.getBaseInterfaces()) {219    emitInterfaceDefMethods(interfaceQualName, base, valueType,220                            "getImpl()->impl" + base.getName(), os,221                            isOpInterface);222  }223}224 225bool InterfaceGenerator::emitInterfaceDefs() {226  llvm::emitSourceFileHeader("Interface Definitions", os);227 228  for (const auto *def : defs)229    emitInterfaceDef(Interface(def), valueType, os);230  return false;231}232 233//===----------------------------------------------------------------------===//234// GEN: Interface declarations235//===----------------------------------------------------------------------===//236 237void InterfaceGenerator::emitConceptDecl(const Interface &interface) {238  os << "  struct Concept {\n";239 240  // Insert each of the pure virtual concept methods.241  os << "    /// The methods defined by the interface.\n";242  for (auto &method : interface.getMethods()) {243    os << "    ";244    emitCPPType(method.getReturnType(), os);245    os << "(*" << method.getUniqueName() << ")(";246    if (!method.isStatic()) {247      os << "const Concept *impl, ";248      emitCPPType(valueType, os) << (method.arg_empty() ? "" : ", ");249    }250    llvm::interleaveComma(251        method.getArguments(), os,252        [&](const InterfaceMethod::Argument &arg) { os << arg.type; });253    os << ");\n";254  }255 256  // Insert a field containing a concept for each of the base interfaces.257  auto baseInterfaces = interface.getBaseInterfaces();258  if (!baseInterfaces.empty()) {259    os << "    /// The base classes of this interface.\n";260    for (const auto &base : interface.getBaseInterfaces()) {261      os << "    const " << base.getFullyQualifiedName() << "::Concept *impl"262         << base.getName() << " = nullptr;\n";263    }264 265    // Define an "initialize" method that allows for the initialization of the266    // base class concepts.267    os << "\n    void initializeInterfaceConcept(::mlir::detail::InterfaceMap "268          "&interfaceMap) {\n";269    std::string interfaceQualName = interface.getFullyQualifiedName();270    for (const auto &base : interface.getBaseInterfaces()) {271      StringRef baseName = base.getName();272      std::string baseQualName = base.getFullyQualifiedName();273      os << "      impl" << baseName << " = interfaceMap.lookup<"274         << baseQualName << ">();\n"275         << "      assert(impl" << baseName << " && \"`" << interfaceQualName276         << "` expected its base interface `" << baseQualName277         << "` to be registered\");\n";278    }279    os << "    }\n";280  }281 282  os << "  };\n";283}284 285void InterfaceGenerator::emitModelDecl(const Interface &interface) {286  // Emit the basic model and the fallback model.287  for (const char *modelClass : {"Model", "FallbackModel"}) {288    os << "  template<typename " << valueTemplate << ">\n";289    os << "  class " << modelClass << " : public Concept {\n  public:\n";290    os << "    using Interface = " << interface.getFullyQualifiedName()291       << ";\n";292    os << "    " << modelClass << "() : Concept{";293    llvm::interleaveComma(294        interface.getMethods(), os,295        [&](const InterfaceMethod &method) { os << method.getUniqueName(); });296    os << "} {}\n\n";297 298    // Insert each of the virtual method overrides.299    for (auto &method : interface.getMethods()) {300      emitCPPType(method.getReturnType(), os << "    static inline ");301      emitMethodNameAndArgs(method, method.getUniqueName(), os, valueType,302                            /*addThisArg=*/!method.isStatic(),303                            /*addConst=*/false);304      os << ";\n";305    }306    os << "  };\n";307  }308 309  // Emit the template for the external model.310  os << "  template<typename ConcreteModel, typename " << valueTemplate311     << ">\n";312  os << "  class ExternalModel : public FallbackModel<ConcreteModel> {\n";313  os << "  public:\n";314  os << "    using ConcreteEntity = " << valueTemplate << ";\n";315 316  // Emit declarations for methods that have default implementations. Other317  // methods are expected to be implemented by the concrete derived model.318  for (auto &method : interface.getMethods()) {319    if (!method.getDefaultImplementation())320      continue;321    os << "    ";322    if (method.isStatic())323      os << "static ";324    emitCPPType(method.getReturnType(), os);325    os << method.getUniqueName() << "(";326    if (!method.isStatic()) {327      emitCPPType(valueType, os);328      os << "tablegen_opaque_val";329      if (!method.arg_empty())330        os << ", ";331    }332    llvm::interleaveComma(method.getArguments(), os,333                          [&](const InterfaceMethod::Argument &arg) {334                            emitCPPType(arg.type, os);335                            os << arg.name;336                          });337    os << ")";338    if (!method.isStatic())339      os << " const";340    os << ";\n";341  }342  os << "  };\n";343}344 345void InterfaceGenerator::emitModelMethodsDef(const Interface &interface) {346  llvm::NamespaceEmitter ns(os, interface.getCppNamespace());347  for (auto &method : interface.getMethods()) {348    os << "template<typename " << valueTemplate << ">\n";349    emitCPPType(method.getReturnType(), os);350    os << "detail::" << interface.getName() << "InterfaceTraits::Model<"351       << valueTemplate << ">::";352    emitMethodNameAndArgs(method, method.getUniqueName(), os, valueType,353                          /*addThisArg=*/!method.isStatic(),354                          /*addConst=*/false);355    os << " {\n  ";356 357    // Check for a provided body to the function.358    if (std::optional<StringRef> body = method.getBody()) {359      if (method.isStatic())360        os << body->trim();361      else362        os << tblgen::tgfmt(body->trim(), &nonStaticMethodFmt);363      os << "\n}\n";364      continue;365    }366 367    // Forward to the method on the concrete operation type.368    if (method.isStatic())369      os << "return " << valueTemplate << "::";370    else371      os << tblgen::tgfmt("return $_self.", &nonStaticMethodFmt);372 373    // Add the arguments to the call.374    os << method.getName() << '(';375    llvm::interleaveComma(376        method.getArguments(), os,377        [&](const InterfaceMethod::Argument &arg) { os << arg.name; });378    os << ");\n}\n";379  }380 381  for (auto &method : interface.getMethods()) {382    os << "template<typename " << valueTemplate << ">\n";383    emitCPPType(method.getReturnType(), os);384    os << "detail::" << interface.getName() << "InterfaceTraits::FallbackModel<"385       << valueTemplate << ">::";386    emitMethodNameAndArgs(method, method.getUniqueName(), os, valueType,387                          /*addThisArg=*/!method.isStatic(),388                          /*addConst=*/false);389    os << " {\n  ";390 391    // Forward to the method on the concrete Model implementation.392    if (method.isStatic())393      os << "return " << valueTemplate << "::";394    else395      os << "return static_cast<const " << valueTemplate << " *>(impl)->";396 397    // Add the arguments to the call.398    os << method.getUniqueName() << '(';399    if (!method.isStatic())400      os << "tablegen_opaque_val" << (method.arg_empty() ? "" : ", ");401    llvm::interleaveComma(402        method.getArguments(), os,403        [&](const InterfaceMethod::Argument &arg) { os << arg.name; });404    os << ");\n}\n";405  }406 407  // Emit default implementations for the external model.408  for (auto &method : interface.getMethods()) {409    if (!method.getDefaultImplementation())410      continue;411    os << "template<typename ConcreteModel, typename " << valueTemplate412       << ">\n";413    emitCPPType(method.getReturnType(), os);414    os << "detail::" << interface.getName()415       << "InterfaceTraits::ExternalModel<ConcreteModel, " << valueTemplate416       << ">::";417 418    os << method.getUniqueName() << "(";419    if (!method.isStatic()) {420      emitCPPType(valueType, os);421      os << "tablegen_opaque_val";422      if (!method.arg_empty())423        os << ", ";424    }425    llvm::interleaveComma(method.getArguments(), os,426                          [&](const InterfaceMethod::Argument &arg) {427                            emitCPPType(arg.type, os);428                            os << arg.name;429                          });430    os << ")";431    if (!method.isStatic())432      os << " const";433 434    os << " {\n";435 436    // Use the empty context for static methods.437    tblgen::FmtContext ctx;438    os << tblgen::tgfmt(method.getDefaultImplementation()->trim(),439                        method.isStatic() ? &ctx : &nonStaticMethodFmt);440    os << "\n}\n";441  }442}443 444void InterfaceGenerator::emitInterfaceTraitDecl(const Interface &interface) {445  auto cppNamespace = (interface.getCppNamespace() + "::detail").str();446  llvm::NamespaceEmitter ns(os, cppNamespace);447 448  StringRef interfaceName = interface.getName();449  auto interfaceTraitsName = (interfaceName + "InterfaceTraits").str();450  os << llvm::formatv("  template <typename {3}>\n"451                      "  struct {0}Trait : public ::mlir::{2}<{0},"452                      " detail::{1}>::Trait<{3}> {{\n",453                      interfaceName, interfaceTraitsName, interfaceBaseType,454                      valueTemplate);455 456  // Insert the default implementation for any methods.457  bool isOpInterface = isa<OpInterface>(interface);458  for (auto &method : interface.getMethods()) {459    // Flag interface methods named verifyTrait.460    if (method.getName() == "verifyTrait")461      PrintFatalError(462          formatv("'verifyTrait' method cannot be specified as interface "463                  "method for '{0}'; use the 'verify' field instead",464                  interfaceName));465    auto defaultImpl = method.getDefaultImplementation();466    if (!defaultImpl)467      continue;468 469    emitInterfaceMethodDoc(method, os, "    ");470    os << "    " << (method.isStatic() ? "static " : "");471    emitCPPType(method.getReturnType(), os);472    emitMethodNameAndArgs(method, method.getName(), os, valueType,473                          /*addThisArg=*/false,474                          /*addConst=*/!isOpInterface && !method.isStatic());475    os << " {\n      " << tblgen::tgfmt(defaultImpl->trim(), &traitMethodFmt)476       << "\n    }\n";477  }478 479  if (auto verify = interface.getVerify()) {480    assert(isa<OpInterface>(interface) && "only OpInterface supports 'verify'");481 482    tblgen::FmtContext verifyCtx;483    verifyCtx.addSubst("_op", "op");484    os << llvm::formatv(485              "    static ::llvm::LogicalResult {0}(::mlir::Operation *op) ",486              (interface.verifyWithRegions() ? "verifyRegionTrait"487                                             : "verifyTrait"))488       << "{\n      " << tblgen::tgfmt(verify->trim(), &verifyCtx)489       << "\n    }\n";490  }491  if (auto extraTraitDecls = interface.getExtraTraitClassDeclaration())492    os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";493  if (auto extraTraitDecls = interface.getExtraSharedClassDeclaration())494    os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";495 496  os << "  };\n";497}498 499static void emitInterfaceDeclMethods(const Interface &interface,500                                     raw_ostream &os, StringRef valueType,501                                     bool isOpInterface,502                                     tblgen::FmtContext &extraDeclsFmt) {503  for (auto &method : interface.getMethods()) {504    emitInterfaceMethodDoc(method, os, "  ");505    emitCPPType(method.getReturnType(), os << "  ");506    emitMethodNameAndArgs(method, method.getName(), os, valueType,507                          /*addThisArg=*/false,508                          /*addConst=*/!isOpInterface);509    os << ";\n";510  }511 512  // Emit any extra declarations.513  if (std::optional<StringRef> extraDecls =514          interface.getExtraClassDeclaration())515    os << extraDecls->rtrim() << "\n";516  if (std::optional<StringRef> extraDecls =517          interface.getExtraSharedClassDeclaration())518    os << tblgen::tgfmt(extraDecls->rtrim(), &extraDeclsFmt) << "\n";519}520 521void InterfaceGenerator::forwardDeclareInterface(const Interface &interface) {522  llvm::NamespaceEmitter ns(os, interface.getCppNamespace());523 524  // Emit a forward declaration of the interface class so that it becomes usable525  // in the signature of its methods.526  tblgen::emitSummaryAndDescComments(os, "",527                                     interface.getDescription().value_or(""));528 529  StringRef interfaceName = interface.getName();530  os << "class " << interfaceName << ";\n";531}532 533void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {534  llvm::NamespaceEmitter ns(os, interface.getCppNamespace());535 536  StringRef interfaceName = interface.getName();537  auto interfaceTraitsName = (interfaceName + "InterfaceTraits").str();538 539  // Emit a forward declaration of the interface class so that it becomes usable540  // in the signature of its methods.541  tblgen::emitSummaryAndDescComments(os, "",542                                     interface.getDescription().value_or(""));543 544  // Emit the traits struct containing the concept and model declarations.545  os << "namespace detail {\n"546     << "struct " << interfaceTraitsName << " {\n";547  emitConceptDecl(interface);548  emitModelDecl(interface);549  os << "};\n";550 551  // Emit the derived trait for the interface.552  os << "template <typename " << valueTemplate << ">\n";553  os << "struct " << interface.getName() << "Trait;\n";554 555  os << "\n} // namespace detail\n";556 557  // Emit the main interface class declaration.558  os << llvm::formatv("class {0} : public ::mlir::{3}<{1}, detail::{2}> {\n"559                      "public:\n"560                      "  using ::mlir::{3}<{1}, detail::{2}>::{3};\n",561                      interfaceName, interfaceName, interfaceTraitsName,562                      interfaceBaseType);563 564  // Emit a utility wrapper trait class.565  os << llvm::formatv("  template <typename {1}>\n"566                      "  struct Trait : public detail::{0}Trait<{1}> {{};\n",567                      interfaceName, valueTemplate);568 569  // Insert the method declarations.570  bool isOpInterface = isa<OpInterface>(interface);571  emitInterfaceDeclMethods(interface, os, valueType, isOpInterface,572                           extraDeclsFmt);573 574  // Insert the method declarations for base classes.575  for (auto &base : interface.getBaseInterfaces()) {576    std::string baseQualName = base.getFullyQualifiedName();577    os << "  //"578          "===---------------------------------------------------------------"579          "-===//\n"580       << "  // Inherited from " << baseQualName << "\n"581       << "  //"582          "===---------------------------------------------------------------"583          "-===//\n\n";584 585    // Allow implicit conversion to the base interface.586    os << "  operator " << baseQualName << " () const {\n"587       << "    if (!*this) return nullptr;\n"588       << "    return " << baseQualName << "(*this, getImpl()->impl"589       << base.getName() << ");\n"590       << "  }\n\n";591 592    // Inherit the base interface's methods.593    emitInterfaceDeclMethods(base, os, valueType, isOpInterface, extraDeclsFmt);594  }595 596  // Emit classof code if necessary.597  if (std::optional<StringRef> extraClassOf = interface.getExtraClassOf()) {598    auto extraClassOfFmt = tblgen::FmtContext();599    extraClassOfFmt.addSubst(substVar, "odsInterfaceInstance");600    os << "  static bool classof(" << valueType << " base) {\n"601       << "    auto* interface = getInterfaceFor(base);\n"602       << "    if (!interface)\n"603          "      return false;\n"604          "    "605       << interfaceName << " odsInterfaceInstance(base, interface);\n"606       << "    " << tblgen::tgfmt(extraClassOf->trim(), &extraClassOfFmt)607       << "\n  }\n";608  }609 610  os << "};\n";611}612 613bool InterfaceGenerator::emitInterfaceDecls() {614  llvm::emitSourceFileHeader("Interface Declarations", os);615  // Sort according to ID, so defs are emitted in the order in which they appear616  // in the Tablegen file.617  std::vector<const Record *> sortedDefs(defs);618  llvm::sort(sortedDefs, [](const Record *lhs, const Record *rhs) {619    return lhs->getID() < rhs->getID();620  });621  for (const Record *def : sortedDefs)622    forwardDeclareInterface(Interface(def));623  for (const Record *def : sortedDefs)624    emitInterfaceDecl(Interface(def));625  for (const Record *def : sortedDefs)626    emitInterfaceTraitDecl(Interface(def));627  for (const Record *def : sortedDefs)628    emitModelMethodsDef(Interface(def));629 630  return false;631}632 633//===----------------------------------------------------------------------===//634// GEN: Interface documentation635//===----------------------------------------------------------------------===//636 637static void emitInterfaceDoc(const Record &interfaceDef, raw_ostream &os) {638  Interface interface(&interfaceDef);639 640  // Emit the interface name followed by the description.641  os << "\n## " << interface.getName() << " (`" << interfaceDef.getName()642     << "`)\n";643  if (auto description = interface.getDescription())644    mlir::tblgen::emitDescription(*description, os);645 646  // Emit the methods required by the interface.647  os << "\n### Methods:\n";648  for (const auto &method : interface.getMethods()) {649    // Emit the method name.650    os << "\n#### `" << method.getName() << "`\n\n```c++\n";651 652    // Emit the method signature.653    if (method.isStatic())654      os << "static ";655    emitCPPType(method.getReturnType(), os) << method.getName() << '(';656    llvm::interleaveComma(method.getArguments(), os,657                          [&](const InterfaceMethod::Argument &arg) {658                            emitCPPType(arg.type, os) << arg.name;659                          });660    os << ");\n```\n";661 662    // Emit the description.663    if (auto description = method.getDescription())664      mlir::tblgen::emitDescription(*description, os);665 666    // If the body is not provided, this method must be provided by the user.667    if (!method.getBody())668      os << "\nNOTE: This method *must* be implemented by the user.";669 670    os << "\n";671  }672}673 674bool InterfaceGenerator::emitInterfaceDocs() {675  os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";676  os << "\n# " << interfaceBaseType << " definitions\n";677 678  for (const auto *def : defs)679    emitInterfaceDoc(*def, os);680  return false;681}682 683//===----------------------------------------------------------------------===//684// GEN: Interface registration hooks685//===----------------------------------------------------------------------===//686 687namespace {688template <typename GeneratorT>689struct InterfaceGenRegistration {690  InterfaceGenRegistration(StringRef genArg, StringRef genDesc)691      : genDeclArg(("gen-" + genArg + "-interface-decls").str()),692        genDefArg(("gen-" + genArg + "-interface-defs").str()),693        genDocArg(("gen-" + genArg + "-interface-docs").str()),694        genDeclDesc(("Generate " + genDesc + " interface declarations").str()),695        genDefDesc(("Generate " + genDesc + " interface definitions").str()),696        genDocDesc(("Generate " + genDesc + " interface documentation").str()),697        genDecls(genDeclArg, genDeclDesc,698                 [](const RecordKeeper &records, raw_ostream &os) {699                   return GeneratorT(records, os).emitInterfaceDecls();700                 }),701        genDefs(genDefArg, genDefDesc,702                [](const RecordKeeper &records, raw_ostream &os) {703                  return GeneratorT(records, os).emitInterfaceDefs();704                }),705        genDocs(genDocArg, genDocDesc,706                [](const RecordKeeper &records, raw_ostream &os) {707                  return GeneratorT(records, os).emitInterfaceDocs();708                }) {}709 710  std::string genDeclArg, genDefArg, genDocArg;711  std::string genDeclDesc, genDefDesc, genDocDesc;712  mlir::GenRegistration genDecls, genDefs, genDocs;713};714} // namespace715 716static InterfaceGenRegistration<AttrInterfaceGenerator> attrGen("attr",717                                                                "attribute");718static InterfaceGenRegistration<OpInterfaceGenerator> opGen("op", "op");719static InterfaceGenRegistration<TypeInterfaceGenerator> typeGen("type", "type");720