1 //===- OpInterfacesGen.cpp - MLIR op interface utility generator ----------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // OpInterfacesGen generates definitions for operation interfaces.
11 //===----------------------------------------------------------------------===//
13 #include "DocGenUtilities.h"
14 #include "mlir/TableGen/Format.h"
15 #include "mlir/TableGen/GenInfo.h"
16 #include "mlir/TableGen/Interfaces.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/Support/FormatVariadic.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include "llvm/TableGen/Error.h"
22 #include "llvm/TableGen/Record.h"
23 #include "llvm/TableGen/TableGenBackend.h"
26 using mlir::tblgen::Interface
;
27 using mlir::tblgen::InterfaceMethod
;
28 using mlir::tblgen::OpInterface
;
30 /// Emit a string corresponding to a C++ type, followed by a space if necessary.
31 static raw_ostream
&emitCPPType(StringRef type
, raw_ostream
&os
) {
34 if (type
.back() != '&' && type
.back() != '*')
39 /// Emit the method name and argument list for the given method. If 'addThisArg'
40 /// is true, then an argument is added to the beginning of the argument list for
41 /// the concrete value.
42 static void emitMethodNameAndArgs(const InterfaceMethod
&method
,
43 raw_ostream
&os
, StringRef valueType
,
44 bool addThisArg
, bool addConst
) {
45 os
<< method
.getName() << '(';
49 os
<< "const Concept *impl, ";
50 emitCPPType(valueType
, os
)
51 << "tablegen_opaque_val" << (method
.arg_empty() ? "" : ", ");
53 llvm::interleaveComma(method
.getArguments(), os
,
54 [&](const InterfaceMethod::Argument
&arg
) {
55 os
<< arg
.type
<< " " << arg
.name
;
62 /// Get an array of all OpInterface definitions but exclude those subclassing
63 /// "DeclareOpInterfaceMethods".
64 static std::vector
<llvm::Record
*>
65 getAllInterfaceDefinitions(const llvm::RecordKeeper
&recordKeeper
,
67 std::vector
<llvm::Record
*> defs
=
68 recordKeeper
.getAllDerivedDefinitions((name
+ "Interface").str());
70 std::string declareName
= ("Declare" + name
+ "InterfaceMethods").str();
71 llvm::erase_if(defs
, [&](const llvm::Record
*def
) {
72 // Ignore any "declare methods" interfaces.
73 if (def
->isSubClassOf(declareName
))
75 // Ignore interfaces defined outside of the top-level file.
76 return llvm::SrcMgr
.FindBufferContainingLoc(def
->getLoc()[0]) !=
77 llvm::SrcMgr
.getMainFileID();
83 /// This struct is the base generator used when processing tablegen interfaces.
84 class InterfaceGenerator
{
86 bool emitInterfaceDefs();
87 bool emitInterfaceDecls();
88 bool emitInterfaceDocs();
91 InterfaceGenerator(std::vector
<llvm::Record
*> &&defs
, raw_ostream
&os
)
92 : defs(std::move(defs
)), os(os
) {}
94 void emitConceptDecl(const Interface
&interface
);
95 void emitModelDecl(const Interface
&interface
);
96 void emitModelMethodsDef(const Interface
&interface
);
97 void emitTraitDecl(const Interface
&interface
, StringRef interfaceName
,
98 StringRef interfaceTraitsName
);
99 void emitInterfaceDecl(const Interface
&interface
);
101 /// The set of interface records to emit.
102 std::vector
<llvm::Record
*> defs
;
103 // The stream to emit to.
105 /// The C++ value type of the interface, e.g. Operation*.
107 /// The C++ base interface type.
108 StringRef interfaceBaseType
;
109 /// The name of the typename for the value template.
110 StringRef valueTemplate
;
111 /// The name of the substituion variable for the value.
113 /// The format context to use for methods.
114 tblgen::FmtContext nonStaticMethodFmt
;
115 tblgen::FmtContext traitMethodFmt
;
116 tblgen::FmtContext extraDeclsFmt
;
119 /// A specialized generator for attribute interfaces.
120 struct AttrInterfaceGenerator
: public InterfaceGenerator
{
121 AttrInterfaceGenerator(const llvm::RecordKeeper
&records
, raw_ostream
&os
)
122 : InterfaceGenerator(getAllInterfaceDefinitions(records
, "Attr"), os
) {
123 valueType
= "::mlir::Attribute";
124 interfaceBaseType
= "AttributeInterface";
125 valueTemplate
= "ConcreteAttr";
127 StringRef castCode
= "(::llvm::cast<ConcreteAttr>(tablegen_opaque_val))";
128 nonStaticMethodFmt
.addSubst(substVar
, castCode
).withSelf(castCode
);
129 traitMethodFmt
.addSubst(substVar
,
130 "(*static_cast<const ConcreteAttr *>(this))");
131 extraDeclsFmt
.addSubst(substVar
, "(*this)");
134 /// A specialized generator for operation interfaces.
135 struct OpInterfaceGenerator
: public InterfaceGenerator
{
136 OpInterfaceGenerator(const llvm::RecordKeeper
&records
, raw_ostream
&os
)
137 : InterfaceGenerator(getAllInterfaceDefinitions(records
, "Op"), os
) {
138 valueType
= "::mlir::Operation *";
139 interfaceBaseType
= "OpInterface";
140 valueTemplate
= "ConcreteOp";
142 StringRef castCode
= "(llvm::cast<ConcreteOp>(tablegen_opaque_val))";
143 nonStaticMethodFmt
.addSubst("_this", "impl")
144 .addSubst(substVar
, castCode
)
146 traitMethodFmt
.addSubst(substVar
, "(*static_cast<ConcreteOp *>(this))");
147 extraDeclsFmt
.addSubst(substVar
, "(*this)");
150 /// A specialized generator for type interfaces.
151 struct TypeInterfaceGenerator
: public InterfaceGenerator
{
152 TypeInterfaceGenerator(const llvm::RecordKeeper
&records
, raw_ostream
&os
)
153 : InterfaceGenerator(getAllInterfaceDefinitions(records
, "Type"), os
) {
154 valueType
= "::mlir::Type";
155 interfaceBaseType
= "TypeInterface";
156 valueTemplate
= "ConcreteType";
158 StringRef castCode
= "(::llvm::cast<ConcreteType>(tablegen_opaque_val))";
159 nonStaticMethodFmt
.addSubst(substVar
, castCode
).withSelf(castCode
);
160 traitMethodFmt
.addSubst(substVar
,
161 "(*static_cast<const ConcreteType *>(this))");
162 extraDeclsFmt
.addSubst(substVar
, "(*this)");
167 //===----------------------------------------------------------------------===//
168 // GEN: Interface definitions
169 //===----------------------------------------------------------------------===//
171 static void emitInterfaceMethodDoc(const InterfaceMethod
&method
,
172 raw_ostream
&os
, StringRef prefix
= "") {
173 if (std::optional
<StringRef
> description
= method
.getDescription())
174 tblgen::emitDescriptionComment(*description
, os
, prefix
);
176 static void emitInterfaceDefMethods(StringRef interfaceQualName
,
177 const Interface
&interface
,
178 StringRef valueType
, const Twine
&implValue
,
179 raw_ostream
&os
, bool isOpInterface
) {
180 for (auto &method
: interface
.getMethods()) {
181 emitInterfaceMethodDoc(method
, os
);
182 emitCPPType(method
.getReturnType(), os
);
183 os
<< interfaceQualName
<< "::";
184 emitMethodNameAndArgs(method
, os
, valueType
, /*addThisArg=*/false,
185 /*addConst=*/!isOpInterface
);
187 // Forward to the method on the concrete operation type.
188 os
<< " {\n return " << implValue
<< "->" << method
.getName() << '(';
189 if (!method
.isStatic()) {
190 os
<< implValue
<< ", ";
191 os
<< (isOpInterface
? "getOperation()" : "*this");
192 os
<< (method
.arg_empty() ? "" : ", ");
194 llvm::interleaveComma(
195 method
.getArguments(), os
,
196 [&](const InterfaceMethod::Argument
&arg
) { os
<< arg
.name
; });
201 static void emitInterfaceDef(const Interface
&interface
, StringRef valueType
,
203 std::string interfaceQualNameStr
= interface
.getFullyQualifiedName();
204 StringRef interfaceQualName
= interfaceQualNameStr
;
205 interfaceQualName
.consume_front("::");
207 // Insert the method definitions.
208 bool isOpInterface
= isa
<OpInterface
>(interface
);
209 emitInterfaceDefMethods(interfaceQualName
, interface
, valueType
, "getImpl()",
212 // Insert the method definitions for base classes.
213 for (auto &base
: interface
.getBaseInterfaces()) {
214 emitInterfaceDefMethods(interfaceQualName
, base
, valueType
,
215 "getImpl()->impl" + base
.getName(), os
,
220 bool InterfaceGenerator::emitInterfaceDefs() {
221 llvm::emitSourceFileHeader("Interface Definitions", os
);
223 for (const auto *def
: defs
)
224 emitInterfaceDef(Interface(def
), valueType
, os
);
228 //===----------------------------------------------------------------------===//
229 // GEN: Interface declarations
230 //===----------------------------------------------------------------------===//
232 void InterfaceGenerator::emitConceptDecl(const Interface
&interface
) {
233 os
<< " struct Concept {\n";
235 // Insert each of the pure virtual concept methods.
236 os
<< " /// The methods defined by the interface.\n";
237 for (auto &method
: interface
.getMethods()) {
239 emitCPPType(method
.getReturnType(), os
);
240 os
<< "(*" << method
.getName() << ")(";
241 if (!method
.isStatic()) {
242 os
<< "const Concept *impl, ";
243 emitCPPType(valueType
, os
) << (method
.arg_empty() ? "" : ", ");
245 llvm::interleaveComma(
246 method
.getArguments(), os
,
247 [&](const InterfaceMethod::Argument
&arg
) { os
<< arg
.type
; });
251 // Insert a field containing a concept for each of the base interfaces.
252 auto baseInterfaces
= interface
.getBaseInterfaces();
253 if (!baseInterfaces
.empty()) {
254 os
<< " /// The base classes of this interface.\n";
255 for (const auto &base
: interface
.getBaseInterfaces()) {
256 os
<< " const " << base
.getFullyQualifiedName() << "::Concept *impl"
257 << base
.getName() << " = nullptr;\n";
260 // Define an "initialize" method that allows for the initialization of the
261 // base class concepts.
262 os
<< "\n void initializeInterfaceConcept(::mlir::detail::InterfaceMap "
263 "&interfaceMap) {\n";
264 std::string interfaceQualName
= interface
.getFullyQualifiedName();
265 for (const auto &base
: interface
.getBaseInterfaces()) {
266 StringRef baseName
= base
.getName();
267 std::string baseQualName
= base
.getFullyQualifiedName();
268 os
<< " impl" << baseName
<< " = interfaceMap.lookup<"
269 << baseQualName
<< ">();\n"
270 << " assert(impl" << baseName
<< " && \"`" << interfaceQualName
271 << "` expected its base interface `" << baseQualName
272 << "` to be registered\");\n";
280 void InterfaceGenerator::emitModelDecl(const Interface
&interface
) {
281 // Emit the basic model and the fallback model.
282 for (const char *modelClass
: {"Model", "FallbackModel"}) {
283 os
<< " template<typename " << valueTemplate
<< ">\n";
284 os
<< " class " << modelClass
<< " : public Concept {\n public:\n";
285 os
<< " using Interface = " << interface
.getFullyQualifiedName()
287 os
<< " " << modelClass
<< "() : Concept{";
288 llvm::interleaveComma(
289 interface
.getMethods(), os
,
290 [&](const InterfaceMethod
&method
) { os
<< method
.getName(); });
293 // Insert each of the virtual method overrides.
294 for (auto &method
: interface
.getMethods()) {
295 emitCPPType(method
.getReturnType(), os
<< " static inline ");
296 emitMethodNameAndArgs(method
, os
, valueType
,
297 /*addThisArg=*/!method
.isStatic(),
304 // Emit the template for the external model.
305 os
<< " template<typename ConcreteModel, typename " << valueTemplate
307 os
<< " class ExternalModel : public FallbackModel<ConcreteModel> {\n";
309 os
<< " using ConcreteEntity = " << valueTemplate
<< ";\n";
311 // Emit declarations for methods that have default implementations. Other
312 // methods are expected to be implemented by the concrete derived model.
313 for (auto &method
: interface
.getMethods()) {
314 if (!method
.getDefaultImplementation())
317 if (method
.isStatic())
319 emitCPPType(method
.getReturnType(), os
);
320 os
<< method
.getName() << "(";
321 if (!method
.isStatic()) {
322 emitCPPType(valueType
, os
);
323 os
<< "tablegen_opaque_val";
324 if (!method
.arg_empty())
327 llvm::interleaveComma(method
.getArguments(), os
,
328 [&](const InterfaceMethod::Argument
&arg
) {
329 emitCPPType(arg
.type
, os
);
333 if (!method
.isStatic())
340 void InterfaceGenerator::emitModelMethodsDef(const Interface
&interface
) {
341 llvm::SmallVector
<StringRef
, 2> namespaces
;
342 llvm::SplitString(interface
.getCppNamespace(), namespaces
, "::");
343 for (StringRef ns
: namespaces
)
344 os
<< "namespace " << ns
<< " {\n";
346 for (auto &method
: interface
.getMethods()) {
347 os
<< "template<typename " << valueTemplate
<< ">\n";
348 emitCPPType(method
.getReturnType(), os
);
349 os
<< "detail::" << interface
.getName() << "InterfaceTraits::Model<"
350 << valueTemplate
<< ">::";
351 emitMethodNameAndArgs(method
, os
, valueType
,
352 /*addThisArg=*/!method
.isStatic(),
356 // Check for a provided body to the function.
357 if (std::optional
<StringRef
> body
= method
.getBody()) {
358 if (method
.isStatic())
361 os
<< tblgen::tgfmt(body
->trim(), &nonStaticMethodFmt
);
366 // Forward to the method on the concrete operation type.
367 if (method
.isStatic())
368 os
<< "return " << valueTemplate
<< "::";
370 os
<< tblgen::tgfmt("return $_self.", &nonStaticMethodFmt
);
372 // Add the arguments to the call.
373 os
<< method
.getName() << '(';
374 llvm::interleaveComma(
375 method
.getArguments(), os
,
376 [&](const InterfaceMethod::Argument
&arg
) { os
<< arg
.name
; });
380 for (auto &method
: interface
.getMethods()) {
381 os
<< "template<typename " << valueTemplate
<< ">\n";
382 emitCPPType(method
.getReturnType(), os
);
383 os
<< "detail::" << interface
.getName() << "InterfaceTraits::FallbackModel<"
384 << valueTemplate
<< ">::";
385 emitMethodNameAndArgs(method
, os
, valueType
,
386 /*addThisArg=*/!method
.isStatic(),
390 // Forward to the method on the concrete Model implementation.
391 if (method
.isStatic())
392 os
<< "return " << valueTemplate
<< "::";
394 os
<< "return static_cast<const " << valueTemplate
<< " *>(impl)->";
396 // Add the arguments to the call.
397 os
<< method
.getName() << '(';
398 if (!method
.isStatic())
399 os
<< "tablegen_opaque_val" << (method
.arg_empty() ? "" : ", ");
400 llvm::interleaveComma(
401 method
.getArguments(), os
,
402 [&](const InterfaceMethod::Argument
&arg
) { os
<< arg
.name
; });
406 // Emit default implementations for the external model.
407 for (auto &method
: interface
.getMethods()) {
408 if (!method
.getDefaultImplementation())
410 os
<< "template<typename ConcreteModel, typename " << valueTemplate
412 emitCPPType(method
.getReturnType(), os
);
413 os
<< "detail::" << interface
.getName()
414 << "InterfaceTraits::ExternalModel<ConcreteModel, " << valueTemplate
417 os
<< method
.getName() << "(";
418 if (!method
.isStatic()) {
419 emitCPPType(valueType
, os
);
420 os
<< "tablegen_opaque_val";
421 if (!method
.arg_empty())
424 llvm::interleaveComma(method
.getArguments(), os
,
425 [&](const InterfaceMethod::Argument
&arg
) {
426 emitCPPType(arg
.type
, os
);
430 if (!method
.isStatic())
435 // Use the empty context for static methods.
436 tblgen::FmtContext ctx
;
437 os
<< tblgen::tgfmt(method
.getDefaultImplementation()->trim(),
438 method
.isStatic() ? &ctx
: &nonStaticMethodFmt
);
442 for (StringRef ns
: llvm::reverse(namespaces
))
443 os
<< "} // namespace " << ns
<< "\n";
446 void InterfaceGenerator::emitTraitDecl(const Interface
&interface
,
447 StringRef interfaceName
,
448 StringRef interfaceTraitsName
) {
449 os
<< llvm::formatv(" template <typename {3}>\n"
450 " struct {0}Trait : public ::mlir::{2}<{0},"
451 " detail::{1}>::Trait<{3}> {{\n",
452 interfaceName
, interfaceTraitsName
, interfaceBaseType
,
455 // Insert the default implementation for any methods.
456 bool isOpInterface
= isa
<OpInterface
>(interface
);
457 for (auto &method
: interface
.getMethods()) {
458 // Flag interface methods named verifyTrait.
459 if (method
.getName() == "verifyTrait")
461 formatv("'verifyTrait' method cannot be specified as interface "
462 "method for '{0}'; use the 'verify' field instead",
464 auto defaultImpl
= method
.getDefaultImplementation();
468 emitInterfaceMethodDoc(method
, os
, " ");
469 os
<< " " << (method
.isStatic() ? "static " : "");
470 emitCPPType(method
.getReturnType(), os
);
471 emitMethodNameAndArgs(method
, os
, valueType
, /*addThisArg=*/false,
472 /*addConst=*/!isOpInterface
&& !method
.isStatic());
473 os
<< " {\n " << tblgen::tgfmt(defaultImpl
->trim(), &traitMethodFmt
)
477 if (auto verify
= interface
.getVerify()) {
478 assert(isa
<OpInterface
>(interface
) && "only OpInterface supports 'verify'");
480 tblgen::FmtContext verifyCtx
;
481 verifyCtx
.addSubst("_op", "op");
483 " static ::llvm::LogicalResult {0}(::mlir::Operation *op) ",
484 (interface
.verifyWithRegions() ? "verifyRegionTrait"
486 << "{\n " << tblgen::tgfmt(verify
->trim(), &verifyCtx
)
489 if (auto extraTraitDecls
= interface
.getExtraTraitClassDeclaration())
490 os
<< tblgen::tgfmt(*extraTraitDecls
, &traitMethodFmt
) << "\n";
491 if (auto extraTraitDecls
= interface
.getExtraSharedClassDeclaration())
492 os
<< tblgen::tgfmt(*extraTraitDecls
, &traitMethodFmt
) << "\n";
497 static void emitInterfaceDeclMethods(const Interface
&interface
,
498 raw_ostream
&os
, StringRef valueType
,
500 tblgen::FmtContext
&extraDeclsFmt
) {
501 for (auto &method
: interface
.getMethods()) {
502 emitInterfaceMethodDoc(method
, os
, " ");
503 emitCPPType(method
.getReturnType(), os
<< " ");
504 emitMethodNameAndArgs(method
, os
, valueType
, /*addThisArg=*/false,
505 /*addConst=*/!isOpInterface
);
509 // Emit any extra declarations.
510 if (std::optional
<StringRef
> extraDecls
=
511 interface
.getExtraClassDeclaration())
512 os
<< extraDecls
->rtrim() << "\n";
513 if (std::optional
<StringRef
> extraDecls
=
514 interface
.getExtraSharedClassDeclaration())
515 os
<< tblgen::tgfmt(extraDecls
->rtrim(), &extraDeclsFmt
) << "\n";
518 void InterfaceGenerator::emitInterfaceDecl(const Interface
&interface
) {
519 llvm::SmallVector
<StringRef
, 2> namespaces
;
520 llvm::SplitString(interface
.getCppNamespace(), namespaces
, "::");
521 for (StringRef ns
: namespaces
)
522 os
<< "namespace " << ns
<< " {\n";
524 StringRef interfaceName
= interface
.getName();
525 auto interfaceTraitsName
= (interfaceName
+ "InterfaceTraits").str();
527 // Emit a forward declaration of the interface class so that it becomes usable
528 // in the signature of its methods.
529 os
<< "class " << interfaceName
<< ";\n";
531 // Emit the traits struct containing the concept and model declarations.
532 os
<< "namespace detail {\n"
533 << "struct " << interfaceTraitsName
<< " {\n";
534 emitConceptDecl(interface
);
535 emitModelDecl(interface
);
538 // Emit the derived trait for the interface.
539 os
<< "template <typename " << valueTemplate
<< ">\n";
540 os
<< "struct " << interface
.getName() << "Trait;\n";
542 os
<< "\n} // namespace detail\n";
544 // Emit the main interface class declaration.
545 os
<< llvm::formatv("class {0} : public ::mlir::{3}<{1}, detail::{2}> {\n"
547 " using ::mlir::{3}<{1}, detail::{2}>::{3};\n",
548 interfaceName
, interfaceName
, interfaceTraitsName
,
551 // Emit a utility wrapper trait class.
552 os
<< llvm::formatv(" template <typename {1}>\n"
553 " struct Trait : public detail::{0}Trait<{1}> {{};\n",
554 interfaceName
, valueTemplate
);
556 // Insert the method declarations.
557 bool isOpInterface
= isa
<OpInterface
>(interface
);
558 emitInterfaceDeclMethods(interface
, os
, valueType
, isOpInterface
,
561 // Insert the method declarations for base classes.
562 for (auto &base
: interface
.getBaseInterfaces()) {
563 std::string baseQualName
= base
.getFullyQualifiedName();
565 "===---------------------------------------------------------------"
567 << " // Inherited from " << baseQualName
<< "\n"
569 "===---------------------------------------------------------------"
572 // Allow implicit conversion to the base interface.
573 os
<< " operator " << baseQualName
<< " () const {\n"
574 << " if (!*this) return nullptr;\n"
575 << " return " << baseQualName
<< "(*this, getImpl()->impl"
576 << base
.getName() << ");\n"
579 // Inherit the base interface's methods.
580 emitInterfaceDeclMethods(base
, os
, valueType
, isOpInterface
, extraDeclsFmt
);
583 // Emit classof code if necessary.
584 if (std::optional
<StringRef
> extraClassOf
= interface
.getExtraClassOf()) {
585 auto extraClassOfFmt
= tblgen::FmtContext();
586 extraClassOfFmt
.addSubst(substVar
, "odsInterfaceInstance");
587 os
<< " static bool classof(" << valueType
<< " base) {\n"
588 << " auto* interface = getInterfaceFor(base);\n"
589 << " if (!interface)\n"
591 " " << interfaceName
<< " odsInterfaceInstance(base, interface);\n"
592 << " " << tblgen::tgfmt(extraClassOf
->trim(), &extraClassOfFmt
)
598 os
<< "namespace detail {\n";
599 emitTraitDecl(interface
, interfaceName
, interfaceTraitsName
);
600 os
<< "}// namespace detail\n";
602 for (StringRef ns
: llvm::reverse(namespaces
))
603 os
<< "} // namespace " << ns
<< "\n";
606 bool InterfaceGenerator::emitInterfaceDecls() {
607 llvm::emitSourceFileHeader("Interface Declarations", os
);
608 // Sort according to ID, so defs are emitted in the order in which they appear
609 // in the Tablegen file.
610 std::vector
<llvm::Record
*> sortedDefs(defs
);
611 llvm::sort(sortedDefs
, [](llvm::Record
*lhs
, llvm::Record
*rhs
) {
612 return lhs
->getID() < rhs
->getID();
614 for (const llvm::Record
*def
: sortedDefs
)
615 emitInterfaceDecl(Interface(def
));
616 for (const llvm::Record
*def
: sortedDefs
)
617 emitModelMethodsDef(Interface(def
));
621 //===----------------------------------------------------------------------===//
622 // GEN: Interface documentation
623 //===----------------------------------------------------------------------===//
625 static void emitInterfaceDoc(const llvm::Record
&interfaceDef
,
627 Interface
interface(&interfaceDef
);
629 // Emit the interface name followed by the description.
630 os
<< "## " << interface
.getName() << " (`" << interfaceDef
.getName()
632 if (auto description
= interface
.getDescription())
633 mlir::tblgen::emitDescription(*description
, os
);
635 // Emit the methods required by the interface.
636 os
<< "\n### Methods:\n";
637 for (const auto &method
: interface
.getMethods()) {
638 // Emit the method name.
639 os
<< "#### `" << method
.getName() << "`\n\n```c++\n";
641 // Emit the method signature.
642 if (method
.isStatic())
644 emitCPPType(method
.getReturnType(), os
) << method
.getName() << '(';
645 llvm::interleaveComma(method
.getArguments(), os
,
646 [&](const InterfaceMethod::Argument
&arg
) {
647 emitCPPType(arg
.type
, os
) << arg
.name
;
651 // Emit the description.
652 if (auto description
= method
.getDescription())
653 mlir::tblgen::emitDescription(*description
, os
);
655 // If the body is not provided, this method must be provided by the user.
656 if (!method
.getBody())
657 os
<< "\nNOTE: This method *must* be implemented by the user.";
663 bool InterfaceGenerator::emitInterfaceDocs() {
664 os
<< "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
665 os
<< "# " << interfaceBaseType
<< " definitions\n";
667 for (const auto *def
: defs
)
668 emitInterfaceDoc(*def
, os
);
672 //===----------------------------------------------------------------------===//
673 // GEN: Interface registration hooks
674 //===----------------------------------------------------------------------===//
677 template <typename GeneratorT
>
678 struct InterfaceGenRegistration
{
679 InterfaceGenRegistration(StringRef genArg
, StringRef genDesc
)
680 : genDeclArg(("gen-" + genArg
+ "-interface-decls").str()),
681 genDefArg(("gen-" + genArg
+ "-interface-defs").str()),
682 genDocArg(("gen-" + genArg
+ "-interface-docs").str()),
683 genDeclDesc(("Generate " + genDesc
+ " interface declarations").str()),
684 genDefDesc(("Generate " + genDesc
+ " interface definitions").str()),
685 genDocDesc(("Generate " + genDesc
+ " interface documentation").str()),
686 genDecls(genDeclArg
, genDeclDesc
,
687 [](const llvm::RecordKeeper
&records
, raw_ostream
&os
) {
688 return GeneratorT(records
, os
).emitInterfaceDecls();
690 genDefs(genDefArg
, genDefDesc
,
691 [](const llvm::RecordKeeper
&records
, raw_ostream
&os
) {
692 return GeneratorT(records
, os
).emitInterfaceDefs();
694 genDocs(genDocArg
, genDocDesc
,
695 [](const llvm::RecordKeeper
&records
, raw_ostream
&os
) {
696 return GeneratorT(records
, os
).emitInterfaceDocs();
699 std::string genDeclArg
, genDefArg
, genDocArg
;
700 std::string genDeclDesc
, genDefDesc
, genDocDesc
;
701 mlir::GenRegistration genDecls
, genDefs
, genDocs
;
705 static InterfaceGenRegistration
<AttrInterfaceGenerator
> attrGen("attr",
707 static InterfaceGenRegistration
<OpInterfaceGenerator
> opGen("op", "op");
708 static InterfaceGenRegistration
<TypeInterfaceGenerator
> typeGen("type", "type");