1 //===- AttrOrTypeDefGen.cpp - MLIR AttrOrType definitions generator -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "AttrOrTypeFormatGen.h"
10 #include "mlir/Support/LogicalResult.h"
11 #include "mlir/TableGen/AttrOrTypeDef.h"
12 #include "mlir/TableGen/Class.h"
13 #include "mlir/TableGen/CodeGenHelpers.h"
14 #include "mlir/TableGen/Format.h"
15 #include "mlir/TableGen/GenInfo.h"
16 #include "mlir/TableGen/Interfaces.h"
17 #include "llvm/ADT/Sequence.h"
18 #include "llvm/ADT/SetVector.h"
19 #include "llvm/ADT/SmallSet.h"
20 #include "llvm/ADT/StringSet.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "llvm/TableGen/Error.h"
23 #include "llvm/TableGen/TableGenBackend.h"
24 
25 #define DEBUG_TYPE "mlir-tblgen-attrortypedefgen"
26 
27 using namespace mlir;
28 using namespace mlir::tblgen;
29 
30 //===----------------------------------------------------------------------===//
31 // Utility Functions
32 //===----------------------------------------------------------------------===//
33 
34 std::string mlir::tblgen::getParameterAccessorName(StringRef name) {
35   assert(!name.empty() && "parameter has empty name");
36   auto ret = "get" + name.str();
37   ret[3] = llvm::toUpper(ret[3]); // uppercase first letter of the name
38   return ret;
39 }
40 
41 /// Find all the AttrOrTypeDef for the specified dialect. If no dialect
42 /// specified and can only find one dialect's defs, use that.
43 static void collectAllDefs(StringRef selectedDialect,
44                            std::vector<llvm::Record *> records,
45                            SmallVectorImpl<AttrOrTypeDef> &resultDefs) {
46   // Nothing to do if no defs were found.
47   if (records.empty())
48     return;
49 
50   auto defs = llvm::map_range(
51       records, [&](const llvm::Record *rec) { return AttrOrTypeDef(rec); });
52   if (selectedDialect.empty()) {
53     // If a dialect was not specified, ensure that all found defs belong to the
54     // same dialect.
55     if (!llvm::is_splat(llvm::map_range(
56             defs, [](const auto &def) { return def.getDialect(); }))) {
57       llvm::PrintFatalError("defs belonging to more than one dialect. Must "
58                             "select one via '--(attr|type)defs-dialect'");
59     }
60     resultDefs.assign(defs.begin(), defs.end());
61   } else {
62     // Otherwise, generate the defs that belong to the selected dialect.
63     auto dialectDefs = llvm::make_filter_range(defs, [&](const auto &def) {
64       return def.getDialect().getName().equals(selectedDialect);
65     });
66     resultDefs.assign(dialectDefs.begin(), dialectDefs.end());
67   }
68 }
69 
70 //===----------------------------------------------------------------------===//
71 // DefGen
72 //===----------------------------------------------------------------------===//
73 
74 namespace {
75 class DefGen {
76 public:
77   /// Create the attribute or type class.
78   DefGen(const AttrOrTypeDef &def);
79 
80   void emitDecl(raw_ostream &os) const {
81     if (storageCls) {
82       NamespaceEmitter ns(os, def.getStorageNamespace());
83       os << "struct " << def.getStorageClassName() << ";\n";
84     }
85     defCls.writeDeclTo(os);
86   }
87   void emitDef(raw_ostream &os) const {
88     if (storageCls && def.genStorageClass()) {
89       NamespaceEmitter ns(os, def.getStorageNamespace());
90       storageCls->writeDeclTo(os); // everything is inline
91     }
92     defCls.writeDefTo(os);
93   }
94 
95 private:
96   /// Add traits from the TableGen definition to the class.
97   void createParentWithTraits();
98   /// Emit top-level declarations: using declarations and any extra class
99   /// declarations.
100   void emitTopLevelDeclarations();
101   /// Emit attribute or type builders.
102   void emitBuilders();
103   /// Emit a verifier for the def.
104   void emitVerifier();
105   /// Emit parsers and printers.
106   void emitParserPrinter();
107   /// Emit parameter accessors, if required.
108   void emitAccessors();
109   /// Emit interface methods.
110   void emitInterfaceMethods();
111 
112   //===--------------------------------------------------------------------===//
113   // Builder Emission
114 
115   /// Emit the default builder `Attribute::get`
116   void emitDefaultBuilder();
117   /// Emit the checked builder `Attribute::getChecked`
118   void emitCheckedBuilder();
119   /// Emit a custom builder.
120   void emitCustomBuilder(const AttrOrTypeBuilder &builder);
121   /// Emit a checked custom builder.
122   void emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder);
123 
124   //===--------------------------------------------------------------------===//
125   // Interface Method Emission
126 
127   /// Emit methods for a trait.
128   void emitTraitMethods(const InterfaceTrait &trait);
129   /// Emit a trait method.
130   void emitTraitMethod(const InterfaceMethod &method);
131 
132   //===--------------------------------------------------------------------===//
133   // Storage Class Emission
134   void emitStorageClass();
135   /// Generate the storage class constructor.
136   void emitStorageConstructor();
137   /// Emit the key type `KeyTy`.
138   void emitKeyType();
139   /// Emit the equality comparison operator.
140   void emitEquals();
141   /// Emit the key hash function.
142   void emitHashKey();
143   /// Emit the function to construct the storage class.
144   void emitConstruct();
145 
146   //===--------------------------------------------------------------------===//
147   // Utility Function Declarations
148 
149   /// Get the method parameters for a def builder, where the first several
150   /// parameters may be different.
151   SmallVector<MethodParameter>
152   getBuilderParams(std::initializer_list<MethodParameter> prefix) const;
153 
154   //===--------------------------------------------------------------------===//
155   // Class fields
156 
157   /// The attribute or type definition.
158   const AttrOrTypeDef &def;
159   /// The list of attribute or type parameters.
160   ArrayRef<AttrOrTypeParameter> params;
161   /// The attribute or type class.
162   Class defCls;
163   /// An optional attribute or type storage class. The storage class will
164   /// exist if and only if the def has more than zero parameters.
165   Optional<Class> storageCls;
166 
167   /// The C++ base value of the def, either "Attribute" or "Type".
168   StringRef valueType;
169   /// The prefix/suffix of the TableGen def name, either "Attr" or "Type".
170   StringRef defType;
171 };
172 } // namespace
173 
174 DefGen::DefGen(const AttrOrTypeDef &def)
175     : def(def), params(def.getParameters()), defCls(def.getCppClassName()),
176       valueType(isa<AttrDef>(def) ? "Attribute" : "Type"),
177       defType(isa<AttrDef>(def) ? "Attr" : "Type") {
178   // Check that all parameters have names.
179   for (const AttrOrTypeParameter &param : def.getParameters())
180     if (param.isAnonymous())
181       llvm::PrintFatalError("all parameters must have a name");
182 
183   // If a storage class is needed, create one.
184   if (def.getNumParameters() > 0)
185     storageCls.emplace(def.getStorageClassName(), /*isStruct=*/true);
186 
187   // Create the parent class with any indicated traits.
188   createParentWithTraits();
189   // Emit top-level declarations.
190   emitTopLevelDeclarations();
191   // Emit builders for defs with parameters
192   if (storageCls)
193     emitBuilders();
194   // Emit the verifier.
195   if (storageCls && def.genVerifyDecl())
196     emitVerifier();
197   // Emit the mnemonic, if there is one, and any associated parser and printer.
198   if (def.getMnemonic())
199     emitParserPrinter();
200   // Emit accessors
201   if (def.genAccessors())
202     emitAccessors();
203   // Emit trait interface methods
204   emitInterfaceMethods();
205   defCls.finalize();
206   // Emit a storage class if one is needed
207   if (storageCls && def.genStorageClass())
208     emitStorageClass();
209 }
210 
211 void DefGen::createParentWithTraits() {
212   ParentClass defParent(strfmt("::mlir::{0}::{1}Base", valueType, defType));
213   defParent.addTemplateParam(def.getCppClassName());
214   defParent.addTemplateParam(def.getCppBaseClassName());
215   defParent.addTemplateParam(storageCls
216                                  ? strfmt("{0}::{1}", def.getStorageNamespace(),
217                                           def.getStorageClassName())
218                                  : strfmt("::mlir::{0}Storage", valueType));
219   for (auto &trait : def.getTraits()) {
220     defParent.addTemplateParam(
221         isa<NativeTrait>(&trait)
222             ? cast<NativeTrait>(&trait)->getFullyQualifiedTraitName()
223             : cast<InterfaceTrait>(&trait)->getFullyQualifiedTraitName());
224   }
225   defCls.addParent(std::move(defParent));
226 }
227 
228 void DefGen::emitTopLevelDeclarations() {
229   // Inherit constructors from the attribute or type class.
230   defCls.declare<VisibilityDeclaration>(Visibility::Public);
231   defCls.declare<UsingDeclaration>("Base::Base");
232 
233   // Emit the extra declarations first in case there's a definition in there.
234   if (Optional<StringRef> extraDecl = def.getExtraDecls())
235     defCls.declare<ExtraClassDeclaration>(*extraDecl);
236 }
237 
238 void DefGen::emitBuilders() {
239   if (!def.skipDefaultBuilders()) {
240     emitDefaultBuilder();
241     if (def.genVerifyDecl())
242       emitCheckedBuilder();
243   }
244   for (auto &builder : def.getBuilders()) {
245     emitCustomBuilder(builder);
246     if (def.genVerifyDecl())
247       emitCheckedCustomBuilder(builder);
248   }
249 }
250 
251 void DefGen::emitVerifier() {
252   defCls.declare<UsingDeclaration>("Base::getChecked");
253   defCls.declareStaticMethod(
254       "::mlir::LogicalResult", "verify",
255       getBuilderParams({{"::llvm::function_ref<::mlir::InFlightDiagnostic()>",
256                          "emitError"}}));
257 }
258 
259 void DefGen::emitParserPrinter() {
260   auto *mnemonic = defCls.addStaticMethod<Method::Constexpr>(
261       "::llvm::StringLiteral", "getMnemonic");
262   mnemonic->body().indent() << strfmt("return {\"{0}\"};", *def.getMnemonic());
263 
264   // Declare the parser and printer, if needed.
265   bool hasAssemblyFormat = def.getAssemblyFormat().hasValue();
266   if (!def.hasCustomAssemblyFormat() && !hasAssemblyFormat)
267     return;
268 
269   // Declare the parser.
270   SmallVector<MethodParameter> parserParams;
271   parserParams.emplace_back("::mlir::AsmParser &", "odsParser");
272   if (isa<AttrDef>(&def))
273     parserParams.emplace_back("::mlir::Type", "odsType");
274   auto *parser = defCls.addMethod(strfmt("::mlir::{0}", valueType), "parse",
275                                   hasAssemblyFormat ? Method::Static
276                                                     : Method::StaticDeclaration,
277                                   std::move(parserParams));
278   // Declare the printer.
279   auto props = hasAssemblyFormat ? Method::Const : Method::ConstDeclaration;
280   Method *printer =
281       defCls.addMethod("void", "print", props,
282                        MethodParameter("::mlir::AsmPrinter &", "odsPrinter"));
283   // Emit the bodies if we are using the declarative format.
284   if (hasAssemblyFormat)
285     return generateAttrOrTypeFormat(def, parser->body(), printer->body());
286 }
287 
288 void DefGen::emitAccessors() {
289   for (auto &param : params) {
290     Method *m = defCls.addMethod(
291         param.getCppAccessorType(), getParameterAccessorName(param.getName()),
292         def.genStorageClass() ? Method::Const : Method::ConstDeclaration);
293     // Generate accessor definitions only if we also generate the storage
294     // class. Otherwise, let the user define the exact accessor definition.
295     if (!def.genStorageClass())
296       continue;
297     auto scope = m->body().indent().scope("return getImpl()->", ";");
298     if (isa<AttributeSelfTypeParameter>(param))
299       m->body() << formatv("getType().cast<{0}>()", param.getCppType());
300     else
301       m->body() << param.getName();
302   }
303 }
304 
305 void DefGen::emitInterfaceMethods() {
306   for (auto &traitDef : def.getTraits())
307     if (auto *trait = dyn_cast<InterfaceTrait>(&traitDef))
308       if (trait->shouldDeclareMethods())
309         emitTraitMethods(*trait);
310 }
311 
312 //===----------------------------------------------------------------------===//
313 // Builder Emission
314 
315 SmallVector<MethodParameter>
316 DefGen::getBuilderParams(std::initializer_list<MethodParameter> prefix) const {
317   SmallVector<MethodParameter> builderParams;
318   builderParams.append(prefix.begin(), prefix.end());
319   for (auto &param : params)
320     builderParams.emplace_back(param.getCppType(), param.getName());
321   return builderParams;
322 }
323 
324 void DefGen::emitDefaultBuilder() {
325   Method *m = defCls.addStaticMethod(
326       def.getCppClassName(), "get",
327       getBuilderParams({{"::mlir::MLIRContext *", "context"}}));
328   MethodBody &body = m->body().indent();
329   auto scope = body.scope("return Base::get(context", ");");
330   llvm::for_each(params, [&](auto &param) { body << ", " << param.getName(); });
331 }
332 
333 void DefGen::emitCheckedBuilder() {
334   Method *m = defCls.addStaticMethod(
335       def.getCppClassName(), "getChecked",
336       getBuilderParams(
337           {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"},
338            {"::mlir::MLIRContext *", "context"}}));
339   MethodBody &body = m->body().indent();
340   auto scope = body.scope("return Base::getChecked(emitError, context", ");");
341   llvm::for_each(params, [&](auto &param) { body << ", " << param.getName(); });
342 }
343 
344 static SmallVector<MethodParameter>
345 getCustomBuilderParams(std::initializer_list<MethodParameter> prefix,
346                        const AttrOrTypeBuilder &builder) {
347   auto params = builder.getParameters();
348   SmallVector<MethodParameter> builderParams;
349   builderParams.append(prefix.begin(), prefix.end());
350   if (!builder.hasInferredContextParameter())
351     builderParams.emplace_back("::mlir::MLIRContext *", "context");
352   for (auto &param : params) {
353     builderParams.emplace_back(param.getCppType(), *param.getName(),
354                                param.getDefaultValue());
355   }
356   return builderParams;
357 }
358 
359 void DefGen::emitCustomBuilder(const AttrOrTypeBuilder &builder) {
360   // Don't emit a body if there isn't one.
361   auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration;
362   Method *m = defCls.addMethod(def.getCppClassName(), "get", props,
363                                getCustomBuilderParams({}, builder));
364   if (!builder.getBody())
365     return;
366 
367   // Format the body and emit it.
368   FmtContext ctx;
369   ctx.addSubst("_get", "Base::get");
370   if (!builder.hasInferredContextParameter())
371     ctx.addSubst("_ctxt", "context");
372   std::string bodyStr = tgfmt(*builder.getBody(), &ctx);
373   m->body().indent().getStream().printReindented(bodyStr);
374 }
375 
376 /// Replace all instances of 'from' to 'to' in `str` and return the new string.
377 static std::string replaceInStr(std::string str, StringRef from, StringRef to) {
378   size_t pos = 0;
379   while ((pos = str.find(from.data(), pos, from.size())) != std::string::npos)
380     str.replace(pos, from.size(), to.data(), to.size());
381   return str;
382 }
383 
384 void DefGen::emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder) {
385   // Don't emit a body if there isn't one.
386   auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration;
387   Method *m = defCls.addMethod(
388       def.getCppClassName(), "getChecked", props,
389       getCustomBuilderParams(
390           {{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}},
391           builder));
392   if (!builder.getBody())
393     return;
394 
395   // Format the body and emit it. Replace $_get(...) with
396   // Base::getChecked(emitError, ...)
397   FmtContext ctx;
398   if (!builder.hasInferredContextParameter())
399     ctx.addSubst("_ctxt", "context");
400   std::string bodyStr = replaceInStr(builder.getBody()->str(), "$_get(",
401                                      "Base::getChecked(emitError, ");
402   bodyStr = tgfmt(bodyStr, &ctx);
403   m->body().indent().getStream().printReindented(bodyStr);
404 }
405 
406 //===----------------------------------------------------------------------===//
407 // Interface Method Emission
408 
409 void DefGen::emitTraitMethods(const InterfaceTrait &trait) {
410   // Get the set of methods that should always be declared.
411   auto alwaysDeclaredMethods = trait.getAlwaysDeclaredMethods();
412   StringSet<> alwaysDeclared;
413   alwaysDeclared.insert(alwaysDeclaredMethods.begin(),
414                         alwaysDeclaredMethods.end());
415 
416   Interface iface = trait.getInterface(); // causes strange bugs if elided
417   for (auto &method : iface.getMethods()) {
418     // Don't declare if the method has a body. Or if the method has a default
419     // implementation and the def didn't request that it always be declared.
420     if (method.getBody() || (method.getDefaultImplementation() &&
421                              !alwaysDeclared.count(method.getName())))
422       continue;
423     emitTraitMethod(method);
424   }
425 }
426 
427 void DefGen::emitTraitMethod(const InterfaceMethod &method) {
428   // All interface methods are declaration-only.
429   auto props =
430       method.isStatic() ? Method::StaticDeclaration : Method::ConstDeclaration;
431   SmallVector<MethodParameter> params;
432   for (auto &param : method.getArguments())
433     params.emplace_back(param.type, param.name);
434   defCls.addMethod(method.getReturnType(), method.getName(), props,
435                    std::move(params));
436 }
437 
438 //===----------------------------------------------------------------------===//
439 // Storage Class Emission
440 
441 void DefGen::emitStorageConstructor() {
442   Constructor *ctor =
443       storageCls->addConstructor<Method::Inline>(getBuilderParams({}));
444   if (auto *attrDef = dyn_cast<AttrDef>(&def)) {
445     // For attributes, a parameter marked with AttributeSelfTypeParameter is
446     // the type initializer that must be passed to the parent constructor.
447     const auto isSelfType = [](const AttrOrTypeParameter &param) {
448       return isa<AttributeSelfTypeParameter>(param);
449     };
450     auto *selfTypeParam = llvm::find_if(params, isSelfType);
451     if (std::count_if(selfTypeParam, params.end(), isSelfType) > 1) {
452       PrintFatalError(def.getLoc(),
453                       "Only one attribute parameter can be marked as "
454                       "AttributeSelfTypeParameter");
455     }
456     // Alternatively, if a type builder was specified, use that instead.
457     std::string attrStorageInit =
458         selfTypeParam == params.end() ? "" : selfTypeParam->getName().str();
459     if (attrDef->getTypeBuilder()) {
460       FmtContext ctx;
461       for (auto &param : params)
462         ctx.addSubst(strfmt("_{0}", param.getName()), param.getName());
463       attrStorageInit = tgfmt(*attrDef->getTypeBuilder(), &ctx);
464     }
465     ctor->addMemberInitializer("::mlir::AttributeStorage",
466                                std::move(attrStorageInit));
467     // Initialize members that aren't the attribute's type.
468     for (auto &param : params)
469       if (selfTypeParam == params.end() || *selfTypeParam != param)
470         ctor->addMemberInitializer(param.getName(), param.getName());
471   } else {
472     for (auto &param : params)
473       ctor->addMemberInitializer(param.getName(), param.getName());
474   }
475 }
476 
477 void DefGen::emitKeyType() {
478   std::string keyType("std::tuple<");
479   llvm::raw_string_ostream os(keyType);
480   llvm::interleaveComma(params, os,
481                         [&](auto &param) { os << param.getCppType(); });
482   os << '>';
483   storageCls->declare<UsingDeclaration>("KeyTy", std::move(os.str()));
484 }
485 
486 void DefGen::emitEquals() {
487   Method *eq = storageCls->addConstMethod<Method::Inline>(
488       "bool", "operator==", MethodParameter("const KeyTy &", "tblgenKey"));
489   auto &body = eq->body().indent();
490   auto scope = body.scope("return (", ");");
491   const auto eachFn = [&](auto it) {
492     FmtContext ctx({{"_lhs", isa<AttributeSelfTypeParameter>(it.value())
493                                  ? "getType()"
494                                  : it.value().getName()},
495                     {"_rhs", strfmt("std::get<{0}>(tblgenKey)", it.index())}});
496     body << tgfmt(it.value().getComparator(), &ctx);
497   };
498   llvm::interleave(llvm::enumerate(params), body, eachFn, ") && (");
499 }
500 
501 void DefGen::emitHashKey() {
502   Method *hash = storageCls->addStaticInlineMethod(
503       "::llvm::hash_code", "hashKey",
504       MethodParameter("const KeyTy &", "tblgenKey"));
505   auto &body = hash->body().indent();
506   auto scope = body.scope("return ::llvm::hash_combine(", ");");
507   llvm::interleaveComma(llvm::enumerate(params), body, [&](auto it) {
508     body << llvm::formatv("std::get<{0}>(tblgenKey)", it.index());
509   });
510 }
511 
512 void DefGen::emitConstruct() {
513   Method *construct = storageCls->addMethod<Method::Inline>(
514       strfmt("{0} *", def.getStorageClassName()), "construct",
515       def.hasStorageCustomConstructor() ? Method::StaticDeclaration
516                                         : Method::Static,
517       MethodParameter(strfmt("::mlir::{0}StorageAllocator &", valueType),
518                       "allocator"),
519       MethodParameter("const KeyTy &", "tblgenKey"));
520   if (!def.hasStorageCustomConstructor()) {
521     auto &body = construct->body().indent();
522     for (const auto &it : llvm::enumerate(params)) {
523       body << formatv("auto {0} = std::get<{1}>(tblgenKey);\n",
524                       it.value().getName(), it.index());
525     }
526     // Use the parameters' custom allocator code, if provided.
527     FmtContext ctx = FmtContext().addSubst("_allocator", "allocator");
528     for (auto &param : params) {
529       if (Optional<StringRef> allocCode = param.getAllocator()) {
530         ctx.withSelf(param.getName()).addSubst("_dst", param.getName());
531         body << tgfmt(*allocCode, &ctx) << '\n';
532       }
533     }
534     auto scope =
535         body.scope(strfmt("return new (allocator.allocate<{0}>()) {0}(",
536                           def.getStorageClassName()),
537                    ");");
538     llvm::interleaveComma(params, body,
539                           [&](auto &param) { body << param.getName(); });
540   }
541 }
542 
543 void DefGen::emitStorageClass() {
544   // Add the appropriate parent class.
545   storageCls->addParent(strfmt("::mlir::{0}Storage", valueType));
546   // Add the constructor.
547   emitStorageConstructor();
548   // Declare the key type.
549   emitKeyType();
550   // Add the comparison method.
551   emitEquals();
552   // Emit the key hash method.
553   emitHashKey();
554   // Emit the storage constructor. Just declare it if the user wants to define
555   // it themself.
556   emitConstruct();
557   // Emit the storage class members as public, at the very end of the struct.
558   storageCls->finalize();
559   for (auto &param : params)
560     if (!isa<AttributeSelfTypeParameter>(param))
561       storageCls->declare<Field>(param.getCppType(), param.getName());
562 }
563 
564 //===----------------------------------------------------------------------===//
565 // DefGenerator
566 //===----------------------------------------------------------------------===//
567 
568 namespace {
569 /// This struct is the base generator used when processing tablegen interfaces.
570 class DefGenerator {
571 public:
572   bool emitDecls(StringRef selectedDialect);
573   bool emitDefs(StringRef selectedDialect);
574 
575 protected:
576   DefGenerator(std::vector<llvm::Record *> &&defs, raw_ostream &os,
577                StringRef defType, StringRef valueType, bool isAttrGenerator,
578                bool needsDialectParserPrinter)
579       : defRecords(std::move(defs)), os(os), defType(defType),
580         valueType(valueType), isAttrGenerator(isAttrGenerator),
581         needsDialectParserPrinter(needsDialectParserPrinter) {}
582 
583   /// Emit the list of def type names.
584   void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs);
585   /// Emit the code to dispatch between different defs during parsing/printing.
586   void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs);
587 
588   /// The set of def records to emit.
589   std::vector<llvm::Record *> defRecords;
590   /// The attribute or type class to emit.
591   /// The stream to emit to.
592   raw_ostream &os;
593   /// The prefix of the tablegen def name, e.g. Attr or Type.
594   StringRef defType;
595   /// The C++ base value type of the def, e.g. Attribute or Type.
596   StringRef valueType;
597   /// Flag indicating if this generator is for Attributes. False if the
598   /// generator is for types.
599   bool isAttrGenerator;
600   /// Track if we need to emit the printAttribute/parseAttribute
601   /// implementations.
602   bool needsDialectParserPrinter;
603 };
604 
605 /// A specialized generator for AttrDefs.
606 struct AttrDefGenerator : public DefGenerator {
607   AttrDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
608       : DefGenerator(records.getAllDerivedDefinitionsIfDefined("AttrDef"), os,
609                      "Attr", "Attribute",
610                      /*isAttrGenerator=*/true,
611                      /*needsDialectParserPrinter=*/
612                      !records.getAllDerivedDefinitions("DialectAttr").empty()) {
613   }
614 };
615 /// A specialized generator for TypeDefs.
616 struct TypeDefGenerator : public DefGenerator {
617   TypeDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
618       : DefGenerator(records.getAllDerivedDefinitionsIfDefined("TypeDef"), os,
619                      "Type", "Type",
620                      /*isAttrGenerator=*/false,
621                      /*needsDialectParserPrinter=*/
622                      !records.getAllDerivedDefinitions("DialectType").empty()) {
623   }
624 };
625 } // namespace
626 
627 //===----------------------------------------------------------------------===//
628 // GEN: Declarations
629 //===----------------------------------------------------------------------===//
630 
631 /// Print this above all the other declarations. Contains type declarations used
632 /// later on.
633 static const char *const typeDefDeclHeader = R"(
634 namespace mlir {
635 class AsmParser;
636 class AsmPrinter;
637 } // namespace mlir
638 )";
639 
640 bool DefGenerator::emitDecls(StringRef selectedDialect) {
641   emitSourceFileHeader((defType + "Def Declarations").str(), os);
642   IfDefScope scope("GET_" + defType.upper() + "DEF_CLASSES", os);
643 
644   // Output the common "header".
645   os << typeDefDeclHeader;
646 
647   SmallVector<AttrOrTypeDef, 16> defs;
648   collectAllDefs(selectedDialect, defRecords, defs);
649   if (defs.empty())
650     return false;
651   {
652     NamespaceEmitter nsEmitter(os, defs.front().getDialect());
653 
654     // Declare all the def classes first (in case they reference each other).
655     for (const AttrOrTypeDef &def : defs)
656       os << "class " << def.getCppClassName() << ";\n";
657 
658     // Emit the declarations.
659     for (const AttrOrTypeDef &def : defs)
660       DefGen(def).emitDecl(os);
661   }
662   // Emit the TypeID explicit specializations to have a single definition for
663   // each of these.
664   for (const AttrOrTypeDef &def : defs)
665     if (!def.getDialect().getCppNamespace().empty())
666       os << "MLIR_DECLARE_EXPLICIT_TYPE_ID("
667          << def.getDialect().getCppNamespace() << "::" << def.getCppClassName()
668          << ")\n";
669 
670   return false;
671 }
672 
673 //===----------------------------------------------------------------------===//
674 // GEN: Def List
675 //===----------------------------------------------------------------------===//
676 
677 void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) {
678   IfDefScope scope("GET_" + defType.upper() + "DEF_LIST", os);
679   auto interleaveFn = [&](const AttrOrTypeDef &def) {
680     os << def.getDialect().getCppNamespace() << "::" << def.getCppClassName();
681   };
682   llvm::interleave(defs, os, interleaveFn, ",\n");
683   os << "\n";
684 }
685 
686 //===----------------------------------------------------------------------===//
687 // GEN: Definitions
688 //===----------------------------------------------------------------------===//
689 
690 /// The code block for default attribute parser/printer dispatch boilerplate.
691 /// {0}: the dialect fully qualified class name.
692 /// {1}: the optional code for the dynamic attribute parser dispatch.
693 /// {2}: the optional code for the dynamic attribute printer dispatch.
694 static const char *const dialectDefaultAttrPrinterParserDispatch = R"(
695 /// Parse an attribute registered to this dialect.
696 ::mlir::Attribute {0}::parseAttribute(::mlir::DialectAsmParser &parser,
697                                       ::mlir::Type type) const {{
698   ::llvm::SMLoc typeLoc = parser.getCurrentLocation();
699   ::llvm::StringRef attrTag;
700   if (::mlir::failed(parser.parseKeyword(&attrTag)))
701     return {{};
702   {{
703     ::mlir::Attribute attr;
704     auto parseResult = generatedAttributeParser(parser, attrTag, type, attr);
705     if (parseResult.hasValue())
706       return attr;
707   }
708   {1}
709   parser.emitError(typeLoc) << "unknown attribute `"
710       << attrTag << "` in dialect `" << getNamespace() << "`";
711   return {{};
712 }
713 /// Print an attribute registered to this dialect.
714 void {0}::printAttribute(::mlir::Attribute attr,
715                          ::mlir::DialectAsmPrinter &printer) const {{
716   if (::mlir::succeeded(generatedAttributePrinter(attr, printer)))
717     return;
718   {2}
719 }
720 )";
721 
722 /// The code block for dynamic attribute parser dispatch boilerplate.
723 static const char *const dialectDynamicAttrParserDispatch = R"(
724   {
725     ::mlir::Attribute genAttr;
726     auto parseResult = parseOptionalDynamicAttr(attrTag, parser, genAttr);
727     if (parseResult.hasValue()) {
728       if (::mlir::succeeded(parseResult.getValue()))
729         return genAttr;
730       return Attribute();
731     }
732   }
733 )";
734 
735 /// The code block for dynamic type printer dispatch boilerplate.
736 static const char *const dialectDynamicAttrPrinterDispatch = R"(
737   if (::mlir::succeeded(printIfDynamicAttr(attr, printer)))
738     return;
739 )";
740 
741 /// The code block for default type parser/printer dispatch boilerplate.
742 /// {0}: the dialect fully qualified class name.
743 /// {1}: the optional code for the dynamic type parser dispatch.
744 /// {2}: the optional code for the dynamic type printer dispatch.
745 static const char *const dialectDefaultTypePrinterParserDispatch = R"(
746 /// Parse a type registered to this dialect.
747 ::mlir::Type {0}::parseType(::mlir::DialectAsmParser &parser) const {{
748   ::llvm::SMLoc typeLoc = parser.getCurrentLocation();
749   ::llvm::StringRef mnemonic;
750   if (parser.parseKeyword(&mnemonic))
751     return ::mlir::Type();
752   ::mlir::Type genType;
753   auto parseResult = generatedTypeParser(parser, mnemonic, genType);
754   if (parseResult.hasValue())
755     return genType;
756   {1}
757   parser.emitError(typeLoc) << "unknown  type `"
758       << mnemonic << "` in dialect `" << getNamespace() << "`";
759   return {{};
760 }
761 /// Print a type registered to this dialect.
762 void {0}::printType(::mlir::Type type,
763                     ::mlir::DialectAsmPrinter &printer) const {{
764   if (::mlir::succeeded(generatedTypePrinter(type, printer)))
765     return;
766   {2}
767 }
768 )";
769 
770 /// The code block for dynamic type parser dispatch boilerplate.
771 static const char *const dialectDynamicTypeParserDispatch = R"(
772   {
773     auto parseResult = parseOptionalDynamicType(mnemonic, parser, genType);
774     if (parseResult.hasValue()) {
775       if (::mlir::succeeded(parseResult.getValue()))
776         return genType;
777       return Type();
778     }
779   }
780 )";
781 
782 /// The code block for dynamic type printer dispatch boilerplate.
783 static const char *const dialectDynamicTypePrinterDispatch = R"(
784   if (::mlir::succeeded(printIfDynamicType(type, printer)))
785     return;
786 )";
787 
788 /// Emit the dialect printer/parser dispatcher. User's code should call these
789 /// functions from their dialect's print/parse methods.
790 void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) {
791   if (llvm::none_of(defs, [](const AttrOrTypeDef &def) {
792         return def.getMnemonic().hasValue();
793       })) {
794     return;
795   }
796   // Declare the parser.
797   SmallVector<MethodParameter> params = {{"::mlir::AsmParser &", "parser"},
798                                          {"::llvm::StringRef", "mnemonic"}};
799   if (isAttrGenerator)
800     params.emplace_back("::mlir::Type", "type");
801   params.emplace_back(strfmt("::mlir::{0} &", valueType), "value");
802   Method parse("::mlir::OptionalParseResult",
803                strfmt("generated{0}Parser", valueType), Method::StaticInline,
804                std::move(params));
805   // Declare the printer.
806   Method printer("::mlir::LogicalResult",
807                  strfmt("generated{0}Printer", valueType), Method::StaticInline,
808                  {{strfmt("::mlir::{0}", valueType), "def"},
809                   {"::mlir::AsmPrinter &", "printer"}});
810 
811   // The parser dispatch is just a list of if-elses, matching on the mnemonic
812   // and calling the def's parse function.
813   const char *const getValueForMnemonic =
814       R"(  if (mnemonic == {0}::getMnemonic()) {{
815     value = {0}::{1};
816     return ::mlir::success(!!value);
817   }
818 )";
819   // The printer dispatch uses llvm::TypeSwitch to find and call the correct
820   // printer.
821   printer.body() << "  return ::llvm::TypeSwitch<::mlir::" << valueType
822                  << ", ::mlir::LogicalResult>(def)";
823   const char *const printValue = R"(    .Case<{0}>([&](auto t) {{
824       printer << {0}::getMnemonic();{1}
825       return ::mlir::success();
826     })
827 )";
828   for (auto &def : defs) {
829     if (!def.getMnemonic())
830       continue;
831     bool hasParserPrinterDecl =
832         def.hasCustomAssemblyFormat() || def.getAssemblyFormat();
833     std::string defClass = strfmt(
834         "{0}::{1}", def.getDialect().getCppNamespace(), def.getCppClassName());
835 
836     // If the def has no parameters or parser code, invoke a normal `get`.
837     std::string parseOrGet =
838         hasParserPrinterDecl
839             ? strfmt("parse(parser{0})", isAttrGenerator ? ", type" : "")
840             : "get(parser.getContext())";
841     parse.body() << llvm::formatv(getValueForMnemonic, defClass, parseOrGet);
842 
843     // If the def has no parameters and no printer, just print the mnemonic.
844     StringRef printDef = "";
845     if (hasParserPrinterDecl)
846       printDef = "\nt.print(printer);";
847     printer.body() << llvm::formatv(printValue, defClass, printDef);
848   }
849   parse.body() << "  return {};";
850   printer.body() << "    .Default([](auto) { return ::mlir::failure(); });";
851 
852   raw_indented_ostream indentedOs(os);
853   parse.writeDeclTo(indentedOs);
854   printer.writeDeclTo(indentedOs);
855 }
856 
857 bool DefGenerator::emitDefs(StringRef selectedDialect) {
858   emitSourceFileHeader((defType + "Def Definitions").str(), os);
859 
860   SmallVector<AttrOrTypeDef, 16> defs;
861   collectAllDefs(selectedDialect, defRecords, defs);
862   if (defs.empty())
863     return false;
864   emitTypeDefList(defs);
865 
866   IfDefScope scope("GET_" + defType.upper() + "DEF_CLASSES", os);
867   emitParsePrintDispatch(defs);
868   for (const AttrOrTypeDef &def : defs) {
869     {
870       NamespaceEmitter ns(os, def.getDialect());
871       DefGen gen(def);
872       gen.emitDef(os);
873     }
874     // Emit the TypeID explicit specializations to have a single symbol def.
875     if (!def.getDialect().getCppNamespace().empty())
876       os << "MLIR_DEFINE_EXPLICIT_TYPE_ID("
877          << def.getDialect().getCppNamespace() << "::" << def.getCppClassName()
878          << ")\n";
879   }
880 
881   Dialect firstDialect = defs.front().getDialect();
882   // Emit the default parser/printer for Attributes if the dialect asked for
883   // it.
884   if (valueType == "Attribute" && needsDialectParserPrinter &&
885       firstDialect.useDefaultAttributePrinterParser()) {
886     NamespaceEmitter nsEmitter(os, firstDialect);
887     if (firstDialect.isExtensible()) {
888       os << llvm::formatv(dialectDefaultAttrPrinterParserDispatch,
889                           firstDialect.getCppClassName(),
890                           dialectDynamicAttrParserDispatch,
891                           dialectDynamicAttrPrinterDispatch);
892     } else {
893       os << llvm::formatv(dialectDefaultAttrPrinterParserDispatch,
894                           firstDialect.getCppClassName(), "", "");
895     }
896   }
897 
898   // Emit the default parser/printer for Types if the dialect asked for it.
899   if (valueType == "Type" && needsDialectParserPrinter &&
900       firstDialect.useDefaultTypePrinterParser()) {
901     NamespaceEmitter nsEmitter(os, firstDialect);
902     if (firstDialect.isExtensible()) {
903       os << llvm::formatv(dialectDefaultTypePrinterParserDispatch,
904                           firstDialect.getCppClassName(),
905                           dialectDynamicTypeParserDispatch,
906                           dialectDynamicTypePrinterDispatch);
907     } else {
908       os << llvm::formatv(dialectDefaultTypePrinterParserDispatch,
909                           firstDialect.getCppClassName(), "", "");
910     }
911   }
912 
913   return false;
914 }
915 
916 //===----------------------------------------------------------------------===//
917 // GEN: Registration hooks
918 //===----------------------------------------------------------------------===//
919 
920 //===----------------------------------------------------------------------===//
921 // AttrDef
922 
923 static llvm::cl::OptionCategory attrdefGenCat("Options for -gen-attrdef-*");
924 static llvm::cl::opt<std::string>
925     attrDialect("attrdefs-dialect",
926                 llvm::cl::desc("Generate attributes for this dialect"),
927                 llvm::cl::cat(attrdefGenCat), llvm::cl::CommaSeparated);
928 
929 static mlir::GenRegistration
930     genAttrDefs("gen-attrdef-defs", "Generate AttrDef definitions",
931                 [](const llvm::RecordKeeper &records, raw_ostream &os) {
932                   AttrDefGenerator generator(records, os);
933                   return generator.emitDefs(attrDialect);
934                 });
935 static mlir::GenRegistration
936     genAttrDecls("gen-attrdef-decls", "Generate AttrDef declarations",
937                  [](const llvm::RecordKeeper &records, raw_ostream &os) {
938                    AttrDefGenerator generator(records, os);
939                    return generator.emitDecls(attrDialect);
940                  });
941 
942 //===----------------------------------------------------------------------===//
943 // TypeDef
944 
945 static llvm::cl::OptionCategory typedefGenCat("Options for -gen-typedef-*");
946 static llvm::cl::opt<std::string>
947     typeDialect("typedefs-dialect",
948                 llvm::cl::desc("Generate types for this dialect"),
949                 llvm::cl::cat(typedefGenCat), llvm::cl::CommaSeparated);
950 
951 static mlir::GenRegistration
952     genTypeDefs("gen-typedef-defs", "Generate TypeDef definitions",
953                 [](const llvm::RecordKeeper &records, raw_ostream &os) {
954                   TypeDefGenerator generator(records, os);
955                   return generator.emitDefs(typeDialect);
956                 });
957 static mlir::GenRegistration
958     genTypeDecls("gen-typedef-decls", "Generate TypeDef declarations",
959                  [](const llvm::RecordKeeper &records, raw_ostream &os) {
960                    TypeDefGenerator generator(records, os);
961                    return generator.emitDecls(typeDialect);
962                  });
963