xref: /llvm-project/mlir/tools/mlir-tblgen/OpInterfacesGen.cpp (revision e813750354bbc08551cf23ff559a54b4a9ea1f29)
1b9377d7eSRiver Riddle //===- OpInterfacesGen.cpp - MLIR op interface utility generator ----------===//
2b9377d7eSRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b9377d7eSRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8b9377d7eSRiver Riddle //
9b9377d7eSRiver Riddle // OpInterfacesGen generates definitions for operation interfaces.
10b9377d7eSRiver Riddle //
11b9377d7eSRiver Riddle //===----------------------------------------------------------------------===//
12b9377d7eSRiver Riddle 
13635544fcSRiver Riddle #include "DocGenUtilities.h"
14178562fbSJacques Pienaar #include "mlir/TableGen/Format.h"
15b9377d7eSRiver Riddle #include "mlir/TableGen/GenInfo.h"
162e2cdd0aSRiver Riddle #include "mlir/TableGen/Interfaces.h"
17b9377d7eSRiver Riddle #include "llvm/ADT/SmallVector.h"
18b9377d7eSRiver Riddle #include "llvm/ADT/StringExtras.h"
19b9377d7eSRiver Riddle #include "llvm/Support/FormatVariadic.h"
20b9377d7eSRiver Riddle #include "llvm/Support/raw_ostream.h"
21b9377d7eSRiver Riddle #include "llvm/TableGen/Error.h"
22b9377d7eSRiver Riddle #include "llvm/TableGen/Record.h"
23b9377d7eSRiver Riddle #include "llvm/TableGen/TableGenBackend.h"
24b9377d7eSRiver Riddle 
25b9377d7eSRiver Riddle using namespace mlir;
26bccd37f6SRahul Joshi using llvm::Record;
27bccd37f6SRahul Joshi using llvm::RecordKeeper;
282e2cdd0aSRiver Riddle using mlir::tblgen::Interface;
292e2cdd0aSRiver Riddle using mlir::tblgen::InterfaceMethod;
300b81eb92SJacques Pienaar using mlir::tblgen::OpInterface;
31635544fcSRiver Riddle 
32635544fcSRiver Riddle /// Emit a string corresponding to a C++ type, followed by a space if necessary.
33635544fcSRiver Riddle static raw_ostream &emitCPPType(StringRef type, raw_ostream &os) {
34635544fcSRiver Riddle   type = type.trim();
35635544fcSRiver Riddle   os << type;
36635544fcSRiver Riddle   if (type.back() != '&' && type.back() != '*')
37635544fcSRiver Riddle     os << " ";
38635544fcSRiver Riddle   return os;
39635544fcSRiver Riddle }
40635544fcSRiver Riddle 
412e2cdd0aSRiver Riddle /// Emit the method name and argument list for the given method. If 'addThisArg'
422e2cdd0aSRiver Riddle /// is true, then an argument is added to the beginning of the argument list for
432e2cdd0aSRiver Riddle /// the concrete value.
442e2cdd0aSRiver Riddle static void emitMethodNameAndArgs(const InterfaceMethod &method,
452e2cdd0aSRiver Riddle                                   raw_ostream &os, StringRef valueType,
462e2cdd0aSRiver Riddle                                   bool addThisArg, bool addConst) {
472e2cdd0aSRiver Riddle   os << method.getName() << '(';
48d905c103SMehdi Amini   if (addThisArg) {
49d905c103SMehdi Amini     if (addConst)
50d905c103SMehdi Amini       os << "const ";
51d905c103SMehdi Amini     os << "const Concept *impl, ";
522e2cdd0aSRiver Riddle     emitCPPType(valueType, os)
532e2cdd0aSRiver Riddle         << "tablegen_opaque_val" << (method.arg_empty() ? "" : ", ");
54d905c103SMehdi Amini   }
552e2cdd0aSRiver Riddle   llvm::interleaveComma(method.getArguments(), os,
562e2cdd0aSRiver Riddle                         [&](const InterfaceMethod::Argument &arg) {
572e2cdd0aSRiver Riddle                           os << arg.type << " " << arg.name;
582e2cdd0aSRiver Riddle                         });
592e2cdd0aSRiver Riddle   os << ')';
602e2cdd0aSRiver Riddle   if (addConst)
612e2cdd0aSRiver Riddle     os << " const";
622e2cdd0aSRiver Riddle }
632e2cdd0aSRiver Riddle 
642e2cdd0aSRiver Riddle /// Get an array of all OpInterface definitions but exclude those subclassing
652e2cdd0aSRiver Riddle /// "DeclareOpInterfaceMethods".
66bccd37f6SRahul Joshi static std::vector<const Record *>
67*e8137503SRahul Joshi getAllInterfaceDefinitions(const RecordKeeper &records, StringRef name) {
68bccd37f6SRahul Joshi   std::vector<const Record *> defs =
69*e8137503SRahul Joshi       records.getAllDerivedDefinitions((name + "Interface").str());
702e2cdd0aSRiver Riddle 
713e731af9SRiver Riddle   std::string declareName = ("Declare" + name + "InterfaceMethods").str();
72bccd37f6SRahul Joshi   llvm::erase_if(defs, [&](const Record *def) {
733e731af9SRiver Riddle     // Ignore any "declare methods" interfaces.
743e731af9SRiver Riddle     if (def->isSubClassOf(declareName))
753e731af9SRiver Riddle       return true;
763e731af9SRiver Riddle     // Ignore interfaces defined outside of the top-level file.
773e731af9SRiver Riddle     return llvm::SrcMgr.FindBufferContainingLoc(def->getLoc()[0]) !=
783e731af9SRiver Riddle            llvm::SrcMgr.getMainFileID();
792e2cdd0aSRiver Riddle   });
802e2cdd0aSRiver Riddle   return defs;
812e2cdd0aSRiver Riddle }
822e2cdd0aSRiver Riddle 
832e2cdd0aSRiver Riddle namespace {
842e2cdd0aSRiver Riddle /// This struct is the base generator used when processing tablegen interfaces.
852e2cdd0aSRiver Riddle class InterfaceGenerator {
862e2cdd0aSRiver Riddle public:
872e2cdd0aSRiver Riddle   bool emitInterfaceDefs();
882e2cdd0aSRiver Riddle   bool emitInterfaceDecls();
892e2cdd0aSRiver Riddle   bool emitInterfaceDocs();
902e2cdd0aSRiver Riddle 
912e2cdd0aSRiver Riddle protected:
92bccd37f6SRahul Joshi   InterfaceGenerator(std::vector<const Record *> &&defs, raw_ostream &os)
932e2cdd0aSRiver Riddle       : defs(std::move(defs)), os(os) {}
942e2cdd0aSRiver Riddle 
9578fdbdbfSMehdi Amini   void emitConceptDecl(const Interface &interface);
9678fdbdbfSMehdi Amini   void emitModelDecl(const Interface &interface);
9778fdbdbfSMehdi Amini   void emitModelMethodsDef(const Interface &interface);
9878fdbdbfSMehdi Amini   void emitTraitDecl(const Interface &interface, StringRef interfaceName,
992e2cdd0aSRiver Riddle                      StringRef interfaceTraitsName);
10078fdbdbfSMehdi Amini   void emitInterfaceDecl(const Interface &interface);
1012e2cdd0aSRiver Riddle 
1022e2cdd0aSRiver Riddle   /// The set of interface records to emit.
103bccd37f6SRahul Joshi   std::vector<const Record *> defs;
1042e2cdd0aSRiver Riddle   // The stream to emit to.
1052e2cdd0aSRiver Riddle   raw_ostream &os;
1062e2cdd0aSRiver Riddle   /// The C++ value type of the interface, e.g. Operation*.
1072e2cdd0aSRiver Riddle   StringRef valueType;
1082e2cdd0aSRiver Riddle   /// The C++ base interface type.
1092e2cdd0aSRiver Riddle   StringRef interfaceBaseType;
1102e2cdd0aSRiver Riddle   /// The name of the typename for the value template.
1112e2cdd0aSRiver Riddle   StringRef valueTemplate;
1125cdc2bbcSRiver Riddle   /// The name of the substituion variable for the value.
1135cdc2bbcSRiver Riddle   StringRef substVar;
1142e2cdd0aSRiver Riddle   /// The format context to use for methods.
1152e2cdd0aSRiver Riddle   tblgen::FmtContext nonStaticMethodFmt;
1162e2cdd0aSRiver Riddle   tblgen::FmtContext traitMethodFmt;
117a60e83feSRiver Riddle   tblgen::FmtContext extraDeclsFmt;
1182e2cdd0aSRiver Riddle };
1192e2cdd0aSRiver Riddle 
1202e2cdd0aSRiver Riddle /// A specialized generator for attribute interfaces.
1212e2cdd0aSRiver Riddle struct AttrInterfaceGenerator : public InterfaceGenerator {
122bccd37f6SRahul Joshi   AttrInterfaceGenerator(const RecordKeeper &records, raw_ostream &os)
1233e731af9SRiver Riddle       : InterfaceGenerator(getAllInterfaceDefinitions(records, "Attr"), os) {
1242e2cdd0aSRiver Riddle     valueType = "::mlir::Attribute";
1251eded173SUlysse Beaugnon     interfaceBaseType = "AttributeInterface";
1262e2cdd0aSRiver Riddle     valueTemplate = "ConcreteAttr";
1275cdc2bbcSRiver Riddle     substVar = "_attr";
1286de63b82STres Popp     StringRef castCode = "(::llvm::cast<ConcreteAttr>(tablegen_opaque_val))";
1295cdc2bbcSRiver Riddle     nonStaticMethodFmt.addSubst(substVar, castCode).withSelf(castCode);
1305cdc2bbcSRiver Riddle     traitMethodFmt.addSubst(substVar,
1312e2cdd0aSRiver Riddle                             "(*static_cast<const ConcreteAttr *>(this))");
1325cdc2bbcSRiver Riddle     extraDeclsFmt.addSubst(substVar, "(*this)");
1332e2cdd0aSRiver Riddle   }
1342e2cdd0aSRiver Riddle };
135a23d0559SKazuaki Ishizaki /// A specialized generator for operation interfaces.
1362e2cdd0aSRiver Riddle struct OpInterfaceGenerator : public InterfaceGenerator {
137bccd37f6SRahul Joshi   OpInterfaceGenerator(const RecordKeeper &records, raw_ostream &os)
1383e731af9SRiver Riddle       : InterfaceGenerator(getAllInterfaceDefinitions(records, "Op"), os) {
1392e2cdd0aSRiver Riddle     valueType = "::mlir::Operation *";
1402e2cdd0aSRiver Riddle     interfaceBaseType = "OpInterface";
1412e2cdd0aSRiver Riddle     valueTemplate = "ConcreteOp";
1425cdc2bbcSRiver Riddle     substVar = "_op";
1432e2cdd0aSRiver Riddle     StringRef castCode = "(llvm::cast<ConcreteOp>(tablegen_opaque_val))";
144d905c103SMehdi Amini     nonStaticMethodFmt.addSubst("_this", "impl")
1455cdc2bbcSRiver Riddle         .addSubst(substVar, castCode)
146d905c103SMehdi Amini         .withSelf(castCode);
1475cdc2bbcSRiver Riddle     traitMethodFmt.addSubst(substVar, "(*static_cast<ConcreteOp *>(this))");
1485cdc2bbcSRiver Riddle     extraDeclsFmt.addSubst(substVar, "(*this)");
1492e2cdd0aSRiver Riddle   }
1502e2cdd0aSRiver Riddle };
1512e2cdd0aSRiver Riddle /// A specialized generator for type interfaces.
1522e2cdd0aSRiver Riddle struct TypeInterfaceGenerator : public InterfaceGenerator {
153bccd37f6SRahul Joshi   TypeInterfaceGenerator(const RecordKeeper &records, raw_ostream &os)
1543e731af9SRiver Riddle       : InterfaceGenerator(getAllInterfaceDefinitions(records, "Type"), os) {
1552e2cdd0aSRiver Riddle     valueType = "::mlir::Type";
1562e2cdd0aSRiver Riddle     interfaceBaseType = "TypeInterface";
1572e2cdd0aSRiver Riddle     valueTemplate = "ConcreteType";
1585cdc2bbcSRiver Riddle     substVar = "_type";
1596de63b82STres Popp     StringRef castCode = "(::llvm::cast<ConcreteType>(tablegen_opaque_val))";
1605cdc2bbcSRiver Riddle     nonStaticMethodFmt.addSubst(substVar, castCode).withSelf(castCode);
1615cdc2bbcSRiver Riddle     traitMethodFmt.addSubst(substVar,
1622e2cdd0aSRiver Riddle                             "(*static_cast<const ConcreteType *>(this))");
1635cdc2bbcSRiver Riddle     extraDeclsFmt.addSubst(substVar, "(*this)");
1642e2cdd0aSRiver Riddle   }
1652e2cdd0aSRiver Riddle };
166be0a7e9fSMehdi Amini } // namespace
1672e2cdd0aSRiver Riddle 
1682e2cdd0aSRiver Riddle //===----------------------------------------------------------------------===//
1692e2cdd0aSRiver Riddle // GEN: Interface definitions
1702e2cdd0aSRiver Riddle //===----------------------------------------------------------------------===//
1712e2cdd0aSRiver Riddle 
1722e2ad539SAlex Zinenko static void emitInterfaceMethodDoc(const InterfaceMethod &method,
1732e2ad539SAlex Zinenko                                    raw_ostream &os, StringRef prefix = "") {
1743cfe412eSFangrui Song   if (std::optional<StringRef> description = method.getDescription())
1752e2ad539SAlex Zinenko     tblgen::emitDescriptionComment(*description, os, prefix);
1762e2ad539SAlex Zinenko }
17783a635c0SRiver Riddle static void emitInterfaceDefMethods(StringRef interfaceQualName,
17883a635c0SRiver Riddle                                     const Interface &interface,
17983a635c0SRiver Riddle                                     StringRef valueType, const Twine &implValue,
18083a635c0SRiver Riddle                                     raw_ostream &os, bool isOpInterface) {
1812e2cdd0aSRiver Riddle   for (auto &method : interface.getMethods()) {
1822e2ad539SAlex Zinenko     emitInterfaceMethodDoc(method, os);
183572c2905SRiver Riddle     emitCPPType(method.getReturnType(), os);
18483a635c0SRiver Riddle     os << interfaceQualName << "::";
1852e2cdd0aSRiver Riddle     emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
1862e2cdd0aSRiver Riddle                           /*addConst=*/!isOpInterface);
1872e2cdd0aSRiver Riddle 
1882e2cdd0aSRiver Riddle     // Forward to the method on the concrete operation type.
18983a635c0SRiver Riddle     os << " {\n      return " << implValue << "->" << method.getName() << '(';
1902e2cdd0aSRiver Riddle     if (!method.isStatic()) {
19183a635c0SRiver Riddle       os << implValue << ", ";
1922e2cdd0aSRiver Riddle       os << (isOpInterface ? "getOperation()" : "*this");
1932e2cdd0aSRiver Riddle       os << (method.arg_empty() ? "" : ", ");
1942e2cdd0aSRiver Riddle     }
1952e2cdd0aSRiver Riddle     llvm::interleaveComma(
1962e2cdd0aSRiver Riddle         method.getArguments(), os,
1972e2cdd0aSRiver Riddle         [&](const InterfaceMethod::Argument &arg) { os << arg.name; });
1982e2cdd0aSRiver Riddle     os << ");\n  }\n";
1992e2cdd0aSRiver Riddle   }
2002e2cdd0aSRiver Riddle }
2012e2cdd0aSRiver Riddle 
20283a635c0SRiver Riddle static void emitInterfaceDef(const Interface &interface, StringRef valueType,
20383a635c0SRiver Riddle                              raw_ostream &os) {
20483a635c0SRiver Riddle   std::string interfaceQualNameStr = interface.getFullyQualifiedName();
20583a635c0SRiver Riddle   StringRef interfaceQualName = interfaceQualNameStr;
20683a635c0SRiver Riddle   interfaceQualName.consume_front("::");
20783a635c0SRiver Riddle 
20883a635c0SRiver Riddle   // Insert the method definitions.
20983a635c0SRiver Riddle   bool isOpInterface = isa<OpInterface>(interface);
21083a635c0SRiver Riddle   emitInterfaceDefMethods(interfaceQualName, interface, valueType, "getImpl()",
21183a635c0SRiver Riddle                           os, isOpInterface);
21283a635c0SRiver Riddle 
21383a635c0SRiver Riddle   // Insert the method definitions for base classes.
21483a635c0SRiver Riddle   for (auto &base : interface.getBaseInterfaces()) {
21583a635c0SRiver Riddle     emitInterfaceDefMethods(interfaceQualName, base, valueType,
21683a635c0SRiver Riddle                             "getImpl()->impl" + base.getName(), os,
21783a635c0SRiver Riddle                             isOpInterface);
21883a635c0SRiver Riddle   }
21983a635c0SRiver Riddle }
22083a635c0SRiver Riddle 
2212e2cdd0aSRiver Riddle bool InterfaceGenerator::emitInterfaceDefs() {
2222e2cdd0aSRiver Riddle   llvm::emitSourceFileHeader("Interface Definitions", os);
2232e2cdd0aSRiver Riddle 
2242e2cdd0aSRiver Riddle   for (const auto *def : defs)
2252e2cdd0aSRiver Riddle     emitInterfaceDef(Interface(def), valueType, os);
2262e2cdd0aSRiver Riddle   return false;
2272e2cdd0aSRiver Riddle }
2282e2cdd0aSRiver Riddle 
2292e2cdd0aSRiver Riddle //===----------------------------------------------------------------------===//
2302e2cdd0aSRiver Riddle // GEN: Interface declarations
2312e2cdd0aSRiver Riddle //===----------------------------------------------------------------------===//
2322e2cdd0aSRiver Riddle 
23378fdbdbfSMehdi Amini void InterfaceGenerator::emitConceptDecl(const Interface &interface) {
234ef728eafSRiver Riddle   os << "  struct Concept {\n";
2352e2cdd0aSRiver Riddle 
2362e2cdd0aSRiver Riddle   // Insert each of the pure virtual concept methods.
23783a635c0SRiver Riddle   os << "    /// The methods defined by the interface.\n";
2382e2cdd0aSRiver Riddle   for (auto &method : interface.getMethods()) {
239ef728eafSRiver Riddle     os << "    ";
2402e2cdd0aSRiver Riddle     emitCPPType(method.getReturnType(), os);
241ef728eafSRiver Riddle     os << "(*" << method.getName() << ")(";
242d905c103SMehdi Amini     if (!method.isStatic()) {
243d905c103SMehdi Amini       os << "const Concept *impl, ";
244ef728eafSRiver Riddle       emitCPPType(valueType, os) << (method.arg_empty() ? "" : ", ");
245d905c103SMehdi Amini     }
246ef728eafSRiver Riddle     llvm::interleaveComma(
247ef728eafSRiver Riddle         method.getArguments(), os,
248ef728eafSRiver Riddle         [&](const InterfaceMethod::Argument &arg) { os << arg.type; });
249ef728eafSRiver Riddle     os << ");\n";
2502e2cdd0aSRiver Riddle   }
25183a635c0SRiver Riddle 
25283a635c0SRiver Riddle   // Insert a field containing a concept for each of the base interfaces.
25383a635c0SRiver Riddle   auto baseInterfaces = interface.getBaseInterfaces();
25483a635c0SRiver Riddle   if (!baseInterfaces.empty()) {
25583a635c0SRiver Riddle     os << "    /// The base classes of this interface.\n";
25683a635c0SRiver Riddle     for (const auto &base : interface.getBaseInterfaces()) {
25783a635c0SRiver Riddle       os << "    const " << base.getFullyQualifiedName() << "::Concept *impl"
25883a635c0SRiver Riddle          << base.getName() << " = nullptr;\n";
25983a635c0SRiver Riddle     }
26083a635c0SRiver Riddle 
26183a635c0SRiver Riddle     // Define an "initialize" method that allows for the initialization of the
26283a635c0SRiver Riddle     // base class concepts.
26383a635c0SRiver Riddle     os << "\n    void initializeInterfaceConcept(::mlir::detail::InterfaceMap "
26483a635c0SRiver Riddle           "&interfaceMap) {\n";
26583a635c0SRiver Riddle     std::string interfaceQualName = interface.getFullyQualifiedName();
26683a635c0SRiver Riddle     for (const auto &base : interface.getBaseInterfaces()) {
26783a635c0SRiver Riddle       StringRef baseName = base.getName();
26883a635c0SRiver Riddle       std::string baseQualName = base.getFullyQualifiedName();
26983a635c0SRiver Riddle       os << "      impl" << baseName << " = interfaceMap.lookup<"
27083a635c0SRiver Riddle          << baseQualName << ">();\n"
27183a635c0SRiver Riddle          << "      assert(impl" << baseName << " && \"`" << interfaceQualName
27283a635c0SRiver Riddle          << "` expected its base interface `" << baseQualName
27383a635c0SRiver Riddle          << "` to be registered\");\n";
27483a635c0SRiver Riddle     }
27583a635c0SRiver Riddle     os << "    }\n";
27683a635c0SRiver Riddle   }
27783a635c0SRiver Riddle 
2782e2cdd0aSRiver Riddle   os << "  };\n";
2792e2cdd0aSRiver Riddle }
2802e2cdd0aSRiver Riddle 
28178fdbdbfSMehdi Amini void InterfaceGenerator::emitModelDecl(const Interface &interface) {
2829b2a1bcfSAlex Zinenko   // Emit the basic model and the fallback model.
283d905c103SMehdi Amini   for (const char *modelClass : {"Model", "FallbackModel"}) {
2842e2cdd0aSRiver Riddle     os << "  template<typename " << valueTemplate << ">\n";
285d905c103SMehdi Amini     os << "  class " << modelClass << " : public Concept {\n  public:\n";
28683a635c0SRiver Riddle     os << "    using Interface = " << interface.getFullyQualifiedName()
28783a635c0SRiver Riddle        << ";\n";
288d905c103SMehdi Amini     os << "    " << modelClass << "() : Concept{";
289ef728eafSRiver Riddle     llvm::interleaveComma(
290ef728eafSRiver Riddle         interface.getMethods(), os,
291ef728eafSRiver Riddle         [&](const InterfaceMethod &method) { os << method.getName(); });
292ef728eafSRiver Riddle     os << "} {}\n\n";
2932e2cdd0aSRiver Riddle 
2942e2cdd0aSRiver Riddle     // Insert each of the virtual method overrides.
2952e2cdd0aSRiver Riddle     for (auto &method : interface.getMethods()) {
29688f25bdaSAlex Zinenko       emitCPPType(method.getReturnType(), os << "    static inline ");
29788f25bdaSAlex Zinenko       emitMethodNameAndArgs(method, os, valueType,
29888f25bdaSAlex Zinenko                             /*addThisArg=*/!method.isStatic(),
29988f25bdaSAlex Zinenko                             /*addConst=*/false);
30088f25bdaSAlex Zinenko       os << ";\n";
30188f25bdaSAlex Zinenko     }
30288f25bdaSAlex Zinenko     os << "  };\n";
30388f25bdaSAlex Zinenko   }
3049b2a1bcfSAlex Zinenko 
305a4f81b20SAlex Zinenko   // Emit the template for the external model.
3069b2a1bcfSAlex Zinenko   os << "  template<typename ConcreteModel, typename " << valueTemplate
3079b2a1bcfSAlex Zinenko      << ">\n";
3089b2a1bcfSAlex Zinenko   os << "  class ExternalModel : public FallbackModel<ConcreteModel> {\n";
3099b2a1bcfSAlex Zinenko   os << "  public:\n";
3109c8fe394SAlex Zinenko   os << "    using ConcreteEntity = " << valueTemplate << ";\n";
3119b2a1bcfSAlex Zinenko 
3129b2a1bcfSAlex Zinenko   // Emit declarations for methods that have default implementations. Other
3139b2a1bcfSAlex Zinenko   // methods are expected to be implemented by the concrete derived model.
3149b2a1bcfSAlex Zinenko   for (auto &method : interface.getMethods()) {
3159b2a1bcfSAlex Zinenko     if (!method.getDefaultImplementation())
3169b2a1bcfSAlex Zinenko       continue;
3179b2a1bcfSAlex Zinenko     os << "    ";
3189b2a1bcfSAlex Zinenko     if (method.isStatic())
3199b2a1bcfSAlex Zinenko       os << "static ";
3209b2a1bcfSAlex Zinenko     emitCPPType(method.getReturnType(), os);
3219b2a1bcfSAlex Zinenko     os << method.getName() << "(";
3229b2a1bcfSAlex Zinenko     if (!method.isStatic()) {
3239b2a1bcfSAlex Zinenko       emitCPPType(valueType, os);
3249b2a1bcfSAlex Zinenko       os << "tablegen_opaque_val";
3259b2a1bcfSAlex Zinenko       if (!method.arg_empty())
3269b2a1bcfSAlex Zinenko         os << ", ";
3279b2a1bcfSAlex Zinenko     }
3289b2a1bcfSAlex Zinenko     llvm::interleaveComma(method.getArguments(), os,
3299b2a1bcfSAlex Zinenko                           [&](const InterfaceMethod::Argument &arg) {
3309b2a1bcfSAlex Zinenko                             emitCPPType(arg.type, os);
3319b2a1bcfSAlex Zinenko                             os << arg.name;
3329b2a1bcfSAlex Zinenko                           });
3339b2a1bcfSAlex Zinenko     os << ")";
3349b2a1bcfSAlex Zinenko     if (!method.isStatic())
3359b2a1bcfSAlex Zinenko       os << " const";
3369b2a1bcfSAlex Zinenko     os << ";\n";
3379b2a1bcfSAlex Zinenko   }
3389b2a1bcfSAlex Zinenko   os << "  };\n";
339d905c103SMehdi Amini }
34088f25bdaSAlex Zinenko 
34178fdbdbfSMehdi Amini void InterfaceGenerator::emitModelMethodsDef(const Interface &interface) {
3425e4eec98SAlex Zinenko   llvm::SmallVector<StringRef, 2> namespaces;
3435e4eec98SAlex Zinenko   llvm::SplitString(interface.getCppNamespace(), namespaces, "::");
3445e4eec98SAlex Zinenko   for (StringRef ns : namespaces)
3455e4eec98SAlex Zinenko     os << "namespace " << ns << " {\n";
3465e4eec98SAlex Zinenko 
34788f25bdaSAlex Zinenko   for (auto &method : interface.getMethods()) {
34888f25bdaSAlex Zinenko     os << "template<typename " << valueTemplate << ">\n";
34988f25bdaSAlex Zinenko     emitCPPType(method.getReturnType(), os);
35088f25bdaSAlex Zinenko     os << "detail::" << interface.getName() << "InterfaceTraits::Model<"
35188f25bdaSAlex Zinenko        << valueTemplate << ">::";
3522e2cdd0aSRiver Riddle     emitMethodNameAndArgs(method, os, valueType,
353ef728eafSRiver Riddle                           /*addThisArg=*/!method.isStatic(),
354ef728eafSRiver Riddle                           /*addConst=*/false);
355ef728eafSRiver Riddle     os << " {\n  ";
3562e2cdd0aSRiver Riddle 
3572e2cdd0aSRiver Riddle     // Check for a provided body to the function.
3583cfe412eSFangrui Song     if (std::optional<StringRef> body = method.getBody()) {
3592e2cdd0aSRiver Riddle       if (method.isStatic())
3602e2cdd0aSRiver Riddle         os << body->trim();
3612e2cdd0aSRiver Riddle       else
3622e2cdd0aSRiver Riddle         os << tblgen::tgfmt(body->trim(), &nonStaticMethodFmt);
3632e2cdd0aSRiver Riddle       os << "\n}\n";
3642e2cdd0aSRiver Riddle       continue;
3652e2cdd0aSRiver Riddle     }
3662e2cdd0aSRiver Riddle 
3672e2cdd0aSRiver Riddle     // Forward to the method on the concrete operation type.
3682e2cdd0aSRiver Riddle     if (method.isStatic())
3692e2cdd0aSRiver Riddle       os << "return " << valueTemplate << "::";
3702e2cdd0aSRiver Riddle     else
3712e2cdd0aSRiver Riddle       os << tblgen::tgfmt("return $_self.", &nonStaticMethodFmt);
3722e2cdd0aSRiver Riddle 
3732e2cdd0aSRiver Riddle     // Add the arguments to the call.
3742e2cdd0aSRiver Riddle     os << method.getName() << '(';
3752e2cdd0aSRiver Riddle     llvm::interleaveComma(
3762e2cdd0aSRiver Riddle         method.getArguments(), os,
3772e2cdd0aSRiver Riddle         [&](const InterfaceMethod::Argument &arg) { os << arg.name; });
3782e2cdd0aSRiver Riddle     os << ");\n}\n";
3792e2cdd0aSRiver Riddle   }
380d905c103SMehdi Amini 
381d905c103SMehdi Amini   for (auto &method : interface.getMethods()) {
382d905c103SMehdi Amini     os << "template<typename " << valueTemplate << ">\n";
383d905c103SMehdi Amini     emitCPPType(method.getReturnType(), os);
384d905c103SMehdi Amini     os << "detail::" << interface.getName() << "InterfaceTraits::FallbackModel<"
385d905c103SMehdi Amini        << valueTemplate << ">::";
386d905c103SMehdi Amini     emitMethodNameAndArgs(method, os, valueType,
387d905c103SMehdi Amini                           /*addThisArg=*/!method.isStatic(),
388d905c103SMehdi Amini                           /*addConst=*/false);
389d905c103SMehdi Amini     os << " {\n  ";
390d905c103SMehdi Amini 
391d905c103SMehdi Amini     // Forward to the method on the concrete Model implementation.
392d905c103SMehdi Amini     if (method.isStatic())
393d905c103SMehdi Amini       os << "return " << valueTemplate << "::";
394d905c103SMehdi Amini     else
395d905c103SMehdi Amini       os << "return static_cast<const " << valueTemplate << " *>(impl)->";
396d905c103SMehdi Amini 
397d905c103SMehdi Amini     // Add the arguments to the call.
398d905c103SMehdi Amini     os << method.getName() << '(';
399d905c103SMehdi Amini     if (!method.isStatic())
400d905c103SMehdi Amini       os << "tablegen_opaque_val" << (method.arg_empty() ? "" : ", ");
401d905c103SMehdi Amini     llvm::interleaveComma(
402d905c103SMehdi Amini         method.getArguments(), os,
403d905c103SMehdi Amini         [&](const InterfaceMethod::Argument &arg) { os << arg.name; });
404d905c103SMehdi Amini     os << ");\n}\n";
405d905c103SMehdi Amini   }
4069b2a1bcfSAlex Zinenko 
4079b2a1bcfSAlex Zinenko   // Emit default implementations for the external model.
4089b2a1bcfSAlex Zinenko   for (auto &method : interface.getMethods()) {
4099b2a1bcfSAlex Zinenko     if (!method.getDefaultImplementation())
4109b2a1bcfSAlex Zinenko       continue;
4119b2a1bcfSAlex Zinenko     os << "template<typename ConcreteModel, typename " << valueTemplate
4129b2a1bcfSAlex Zinenko        << ">\n";
4139b2a1bcfSAlex Zinenko     emitCPPType(method.getReturnType(), os);
4149b2a1bcfSAlex Zinenko     os << "detail::" << interface.getName()
4159b2a1bcfSAlex Zinenko        << "InterfaceTraits::ExternalModel<ConcreteModel, " << valueTemplate
4169b2a1bcfSAlex Zinenko        << ">::";
4179b2a1bcfSAlex Zinenko 
4189b2a1bcfSAlex Zinenko     os << method.getName() << "(";
4199b2a1bcfSAlex Zinenko     if (!method.isStatic()) {
4209b2a1bcfSAlex Zinenko       emitCPPType(valueType, os);
4219b2a1bcfSAlex Zinenko       os << "tablegen_opaque_val";
4229b2a1bcfSAlex Zinenko       if (!method.arg_empty())
4239b2a1bcfSAlex Zinenko         os << ", ";
4249b2a1bcfSAlex Zinenko     }
4259b2a1bcfSAlex Zinenko     llvm::interleaveComma(method.getArguments(), os,
4269b2a1bcfSAlex Zinenko                           [&](const InterfaceMethod::Argument &arg) {
4279b2a1bcfSAlex Zinenko                             emitCPPType(arg.type, os);
4289b2a1bcfSAlex Zinenko                             os << arg.name;
4299b2a1bcfSAlex Zinenko                           });
4309b2a1bcfSAlex Zinenko     os << ")";
4319b2a1bcfSAlex Zinenko     if (!method.isStatic())
4329b2a1bcfSAlex Zinenko       os << " const";
4339b2a1bcfSAlex Zinenko 
4349b2a1bcfSAlex Zinenko     os << " {\n";
4359b2a1bcfSAlex Zinenko 
4369b2a1bcfSAlex Zinenko     // Use the empty context for static methods.
4379b2a1bcfSAlex Zinenko     tblgen::FmtContext ctx;
4389b2a1bcfSAlex Zinenko     os << tblgen::tgfmt(method.getDefaultImplementation()->trim(),
4399b2a1bcfSAlex Zinenko                         method.isStatic() ? &ctx : &nonStaticMethodFmt);
4409b2a1bcfSAlex Zinenko     os << "\n}\n";
4419b2a1bcfSAlex Zinenko   }
4425e4eec98SAlex Zinenko 
4435e4eec98SAlex Zinenko   for (StringRef ns : llvm::reverse(namespaces))
4445e4eec98SAlex Zinenko     os << "} // namespace " << ns << "\n";
4452e2cdd0aSRiver Riddle }
4462e2cdd0aSRiver Riddle 
44778fdbdbfSMehdi Amini void InterfaceGenerator::emitTraitDecl(const Interface &interface,
4482e2cdd0aSRiver Riddle                                        StringRef interfaceName,
4492e2cdd0aSRiver Riddle                                        StringRef interfaceTraitsName) {
4502e2cdd0aSRiver Riddle   os << llvm::formatv("  template <typename {3}>\n"
4512e2cdd0aSRiver Riddle                       "  struct {0}Trait : public ::mlir::{2}<{0},"
4522e2cdd0aSRiver Riddle                       " detail::{1}>::Trait<{3}> {{\n",
4532e2cdd0aSRiver Riddle                       interfaceName, interfaceTraitsName, interfaceBaseType,
4542e2cdd0aSRiver Riddle                       valueTemplate);
4552e2cdd0aSRiver Riddle 
4562e2cdd0aSRiver Riddle   // Insert the default implementation for any methods.
4572e2cdd0aSRiver Riddle   bool isOpInterface = isa<OpInterface>(interface);
4582e2cdd0aSRiver Riddle   for (auto &method : interface.getMethods()) {
4592e2cdd0aSRiver Riddle     // Flag interface methods named verifyTrait.
4602e2cdd0aSRiver Riddle     if (method.getName() == "verifyTrait")
4612e2cdd0aSRiver Riddle       PrintFatalError(
4622e2cdd0aSRiver Riddle           formatv("'verifyTrait' method cannot be specified as interface "
4632e2cdd0aSRiver Riddle                   "method for '{0}'; use the 'verify' field instead",
4642e2cdd0aSRiver Riddle                   interfaceName));
4652e2cdd0aSRiver Riddle     auto defaultImpl = method.getDefaultImplementation();
4662e2cdd0aSRiver Riddle     if (!defaultImpl)
4672e2cdd0aSRiver Riddle       continue;
4682e2cdd0aSRiver Riddle 
4692e2ad539SAlex Zinenko     emitInterfaceMethodDoc(method, os, "    ");
4702e2cdd0aSRiver Riddle     os << "    " << (method.isStatic() ? "static " : "");
4712e2cdd0aSRiver Riddle     emitCPPType(method.getReturnType(), os);
4722e2cdd0aSRiver Riddle     emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
4738ed88559SAlex Zinenko                           /*addConst=*/!isOpInterface && !method.isStatic());
4742e2cdd0aSRiver Riddle     os << " {\n      " << tblgen::tgfmt(defaultImpl->trim(), &traitMethodFmt)
4752e2cdd0aSRiver Riddle        << "\n    }\n";
4762e2cdd0aSRiver Riddle   }
4772e2cdd0aSRiver Riddle 
4782e2cdd0aSRiver Riddle   if (auto verify = interface.getVerify()) {
4792e2cdd0aSRiver Riddle     assert(isa<OpInterface>(interface) && "only OpInterface supports 'verify'");
4802e2cdd0aSRiver Riddle 
4812e2cdd0aSRiver Riddle     tblgen::FmtContext verifyCtx;
4825cdc2bbcSRiver Riddle     verifyCtx.addSubst("_op", "op");
4839445b396SChia-hung Duan     os << llvm::formatv(
484db791b27SRamkumar Ramachandra               "    static ::llvm::LogicalResult {0}(::mlir::Operation *op) ",
4859445b396SChia-hung Duan               (interface.verifyWithRegions() ? "verifyRegionTrait"
4869445b396SChia-hung Duan                                              : "verifyTrait"))
4879445b396SChia-hung Duan        << "{\n      " << tblgen::tgfmt(verify->trim(), &verifyCtx)
4889445b396SChia-hung Duan        << "\n    }\n";
4892e2cdd0aSRiver Riddle   }
4902e2cdd0aSRiver Riddle   if (auto extraTraitDecls = interface.getExtraTraitClassDeclaration())
4912e2cdd0aSRiver Riddle     os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";
492a60e83feSRiver Riddle   if (auto extraTraitDecls = interface.getExtraSharedClassDeclaration())
493a60e83feSRiver Riddle     os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";
4942e2cdd0aSRiver Riddle 
4952e2cdd0aSRiver Riddle   os << "  };\n";
4962e2cdd0aSRiver Riddle }
4972e2cdd0aSRiver Riddle 
49883a635c0SRiver Riddle static void emitInterfaceDeclMethods(const Interface &interface,
49983a635c0SRiver Riddle                                      raw_ostream &os, StringRef valueType,
50083a635c0SRiver Riddle                                      bool isOpInterface,
50183a635c0SRiver Riddle                                      tblgen::FmtContext &extraDeclsFmt) {
50283a635c0SRiver Riddle   for (auto &method : interface.getMethods()) {
50383a635c0SRiver Riddle     emitInterfaceMethodDoc(method, os, "  ");
50483a635c0SRiver Riddle     emitCPPType(method.getReturnType(), os << "  ");
50583a635c0SRiver Riddle     emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
50683a635c0SRiver Riddle                           /*addConst=*/!isOpInterface);
50783a635c0SRiver Riddle     os << ";\n";
50883a635c0SRiver Riddle   }
50983a635c0SRiver Riddle 
51083a635c0SRiver Riddle   // Emit any extra declarations.
51183a635c0SRiver Riddle   if (std::optional<StringRef> extraDecls =
51283a635c0SRiver Riddle           interface.getExtraClassDeclaration())
51383a635c0SRiver Riddle     os << extraDecls->rtrim() << "\n";
51483a635c0SRiver Riddle   if (std::optional<StringRef> extraDecls =
51583a635c0SRiver Riddle           interface.getExtraSharedClassDeclaration())
51683a635c0SRiver Riddle     os << tblgen::tgfmt(extraDecls->rtrim(), &extraDeclsFmt) << "\n";
51783a635c0SRiver Riddle }
51883a635c0SRiver Riddle 
51978fdbdbfSMehdi Amini void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {
520572c2905SRiver Riddle   llvm::SmallVector<StringRef, 2> namespaces;
521572c2905SRiver Riddle   llvm::SplitString(interface.getCppNamespace(), namespaces, "::");
522572c2905SRiver Riddle   for (StringRef ns : namespaces)
523572c2905SRiver Riddle     os << "namespace " << ns << " {\n";
524572c2905SRiver Riddle 
5252e2cdd0aSRiver Riddle   StringRef interfaceName = interface.getName();
5262e2cdd0aSRiver Riddle   auto interfaceTraitsName = (interfaceName + "InterfaceTraits").str();
5272e2cdd0aSRiver Riddle 
52888f25bdaSAlex Zinenko   // Emit a forward declaration of the interface class so that it becomes usable
52988f25bdaSAlex Zinenko   // in the signature of its methods.
53088f25bdaSAlex Zinenko   os << "class " << interfaceName << ";\n";
53188f25bdaSAlex Zinenko 
5322e2cdd0aSRiver Riddle   // Emit the traits struct containing the concept and model declarations.
5332e2cdd0aSRiver Riddle   os << "namespace detail {\n"
5342e2cdd0aSRiver Riddle      << "struct " << interfaceTraitsName << " {\n";
5352e2cdd0aSRiver Riddle   emitConceptDecl(interface);
5362e2cdd0aSRiver Riddle   emitModelDecl(interface);
53739c739eeSAndrei Golubev   os << "};\n";
538a4f81b20SAlex Zinenko 
539a4f81b20SAlex Zinenko   // Emit the derived trait for the interface.
540a4f81b20SAlex Zinenko   os << "template <typename " << valueTemplate << ">\n";
541a4f81b20SAlex Zinenko   os << "struct " << interface.getName() << "Trait;\n";
542a4f81b20SAlex Zinenko 
543be0a7e9fSMehdi Amini   os << "\n} // namespace detail\n";
5442e2cdd0aSRiver Riddle 
5452e2cdd0aSRiver Riddle   // Emit the main interface class declaration.
5462e2cdd0aSRiver Riddle   os << llvm::formatv("class {0} : public ::mlir::{3}<{1}, detail::{2}> {\n"
5472e2cdd0aSRiver Riddle                       "public:\n"
5482e2cdd0aSRiver Riddle                       "  using ::mlir::{3}<{1}, detail::{2}>::{3};\n",
5492e2cdd0aSRiver Riddle                       interfaceName, interfaceName, interfaceTraitsName,
5502e2cdd0aSRiver Riddle                       interfaceBaseType);
5512e2cdd0aSRiver Riddle 
552a4f81b20SAlex Zinenko   // Emit a utility wrapper trait class.
553a4f81b20SAlex Zinenko   os << llvm::formatv("  template <typename {1}>\n"
554a4f81b20SAlex Zinenko                       "  struct Trait : public detail::{0}Trait<{1}> {{};\n",
555a4f81b20SAlex Zinenko                       interfaceName, valueTemplate);
5562e2cdd0aSRiver Riddle 
5572e2cdd0aSRiver Riddle   // Insert the method declarations.
5582e2cdd0aSRiver Riddle   bool isOpInterface = isa<OpInterface>(interface);
55983a635c0SRiver Riddle   emitInterfaceDeclMethods(interface, os, valueType, isOpInterface,
56083a635c0SRiver Riddle                            extraDeclsFmt);
5612e2cdd0aSRiver Riddle 
56283a635c0SRiver Riddle   // Insert the method declarations for base classes.
56383a635c0SRiver Riddle   for (auto &base : interface.getBaseInterfaces()) {
56483a635c0SRiver Riddle     std::string baseQualName = base.getFullyQualifiedName();
56583a635c0SRiver Riddle     os << "  //"
56683a635c0SRiver Riddle           "===---------------------------------------------------------------"
56783a635c0SRiver Riddle           "-===//\n"
56883a635c0SRiver Riddle        << "  // Inherited from " << baseQualName << "\n"
56983a635c0SRiver Riddle        << "  //"
57083a635c0SRiver Riddle           "===---------------------------------------------------------------"
57183a635c0SRiver Riddle           "-===//\n\n";
57283a635c0SRiver Riddle 
57383a635c0SRiver Riddle     // Allow implicit conversion to the base interface.
57483a635c0SRiver Riddle     os << "  operator " << baseQualName << " () const {\n"
575cedeb31eSMarkus Böck        << "    if (!*this) return nullptr;\n"
57683a635c0SRiver Riddle        << "    return " << baseQualName << "(*this, getImpl()->impl"
57783a635c0SRiver Riddle        << base.getName() << ");\n"
57883a635c0SRiver Riddle        << "  }\n\n";
57983a635c0SRiver Riddle 
58083a635c0SRiver Riddle     // Inherit the base interface's methods.
58183a635c0SRiver Riddle     emitInterfaceDeclMethods(base, os, valueType, isOpInterface, extraDeclsFmt);
58283a635c0SRiver Riddle   }
5832e2cdd0aSRiver Riddle 
5845cdc2bbcSRiver Riddle   // Emit classof code if necessary.
5855cdc2bbcSRiver Riddle   if (std::optional<StringRef> extraClassOf = interface.getExtraClassOf()) {
5865cdc2bbcSRiver Riddle     auto extraClassOfFmt = tblgen::FmtContext();
587edae8f6cSMarkus Böck     extraClassOfFmt.addSubst(substVar, "odsInterfaceInstance");
5885cdc2bbcSRiver Riddle     os << "  static bool classof(" << valueType << " base) {\n"
589d01f559cSJakub Kuderski        << "    auto* interface = getInterfaceFor(base);\n"
590d01f559cSJakub Kuderski        << "    if (!interface)\n"
5915cdc2bbcSRiver Riddle           "      return false;\n"
592d01f559cSJakub Kuderski           "    " << interfaceName << " odsInterfaceInstance(base, interface);\n"
5935cdc2bbcSRiver Riddle        << "    " << tblgen::tgfmt(extraClassOf->trim(), &extraClassOfFmt)
5945cdc2bbcSRiver Riddle        << "\n  }\n";
5955cdc2bbcSRiver Riddle   }
5965cdc2bbcSRiver Riddle 
5972e2cdd0aSRiver Riddle   os << "};\n";
598572c2905SRiver Riddle 
599a4f81b20SAlex Zinenko   os << "namespace detail {\n";
600a4f81b20SAlex Zinenko   emitTraitDecl(interface, interfaceName, interfaceTraitsName);
601a4f81b20SAlex Zinenko   os << "}// namespace detail\n";
602a4f81b20SAlex Zinenko 
603572c2905SRiver Riddle   for (StringRef ns : llvm::reverse(namespaces))
604572c2905SRiver Riddle     os << "} // namespace " << ns << "\n";
6052e2cdd0aSRiver Riddle }
6062e2cdd0aSRiver Riddle 
6072e2cdd0aSRiver Riddle bool InterfaceGenerator::emitInterfaceDecls() {
6082e2cdd0aSRiver Riddle   llvm::emitSourceFileHeader("Interface Declarations", os);
6095f036799SMatthias Springer   // Sort according to ID, so defs are emitted in the order in which they appear
6105f036799SMatthias Springer   // in the Tablegen file.
611bccd37f6SRahul Joshi   std::vector<const Record *> sortedDefs(defs);
612bccd37f6SRahul Joshi   llvm::sort(sortedDefs, [](const Record *lhs, const Record *rhs) {
6135f036799SMatthias Springer     return lhs->getID() < rhs->getID();
6145f036799SMatthias Springer   });
615bccd37f6SRahul Joshi   for (const Record *def : sortedDefs)
6162e2cdd0aSRiver Riddle     emitInterfaceDecl(Interface(def));
617bccd37f6SRahul Joshi   for (const Record *def : sortedDefs)
6185e4eec98SAlex Zinenko     emitModelMethodsDef(Interface(def));
6192e2cdd0aSRiver Riddle   return false;
6202e2cdd0aSRiver Riddle }
6212e2cdd0aSRiver Riddle 
6222e2cdd0aSRiver Riddle //===----------------------------------------------------------------------===//
6232e2cdd0aSRiver Riddle // GEN: Interface documentation
6242e2cdd0aSRiver Riddle //===----------------------------------------------------------------------===//
6252e2cdd0aSRiver Riddle 
626bccd37f6SRahul Joshi static void emitInterfaceDoc(const Record &interfaceDef, raw_ostream &os) {
6272e2cdd0aSRiver Riddle   Interface interface(&interfaceDef);
628635544fcSRiver Riddle 
629635544fcSRiver Riddle   // Emit the interface name followed by the description.
630a8837149SAlex Zinenko   os << "## " << interface.getName() << " (`" << interfaceDef.getName()
631a8837149SAlex Zinenko      << "`)\n\n";
632635544fcSRiver Riddle   if (auto description = interface.getDescription())
633635544fcSRiver Riddle     mlir::tblgen::emitDescription(*description, os);
634635544fcSRiver Riddle 
635635544fcSRiver Riddle   // Emit the methods required by the interface.
636635544fcSRiver Riddle   os << "\n### Methods:\n";
637635544fcSRiver Riddle   for (const auto &method : interface.getMethods()) {
638635544fcSRiver Riddle     // Emit the method name.
639635544fcSRiver Riddle     os << "#### `" << method.getName() << "`\n\n```c++\n";
640635544fcSRiver Riddle 
641635544fcSRiver Riddle     // Emit the method signature.
642635544fcSRiver Riddle     if (method.isStatic())
643635544fcSRiver Riddle       os << "static ";
644635544fcSRiver Riddle     emitCPPType(method.getReturnType(), os) << method.getName() << '(';
6452f21a579SRiver Riddle     llvm::interleaveComma(method.getArguments(), os,
6462e2cdd0aSRiver Riddle                           [&](const InterfaceMethod::Argument &arg) {
647635544fcSRiver Riddle                             emitCPPType(arg.type, os) << arg.name;
648635544fcSRiver Riddle                           });
649635544fcSRiver Riddle     os << ");\n```\n";
650635544fcSRiver Riddle 
651635544fcSRiver Riddle     // Emit the description.
652635544fcSRiver Riddle     if (auto description = method.getDescription())
653635544fcSRiver Riddle       mlir::tblgen::emitDescription(*description, os);
654635544fcSRiver Riddle 
6552e2cdd0aSRiver Riddle     // If the body is not provided, this method must be provided by the user.
656635544fcSRiver Riddle     if (!method.getBody())
657794056e8SSchuyler Eldridge       os << "\nNOTE: This method *must* be implemented by the user.";
658794056e8SSchuyler Eldridge 
659794056e8SSchuyler Eldridge     os << "\n\n";
660635544fcSRiver Riddle   }
661635544fcSRiver Riddle }
662635544fcSRiver Riddle 
6632e2cdd0aSRiver Riddle bool InterfaceGenerator::emitInterfaceDocs() {
664635544fcSRiver Riddle   os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
6652e2cdd0aSRiver Riddle   os << "# " << interfaceBaseType << " definitions\n";
666635544fcSRiver Riddle 
6672e2cdd0aSRiver Riddle   for (const auto *def : defs)
668635544fcSRiver Riddle     emitInterfaceDoc(*def, os);
669635544fcSRiver Riddle   return false;
670635544fcSRiver Riddle }
671635544fcSRiver Riddle 
672635544fcSRiver Riddle //===----------------------------------------------------------------------===//
673635544fcSRiver Riddle // GEN: Interface registration hooks
674635544fcSRiver Riddle //===----------------------------------------------------------------------===//
675635544fcSRiver Riddle 
6762e2cdd0aSRiver Riddle namespace {
67749d840c3SMarius Brehler template <typename GeneratorT>
67849d840c3SMarius Brehler struct InterfaceGenRegistration {
67949d840c3SMarius Brehler   InterfaceGenRegistration(StringRef genArg, StringRef genDesc)
6802e2cdd0aSRiver Riddle       : genDeclArg(("gen-" + genArg + "-interface-decls").str()),
6812e2cdd0aSRiver Riddle         genDefArg(("gen-" + genArg + "-interface-defs").str()),
6822e2cdd0aSRiver Riddle         genDocArg(("gen-" + genArg + "-interface-docs").str()),
68349d840c3SMarius Brehler         genDeclDesc(("Generate " + genDesc + " interface declarations").str()),
68449d840c3SMarius Brehler         genDefDesc(("Generate " + genDesc + " interface definitions").str()),
68549d840c3SMarius Brehler         genDocDesc(("Generate " + genDesc + " interface documentation").str()),
68649d840c3SMarius Brehler         genDecls(genDeclArg, genDeclDesc,
687bccd37f6SRahul Joshi                  [](const RecordKeeper &records, raw_ostream &os) {
6882e2cdd0aSRiver Riddle                    return GeneratorT(records, os).emitInterfaceDecls();
6892e2cdd0aSRiver Riddle                  }),
69049d840c3SMarius Brehler         genDefs(genDefArg, genDefDesc,
691bccd37f6SRahul Joshi                 [](const RecordKeeper &records, raw_ostream &os) {
6922e2cdd0aSRiver Riddle                   return GeneratorT(records, os).emitInterfaceDefs();
6932e2cdd0aSRiver Riddle                 }),
69449d840c3SMarius Brehler         genDocs(genDocArg, genDocDesc,
695bccd37f6SRahul Joshi                 [](const RecordKeeper &records, raw_ostream &os) {
6962e2cdd0aSRiver Riddle                   return GeneratorT(records, os).emitInterfaceDocs();
6972e2cdd0aSRiver Riddle                 }) {}
698b9377d7eSRiver Riddle 
6992e2cdd0aSRiver Riddle   std::string genDeclArg, genDefArg, genDocArg;
70049d840c3SMarius Brehler   std::string genDeclDesc, genDefDesc, genDocDesc;
7012e2cdd0aSRiver Riddle   mlir::GenRegistration genDecls, genDefs, genDocs;
7022e2cdd0aSRiver Riddle };
703be0a7e9fSMehdi Amini } // namespace
704635544fcSRiver Riddle 
70549d840c3SMarius Brehler static InterfaceGenRegistration<AttrInterfaceGenerator> attrGen("attr",
70649d840c3SMarius Brehler                                                                 "attribute");
70749d840c3SMarius Brehler static InterfaceGenRegistration<OpInterfaceGenerator> opGen("op", "op");
70849d840c3SMarius Brehler static InterfaceGenRegistration<TypeInterfaceGenerator> typeGen("type", "type");
709