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