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