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 "mlir/Support/LogicalResult.h"
10 #include "mlir/TableGen/AttrOrTypeDef.h"
11 #include "mlir/TableGen/CodeGenHelpers.h"
12 #include "mlir/TableGen/Format.h"
13 #include "mlir/TableGen/GenInfo.h"
14 #include "llvm/ADT/Sequence.h"
15 #include "llvm/ADT/SmallSet.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/TableGen/Error.h"
18 #include "llvm/TableGen/TableGenBackend.h"
19 
20 #define DEBUG_TYPE "mlir-tblgen-attrortypedefgen"
21 
22 using namespace mlir;
23 using namespace mlir::tblgen;
24 
25 /// Find all the AttrOrTypeDef for the specified dialect. If no dialect
26 /// specified and can only find one dialect's defs, use that.
27 static void collectAllDefs(StringRef selectedDialect,
28                            std::vector<llvm::Record *> records,
29                            SmallVectorImpl<AttrOrTypeDef> &resultDefs) {
30   auto defs = llvm::map_range(
31       records, [&](const llvm::Record *rec) { return AttrOrTypeDef(rec); });
32   if (defs.empty())
33     return;
34 
35   StringRef dialectName;
36   if (selectedDialect.empty()) {
37     if (defs.empty())
38       return;
39 
40     Dialect dialect(nullptr);
41     for (const AttrOrTypeDef &typeDef : defs) {
42       if (!dialect) {
43         dialect = typeDef.getDialect();
44       } else if (dialect != typeDef.getDialect()) {
45         llvm::PrintFatalError("defs belonging to more than one dialect. Must "
46                               "select one via '--(attr|type)defs-dialect'");
47       }
48     }
49 
50     dialectName = dialect.getName();
51   } else {
52     dialectName = selectedDialect;
53   }
54 
55   for (const AttrOrTypeDef &def : defs)
56     if (def.getDialect().getName().equals(dialectName))
57       resultDefs.push_back(def);
58 }
59 
60 //===----------------------------------------------------------------------===//
61 // ParamCommaFormatter
62 //===----------------------------------------------------------------------===//
63 
64 namespace {
65 
66 /// Pass an instance of this class to llvm::formatv() to emit a comma separated
67 /// list of parameters in the format by 'EmitFormat'.
68 class ParamCommaFormatter : public llvm::detail::format_adapter {
69 public:
70   /// Choose the output format
71   enum EmitFormat {
72     /// Emit "parameter1Type parameter1Name, parameter2Type parameter2Name,
73     /// [...]".
74     TypeNamePairs,
75 
76     /// Emit "parameter1(parameter1), parameter2(parameter2), [...]".
77     TypeNameInitializer,
78 
79     /// Emit "param1Name, param2Name, [...]".
80     JustParams,
81   };
82 
83   ParamCommaFormatter(EmitFormat emitFormat,
84                       ArrayRef<AttrOrTypeParameter> params,
85                       bool prependComma = true)
86       : emitFormat(emitFormat), params(params), prependComma(prependComma) {}
87 
88   /// llvm::formatv will call this function when using an instance as a
89   /// replacement value.
90   void format(raw_ostream &os, StringRef options) override {
91     if (!params.empty() && prependComma)
92       os << ", ";
93 
94     switch (emitFormat) {
95     case EmitFormat::TypeNamePairs:
96       interleaveComma(params, os, [&](const AttrOrTypeParameter &p) {
97         emitTypeNamePair(p, os);
98       });
99       break;
100     case EmitFormat::TypeNameInitializer:
101       interleaveComma(params, os, [&](const AttrOrTypeParameter &p) {
102         emitTypeNameInitializer(p, os);
103       });
104       break;
105     case EmitFormat::JustParams:
106       interleaveComma(params, os,
107                       [&](const AttrOrTypeParameter &p) { os << p.getName(); });
108       break;
109     }
110   }
111 
112 private:
113   // Emit "paramType paramName".
114   static void emitTypeNamePair(const AttrOrTypeParameter &param,
115                                raw_ostream &os) {
116     os << param.getCppType() << " " << param.getName();
117   }
118   // Emit "paramName(paramName)"
119   void emitTypeNameInitializer(const AttrOrTypeParameter &param,
120                                raw_ostream &os) {
121     os << param.getName() << "(" << param.getName() << ")";
122   }
123 
124   EmitFormat emitFormat;
125   ArrayRef<AttrOrTypeParameter> params;
126   bool prependComma;
127 };
128 
129 } // end anonymous namespace
130 
131 //===----------------------------------------------------------------------===//
132 // DefGenerator
133 //===----------------------------------------------------------------------===//
134 
135 namespace {
136 /// This struct is the base generator used when processing tablegen interfaces.
137 class DefGenerator {
138 public:
139   bool emitDecls(StringRef selectedDialect);
140   bool emitDefs(StringRef selectedDialect);
141 
142 protected:
143   DefGenerator(std::vector<llvm::Record *> &&defs, raw_ostream &os)
144       : defRecords(std::move(defs)), os(os), isAttrGenerator(false) {}
145 
146   /// Emit the declaration of a single def.
147   void emitDefDecl(const AttrOrTypeDef &def);
148   /// Emit the list of def type names.
149   void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs);
150   /// Emit the code to dispatch between different defs during parsing/printing.
151   void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs);
152   /// Emit the definition of a single def.
153   void emitDefDef(const AttrOrTypeDef &def);
154   /// Emit the storage class for the given def.
155   void emitStorageClass(const AttrOrTypeDef &def);
156   /// Emit the parser/printer for the given def.
157   void emitParsePrint(const AttrOrTypeDef &def);
158 
159   /// The set of def records to emit.
160   std::vector<llvm::Record *> defRecords;
161   /// The stream to emit to.
162   raw_ostream &os;
163   /// The prefix of the tablegen def name, e.g. Attr or Type.
164   StringRef defTypePrefix;
165   /// The C++ base value type of the def, e.g. Attribute or Type.
166   StringRef valueType;
167   /// Flag indicating if this generator is for Attributes. False if the
168   /// generator is for types.
169   bool isAttrGenerator;
170 };
171 
172 /// A specialized generator for AttrDefs.
173 struct AttrDefGenerator : public DefGenerator {
174   AttrDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
175       : DefGenerator(records.getAllDerivedDefinitions("AttrDef"), os) {
176     isAttrGenerator = true;
177     defTypePrefix = "Attr";
178     valueType = "Attribute";
179   }
180 };
181 /// A specialized generator for TypeDefs.
182 struct TypeDefGenerator : public DefGenerator {
183   TypeDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
184       : DefGenerator(records.getAllDerivedDefinitions("TypeDef"), os) {
185     defTypePrefix = "Type";
186     valueType = "Type";
187   }
188 };
189 } // end anonymous namespace
190 
191 //===----------------------------------------------------------------------===//
192 // GEN: Declarations
193 //===----------------------------------------------------------------------===//
194 
195 /// Print this above all the other declarations. Contains type declarations used
196 /// later on.
197 static const char *const typeDefDeclHeader = R"(
198 namespace mlir {
199 class DialectAsmParser;
200 class DialectAsmPrinter;
201 } // namespace mlir
202 )";
203 
204 /// The code block for the start of a typeDef class declaration -- singleton
205 /// case.
206 ///
207 /// {0}: The name of the def class.
208 /// {1}: The name of the type base class.
209 /// {2}: The name of the base value type, e.g. Attribute or Type.
210 /// {3}: The tablegen record type prefix, e.g. Attr or Type.
211 static const char *const defDeclSingletonBeginStr = R"(
212   class {0} : public ::mlir::{2}::{3}Base<{0}, {1}, ::mlir::{2}Storage> {{
213   public:
214     /// Inherit some necessary constructors from '{3}Base'.
215     using Base::Base;
216 )";
217 
218 /// The code block for the start of a typeDef class declaration -- parametric
219 /// case.
220 ///
221 /// {0}: The name of the typeDef class.
222 /// {1}: The name of the type base class.
223 /// {2}: The typeDef storage class namespace.
224 /// {3}: The storage class name.
225 /// {4}: The name of the base value type, e.g. Attribute or Type.
226 /// {5}: The tablegen record type prefix, e.g. Attr or Type.
227 static const char *const defDeclParametricBeginStr = R"(
228   namespace {2} {
229     struct {3};
230   } // end namespace {2}
231   class {0} : public ::mlir::{4}::{5}Base<{0}, {1},
232                                          {2}::{3}> {{
233   public:
234     /// Inherit some necessary constructors from '{5}Base'.
235     using Base::Base;
236 
237 )";
238 
239 /// The code snippet for print/parse of an Attribute/Type.
240 ///
241 /// {0}: The name of the base value type, e.g. Attribute or Type.
242 /// {1}: Extra parser parameters.
243 static const char *const defDeclParsePrintStr = R"(
244     static ::mlir::{0} parse(::mlir::MLIRContext *context,
245                              ::mlir::DialectAsmParser &parser{1});
246     void print(::mlir::DialectAsmPrinter &printer) const;
247 )";
248 
249 /// The code block for the verify method declaration.
250 ///
251 /// {0}: List of parameters, parameters style.
252 static const char *const defDeclVerifyStr = R"(
253     using Base::getChecked;
254     static ::mlir::LogicalResult verify(::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError{0});
255 )";
256 
257 /// Emit the builders for the given def.
258 static void emitBuilderDecls(const AttrOrTypeDef &def, raw_ostream &os,
259                              ParamCommaFormatter &paramTypes) {
260   StringRef typeClass = def.getCppClassName();
261   bool genCheckedMethods = def.genVerifyDecl();
262   if (!def.skipDefaultBuilders()) {
263     os << llvm::formatv(
264         "    static {0} get(::mlir::MLIRContext *context{1});\n", typeClass,
265         paramTypes);
266     if (genCheckedMethods) {
267       os << llvm::formatv("    static {0} "
268                           "getChecked(llvm::function_ref<::mlir::"
269                           "InFlightDiagnostic()> emitError, "
270                           "::mlir::MLIRContext *context{1});\n",
271                           typeClass, paramTypes);
272     }
273   }
274 
275   // Generate the builders specified by the user.
276   for (const AttrOrTypeBuilder &builder : def.getBuilders()) {
277     std::string paramStr;
278     llvm::raw_string_ostream paramOS(paramStr);
279     llvm::interleaveComma(
280         builder.getParameters(), paramOS,
281         [&](const AttrOrTypeBuilder::Parameter &param) {
282           // Note: AttrOrTypeBuilder parameters are guaranteed to have names.
283           paramOS << param.getCppType() << " " << *param.getName();
284           if (Optional<StringRef> defaultParamValue = param.getDefaultValue())
285             paramOS << " = " << *defaultParamValue;
286         });
287     paramOS.flush();
288 
289     // Generate the `get` variant of the builder.
290     os << "    static " << typeClass << " get(";
291     if (!builder.hasInferredContextParameter()) {
292       os << "::mlir::MLIRContext *context";
293       if (!paramStr.empty())
294         os << ", ";
295     }
296     os << paramStr << ");\n";
297 
298     // Generate the `getChecked` variant of the builder.
299     if (genCheckedMethods) {
300       os << "    static " << typeClass
301          << " getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> "
302             "emitError";
303       if (!builder.hasInferredContextParameter())
304         os << ", ::mlir::MLIRContext *context";
305       if (!paramStr.empty())
306         os << ", ";
307       os << paramStr << ");\n";
308     }
309   }
310 }
311 
312 void DefGenerator::emitDefDecl(const AttrOrTypeDef &def) {
313   SmallVector<AttrOrTypeParameter, 4> params;
314   def.getParameters(params);
315 
316   // Emit the beginning string template: either the singleton or parametric
317   // template.
318   if (def.getNumParameters() == 0) {
319     os << formatv(defDeclSingletonBeginStr, def.getCppClassName(),
320                   def.getCppBaseClassName(), valueType, defTypePrefix);
321   } else {
322     os << formatv(defDeclParametricBeginStr, def.getCppClassName(),
323                   def.getCppBaseClassName(), def.getStorageNamespace(),
324                   def.getStorageClassName(), valueType, defTypePrefix);
325   }
326 
327   // Emit the extra declarations first in case there's a definition in there.
328   if (Optional<StringRef> extraDecl = def.getExtraDecls())
329     os << *extraDecl << "\n";
330 
331   ParamCommaFormatter emitTypeNamePairsAfterComma(
332       ParamCommaFormatter::EmitFormat::TypeNamePairs, params);
333   if (!params.empty()) {
334     emitBuilderDecls(def, os, emitTypeNamePairsAfterComma);
335 
336     // Emit the verify invariants declaration.
337     if (def.genVerifyDecl())
338       os << llvm::formatv(defDeclVerifyStr, emitTypeNamePairsAfterComma);
339   }
340 
341   // Emit the mnenomic, if specified.
342   if (auto mnenomic = def.getMnemonic()) {
343     os << "    static constexpr ::llvm::StringLiteral getMnemonic() {\n"
344        << "      return ::llvm::StringLiteral(\"" << mnenomic << "\");\n"
345        << "    }\n";
346 
347     // If mnemonic specified, emit print/parse declarations.
348     if (def.getParserCode() || def.getPrinterCode() || !params.empty()) {
349       os << llvm::formatv(defDeclParsePrintStr, valueType,
350                           isAttrGenerator ? ", ::mlir::Type type" : "");
351     }
352   }
353 
354   if (def.genAccessors()) {
355     SmallVector<AttrOrTypeParameter, 4> parameters;
356     def.getParameters(parameters);
357 
358     for (AttrOrTypeParameter &parameter : parameters) {
359       SmallString<16> name = parameter.getName();
360       name[0] = llvm::toUpper(name[0]);
361       os << formatv("    {0} get{1}() const;\n", parameter.getCppType(), name);
362     }
363   }
364 
365   // End the decl.
366   os << "  };\n";
367 }
368 
369 bool DefGenerator::emitDecls(StringRef selectedDialect) {
370   emitSourceFileHeader((defTypePrefix + "Def Declarations").str(), os);
371   IfDefScope scope("GET_" + defTypePrefix.upper() + "DEF_CLASSES", os);
372 
373   // Output the common "header".
374   os << typeDefDeclHeader;
375 
376   SmallVector<AttrOrTypeDef, 16> defs;
377   collectAllDefs(selectedDialect, defRecords, defs);
378   if (defs.empty())
379     return false;
380 
381   NamespaceEmitter nsEmitter(os, defs.front().getDialect());
382 
383   // Declare all the def classes first (in case they reference each other).
384   for (const AttrOrTypeDef &def : defs)
385     os << "  class " << def.getCppClassName() << ";\n";
386 
387   // Emit the declarations.
388   for (const AttrOrTypeDef &def : defs)
389     emitDefDecl(def);
390   return false;
391 }
392 
393 //===----------------------------------------------------------------------===//
394 // GEN: Def List
395 //===----------------------------------------------------------------------===//
396 
397 void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) {
398   IfDefScope scope("GET_" + defTypePrefix.upper() + "DEF_LIST", os);
399   auto interleaveFn = [&](const AttrOrTypeDef &def) {
400     os << def.getDialect().getCppNamespace() << "::" << def.getCppClassName();
401   };
402   llvm::interleave(defs, os, interleaveFn, ",\n");
403   os << "\n";
404 }
405 
406 //===----------------------------------------------------------------------===//
407 // GEN: Definitions
408 //===----------------------------------------------------------------------===//
409 
410 /// The code block used to start the auto-generated parser function.
411 ///
412 /// {0}: The name of the base value type, e.g. Attribute or Type.
413 /// {1}: Additional parser parameters.
414 static const char *const defParserDispatchStartStr = R"(
415 static ::mlir::OptionalParseResult generated{0}Parser(::mlir::MLIRContext *context,
416                                       ::mlir::DialectAsmParser &parser,
417                                       ::llvm::StringRef mnemonic{1},
418                                       ::mlir::{0} &value) {{
419 )";
420 
421 /// The code block used to start the auto-generated printer function.
422 ///
423 /// {0}: The name of the base value type, e.g. Attribute or Type.
424 static const char *const defPrinterDispatchStartStr = R"(
425 static ::mlir::LogicalResult generated{0}Printer(
426                          ::mlir::{0} def, ::mlir::DialectAsmPrinter &printer) {{
427   return ::llvm::TypeSwitch<::mlir::{0}, ::mlir::LogicalResult>(def)
428 )";
429 
430 /// Beginning of storage class.
431 /// {0}: Storage class namespace.
432 /// {1}: Storage class c++ name.
433 /// {2}: Parameters parameters.
434 /// {3}: Parameter initializer string.
435 /// {4}: Parameter types.
436 /// {5}: The name of the base value type, e.g. Attribute or Type.
437 static const char *const defStorageClassBeginStr = R"(
438 namespace {0} {{
439   struct {1} : public ::mlir::{5}Storage {{
440     {1} ({2})
441       : {3} {{ }
442 
443     /// The hash key is a tuple of the parameter types.
444     using KeyTy = std::tuple<{4}>;
445 )";
446 
447 /// The storage class' constructor template.
448 ///
449 /// {0}: storage class name.
450 /// {1}: The name of the base value type, e.g. Attribute or Type.
451 static const char *const defStorageClassConstructorBeginStr = R"(
452     /// Define a construction method for creating a new instance of this
453     /// storage.
454     static {0} *construct(::mlir::{1}StorageAllocator &allocator,
455                           const KeyTy &key) {{
456 )";
457 
458 /// The storage class' constructor return template.
459 ///
460 /// {0}: storage class name.
461 /// {1}: list of parameters.
462 static const char *const defStorageClassConstructorEndStr = R"(
463       return new (allocator.allocate<{0}>())
464           {0}({1});
465     }
466 )";
467 
468 /// Use tgfmt to emit custom allocation code for each parameter, if necessary.
469 static void emitStorageParameterAllocation(const AttrOrTypeDef &def,
470                                            raw_ostream &os) {
471   SmallVector<AttrOrTypeParameter> parameters;
472   def.getParameters(parameters);
473   FmtContext fmtCtxt = FmtContext().addSubst("_allocator", "allocator");
474   for (AttrOrTypeParameter &parameter : parameters) {
475     if (Optional<StringRef> allocCode = parameter.getAllocator()) {
476       fmtCtxt.withSelf(parameter.getName());
477       fmtCtxt.addSubst("_dst", parameter.getName());
478       os << "      " << tgfmt(*allocCode, &fmtCtxt) << "\n";
479     }
480   }
481 }
482 
483 /// Builds a code block that initializes the attribute storage of 'def'.
484 /// Attribute initialization is separated from Type initialization given that
485 /// the Attribute also needs to initialize its self-type, which has multiple
486 /// means of initialization.
487 static std::string buildAttributeStorageParamInitializer(
488     const AttrOrTypeDef &def, ArrayRef<AttrOrTypeParameter> parameters) {
489   std::string paramInitializer;
490   llvm::raw_string_ostream paramOS(paramInitializer);
491   paramOS << "::mlir::AttributeStorage(";
492 
493   // If this is an attribute, we need to check for value type initialization.
494   Optional<size_t> selfParamIndex;
495   for (auto it : llvm::enumerate(parameters)) {
496     const auto *selfParam = dyn_cast<AttributeSelfTypeParameter>(&it.value());
497     if (!selfParam)
498       continue;
499     if (selfParamIndex) {
500       llvm::PrintFatalError(def.getLoc(),
501                             "Only one attribute parameter can be marked as "
502                             "AttributeSelfTypeParameter");
503     }
504     paramOS << selfParam->getName();
505     selfParamIndex = it.index();
506   }
507 
508   // If we didn't find a self param, but the def has a type builder we use that
509   // to construct the type.
510   if (!selfParamIndex) {
511     const AttrDef &attrDef = cast<AttrDef>(def);
512     if (Optional<StringRef> typeBuilder = attrDef.getTypeBuilder()) {
513       FmtContext fmtContext;
514       for (const AttrOrTypeParameter &param : parameters)
515         fmtContext.addSubst(("_" + param.getName()).str(), param.getName());
516       paramOS << tgfmt(*typeBuilder, &fmtContext);
517     }
518   }
519   paramOS << ")";
520 
521   // Append the parameters to the initializer.
522   for (auto it : llvm::enumerate(parameters))
523     if (it.index() != selfParamIndex)
524       paramOS << llvm::formatv(", {0}({0})", it.value().getName());
525 
526   return paramOS.str();
527 }
528 
529 void DefGenerator::emitStorageClass(const AttrOrTypeDef &def) {
530   SmallVector<AttrOrTypeParameter, 4> params;
531   def.getParameters(params);
532 
533   // Collect the parameter types.
534   auto parameterTypes =
535       llvm::map_range(params, [](const AttrOrTypeParameter &parameter) {
536         return parameter.getCppType();
537       });
538   std::string parameterTypeList = llvm::join(parameterTypes, ", ");
539 
540   // Collect the parameter initializer.
541   std::string paramInitializer;
542   if (isAttrGenerator) {
543     paramInitializer = buildAttributeStorageParamInitializer(def, params);
544 
545   } else {
546     llvm::raw_string_ostream initOS(paramInitializer);
547     llvm::interleaveComma(params, initOS, [&](const AttrOrTypeParameter &it) {
548       initOS << llvm::formatv("{0}({0})", it.getName());
549     });
550   }
551 
552   // * Emit most of the storage class up until the hashKey body.
553   os << formatv(
554       defStorageClassBeginStr, def.getStorageNamespace(),
555       def.getStorageClassName(),
556       ParamCommaFormatter(ParamCommaFormatter::EmitFormat::TypeNamePairs,
557                           params, /*prependComma=*/false),
558       paramInitializer, parameterTypeList, valueType);
559 
560   // * Emit the comparison method.
561   os << "  bool operator==(const KeyTy &key) const {\n";
562   for (auto it : llvm::enumerate(params)) {
563     os << "    if (!(";
564 
565     // Build the comparator context.
566     bool isSelfType = isa<AttributeSelfTypeParameter>(it.value());
567     FmtContext context;
568     context.addSubst("_lhs", isSelfType ? "getType()" : it.value().getName())
569         .addSubst("_rhs", "std::get<" + Twine(it.index()) + ">(key)");
570 
571     // Use the parameter specified comparator if possible, otherwise default to
572     // operator==.
573     Optional<StringRef> comparator = it.value().getComparator();
574     os << tgfmt(comparator ? *comparator : "$_lhs == $_rhs", &context);
575     os << "))\n      return false;\n";
576   }
577   os << "    return true;\n  }\n";
578 
579   // * Emit the haskKey method.
580   os << "  static ::llvm::hash_code hashKey(const KeyTy &key) {\n";
581 
582   // Extract each parameter from the key.
583   os << "      return ::llvm::hash_combine(";
584   llvm::interleaveComma(
585       llvm::seq<unsigned>(0, params.size()), os,
586       [&](unsigned it) { os << "std::get<" << it << ">(key)"; });
587   os << ");\n    }\n";
588 
589   // * Emit the construct method.
590 
591   // If user wants to build the storage constructor themselves, declare it
592   // here and then they can write the definition elsewhere.
593   if (def.hasStorageCustomConstructor()) {
594     os << llvm::formatv("    static {0} *construct(::mlir::{1}StorageAllocator "
595                         "&allocator, const KeyTy &key);\n",
596                         def.getStorageClassName(), valueType);
597 
598     // Otherwise, generate one.
599   } else {
600     // First, unbox the parameters.
601     os << formatv(defStorageClassConstructorBeginStr, def.getStorageClassName(),
602                   valueType);
603     for (unsigned i = 0, e = params.size(); i < e; ++i) {
604       os << formatv("      auto {0} = std::get<{1}>(key);\n",
605                     params[i].getName(), i);
606     }
607 
608     // Second, reassign the parameter variables with allocation code, if it's
609     // specified.
610     emitStorageParameterAllocation(def, os);
611 
612     // Last, return an allocated copy.
613     auto parameterNames = llvm::map_range(
614         params, [](const auto &param) { return param.getName(); });
615     os << formatv(defStorageClassConstructorEndStr, def.getStorageClassName(),
616                   llvm::join(parameterNames, ", "));
617   }
618 
619   // * Emit the parameters as storage class members.
620   for (const AttrOrTypeParameter &parameter : params) {
621     // Attribute value types are not stored as fields in the storage.
622     if (!isa<AttributeSelfTypeParameter>(parameter))
623       os << "      " << parameter.getCppType() << " " << parameter.getName()
624          << ";\n";
625   }
626   os << "  };\n";
627 
628   os << "} // namespace " << def.getStorageNamespace() << "\n";
629 }
630 
631 void DefGenerator::emitParsePrint(const AttrOrTypeDef &def) {
632   // Emit the printer code, if specified.
633   if (Optional<StringRef> printerCode = def.getPrinterCode()) {
634     // Both the mnenomic and printerCode must be defined (for parity with
635     // parserCode).
636     os << "void " << def.getCppClassName()
637        << "::print(::mlir::DialectAsmPrinter &printer) const {\n";
638     if (printerCode->empty()) {
639       // If no code specified, emit error.
640       PrintFatalError(def.getLoc(),
641                       def.getName() +
642                           ": printer (if specified) must have non-empty code");
643     }
644     FmtContext fmtCtxt = FmtContext().addSubst("_printer", "printer");
645     os << tgfmt(*printerCode, &fmtCtxt) << "\n}\n";
646   }
647 
648   // Emit the parser code, if specified.
649   if (Optional<StringRef> parserCode = def.getParserCode()) {
650     FmtContext fmtCtxt;
651     fmtCtxt.addSubst("_parser", "parser").addSubst("_ctxt", "context");
652 
653     // The mnenomic must be defined so the dispatcher knows how to dispatch.
654     os << llvm::formatv("::mlir::{0} {1}::parse(::mlir::MLIRContext *context, "
655                         "::mlir::DialectAsmParser &parser",
656                         valueType, def.getCppClassName());
657     if (isAttrGenerator) {
658       // Attributes also accept a type parameter instead of a context.
659       os << ", ::mlir::Type type";
660       fmtCtxt.addSubst("_type", "type");
661     }
662     os << ") {\n";
663 
664     if (parserCode->empty()) {
665       PrintFatalError(def.getLoc(),
666                       def.getName() +
667                           ": parser (if specified) must have non-empty code");
668     }
669     os << tgfmt(*parserCode, &fmtCtxt) << "\n}\n";
670   }
671 }
672 
673 /// Replace all instances of 'from' to 'to' in `str` and return the new string.
674 static std::string replaceInStr(std::string str, StringRef from, StringRef to) {
675   size_t pos = 0;
676   while ((pos = str.find(from.data(), pos, from.size())) != std::string::npos)
677     str.replace(pos, from.size(), to.data(), to.size());
678   return str;
679 }
680 
681 /// Emit the builders for the given def.
682 static void emitBuilderDefs(const AttrOrTypeDef &def, raw_ostream &os,
683                             ArrayRef<AttrOrTypeParameter> params) {
684   bool genCheckedMethods = def.genVerifyDecl();
685   StringRef className = def.getCppClassName();
686   if (!def.skipDefaultBuilders()) {
687     os << llvm::formatv(
688         "{0} {0}::get(::mlir::MLIRContext *context{1}) {{\n"
689         "  return Base::get(context{2});\n}\n",
690         className,
691         ParamCommaFormatter(ParamCommaFormatter::EmitFormat::TypeNamePairs,
692                             params),
693         ParamCommaFormatter(ParamCommaFormatter::EmitFormat::JustParams,
694                             params));
695     if (genCheckedMethods) {
696       os << llvm::formatv(
697           "{0} {0}::getChecked("
698           "llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, "
699           "::mlir::MLIRContext *context{1}) {{\n"
700           "  return Base::getChecked(emitError, context{2});\n}\n",
701           className,
702           ParamCommaFormatter(ParamCommaFormatter::EmitFormat::TypeNamePairs,
703                               params),
704           ParamCommaFormatter(ParamCommaFormatter::EmitFormat::JustParams,
705                               params));
706     }
707   }
708 
709   auto builderFmtCtx =
710       FmtContext().addSubst("_ctxt", "context").addSubst("_get", "Base::get");
711   auto inferredCtxBuilderFmtCtx = FmtContext().addSubst("_get", "Base::get");
712   auto checkedBuilderFmtCtx = FmtContext().addSubst("_ctxt", "context");
713 
714   // Generate the builders specified by the user.
715   for (const AttrOrTypeBuilder &builder : def.getBuilders()) {
716     Optional<StringRef> body = builder.getBody();
717     if (!body)
718       continue;
719     std::string paramStr;
720     llvm::raw_string_ostream paramOS(paramStr);
721     llvm::interleaveComma(builder.getParameters(), paramOS,
722                           [&](const AttrOrTypeBuilder::Parameter &param) {
723                             // Note: AttrOrTypeBuilder parameters are guaranteed
724                             // to have names.
725                             paramOS << param.getCppType() << " "
726                                     << *param.getName();
727                           });
728     paramOS.flush();
729 
730     // Emit the `get` variant of the builder.
731     os << llvm::formatv("{0} {0}::get(", className);
732     if (!builder.hasInferredContextParameter()) {
733       os << "::mlir::MLIRContext *context";
734       if (!paramStr.empty())
735         os << ", ";
736       os << llvm::formatv("{0}) {{\n  {1};\n}\n", paramStr,
737                           tgfmt(*body, &builderFmtCtx).str());
738     } else {
739       os << llvm::formatv("{0}) {{\n  {1};\n}\n", paramStr,
740                           tgfmt(*body, &inferredCtxBuilderFmtCtx).str());
741     }
742 
743     // Emit the `getChecked` variant of the builder.
744     if (genCheckedMethods) {
745       os << llvm::formatv("{0} "
746                           "{0}::getChecked(llvm::function_ref<::mlir::"
747                           "InFlightDiagnostic()> emitErrorFn",
748                           className);
749       std::string checkedBody =
750           replaceInStr(body->str(), "$_get(", "Base::getChecked(emitErrorFn, ");
751       if (!builder.hasInferredContextParameter()) {
752         os << ", ::mlir::MLIRContext *context";
753         checkedBody = tgfmt(checkedBody, &checkedBuilderFmtCtx).str();
754       }
755       if (!paramStr.empty())
756         os << ", ";
757       os << llvm::formatv("{0}) {{\n  {1};\n}\n", paramStr, checkedBody);
758     }
759   }
760 }
761 
762 /// Print all the def-specific definition code.
763 void DefGenerator::emitDefDef(const AttrOrTypeDef &def) {
764   NamespaceEmitter ns(os, def.getDialect());
765 
766   SmallVector<AttrOrTypeParameter, 4> parameters;
767   def.getParameters(parameters);
768   if (!parameters.empty()) {
769     // Emit the storage class, if requested and necessary.
770     if (def.genStorageClass())
771       emitStorageClass(def);
772 
773     // Emit the builders for this def.
774     emitBuilderDefs(def, os, parameters);
775 
776     // Generate accessor definitions only if we also generate the storage class.
777     // Otherwise, let the user define the exact accessor definition.
778     if (def.genAccessors() && def.genStorageClass()) {
779       for (const AttrOrTypeParameter &param : parameters) {
780         SmallString<32> paramStorageName;
781         if (isa<AttributeSelfTypeParameter>(param)) {
782           Twine("getType().cast<" + param.getCppType() + ">()")
783               .toVector(paramStorageName);
784         } else {
785           paramStorageName = param.getName();
786         }
787 
788         SmallString<16> name = param.getName();
789         name[0] = llvm::toUpper(name[0]);
790         os << formatv("{0} {3}::get{1}() const {{ return getImpl()->{2}; }\n",
791                       param.getCppType(), name, paramStorageName,
792                       def.getCppClassName());
793       }
794     }
795   }
796 
797   // If mnemonic is specified maybe print definitions for the parser and printer
798   // code, if they're specified.
799   if (def.getMnemonic())
800     emitParsePrint(def);
801 }
802 
803 /// Emit the dialect printer/parser dispatcher. User's code should call these
804 /// functions from their dialect's print/parse methods.
805 void DefGenerator::emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs) {
806   if (llvm::none_of(defs, [](const AttrOrTypeDef &def) {
807         return def.getMnemonic().hasValue();
808       })) {
809     return;
810   }
811 
812   // The parser dispatch is just a list of if-elses, matching on the mnemonic
813   // and calling the def's parse function.
814   os << llvm::formatv(defParserDispatchStartStr, valueType,
815                       isAttrGenerator ? ", ::mlir::Type type" : "");
816   for (const AttrOrTypeDef &def : defs) {
817     if (def.getMnemonic()) {
818       os << formatv("  if (mnemonic == {0}::{1}::getMnemonic()) { \n"
819                     "    value = {0}::{1}::",
820                     def.getDialect().getCppNamespace(), def.getCppClassName());
821 
822       // If the def has no parameters and no parser code, just invoke a normal
823       // `get`.
824       if (def.getNumParameters() == 0 && !def.getParserCode()) {
825         os << "get(context);\n    return ::mlir::success(!!value);\n  }\n";
826         continue;
827       }
828 
829       os << "parse(context, parser" << (isAttrGenerator ? ", type" : "")
830          << ");\n    return ::mlir::success(!!value);\n  }\n";
831     }
832   }
833   os << "  return {};\n";
834   os << "}\n\n";
835 
836   // The printer dispatch uses llvm::TypeSwitch to find and call the correct
837   // printer.
838   os << llvm::formatv(defPrinterDispatchStartStr, valueType);
839   for (const AttrOrTypeDef &def : defs) {
840     Optional<StringRef> mnemonic = def.getMnemonic();
841     if (!mnemonic)
842       continue;
843 
844     StringRef cppNamespace = def.getDialect().getCppNamespace();
845     StringRef cppClassName = def.getCppClassName();
846     os << formatv("    .Case<{0}::{1}>([&]({0}::{1} t) {{\n      ",
847                   cppNamespace, cppClassName);
848 
849     // If the def has no parameters and no printer, just print the mnemonic.
850     if (def.getNumParameters() == 0 && !def.getPrinterCode()) {
851       os << formatv("printer << {0}::{1}::getMnemonic();", cppNamespace,
852                     cppClassName);
853     } else {
854       os << "t.print(printer);";
855     }
856     os << "\n      return ::mlir::success();\n    })\n";
857   }
858   os << llvm::formatv(
859       "    .Default([](::mlir::{0}) {{ return ::mlir::failure(); });\n}\n\n",
860       valueType);
861 }
862 
863 bool DefGenerator::emitDefs(StringRef selectedDialect) {
864   emitSourceFileHeader((defTypePrefix + "Def Definitions").str(), os);
865 
866   SmallVector<AttrOrTypeDef, 16> defs;
867   collectAllDefs(selectedDialect, defRecords, defs);
868   if (defs.empty())
869     return false;
870   emitTypeDefList(defs);
871 
872   IfDefScope scope("GET_" + defTypePrefix.upper() + "DEF_CLASSES", os);
873   emitParsePrintDispatch(defs);
874   for (const AttrOrTypeDef &def : defs)
875     emitDefDef(def);
876 
877   return false;
878 }
879 
880 //===----------------------------------------------------------------------===//
881 // GEN: Registration hooks
882 //===----------------------------------------------------------------------===//
883 
884 //===----------------------------------------------------------------------===//
885 // AttrDef
886 
887 static llvm::cl::OptionCategory attrdefGenCat("Options for -gen-attrdef-*");
888 static llvm::cl::opt<std::string>
889     attrDialect("attrdefs-dialect",
890                 llvm::cl::desc("Generate attributes for this dialect"),
891                 llvm::cl::cat(attrdefGenCat), llvm::cl::CommaSeparated);
892 
893 static mlir::GenRegistration
894     genAttrDefs("gen-attrdef-defs", "Generate AttrDef definitions",
895                 [](const llvm::RecordKeeper &records, raw_ostream &os) {
896                   AttrDefGenerator generator(records, os);
897                   return generator.emitDefs(attrDialect);
898                 });
899 static mlir::GenRegistration
900     genAttrDecls("gen-attrdef-decls", "Generate AttrDef declarations",
901                  [](const llvm::RecordKeeper &records, raw_ostream &os) {
902                    AttrDefGenerator generator(records, os);
903                    return generator.emitDecls(attrDialect);
904                  });
905 
906 //===----------------------------------------------------------------------===//
907 // TypeDef
908 
909 static llvm::cl::OptionCategory typedefGenCat("Options for -gen-typedef-*");
910 static llvm::cl::opt<std::string>
911     typeDialect("typedefs-dialect",
912                 llvm::cl::desc("Generate types for this dialect"),
913                 llvm::cl::cat(typedefGenCat), llvm::cl::CommaSeparated);
914 
915 static mlir::GenRegistration
916     genTypeDefs("gen-typedef-defs", "Generate TypeDef definitions",
917                 [](const llvm::RecordKeeper &records, raw_ostream &os) {
918                   TypeDefGenerator generator(records, os);
919                   return generator.emitDefs(typeDialect);
920                 });
921 static mlir::GenRegistration
922     genTypeDecls("gen-typedef-decls", "Generate TypeDef declarations",
923                  [](const llvm::RecordKeeper &records, raw_ostream &os) {
924                    TypeDefGenerator generator(records, os);
925                    return generator.emitDecls(typeDialect);
926                  });
927