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