1 //===- TypeDefGen.cpp - MLIR typeDef 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 // TypeDefGen uses the description of typeDefs to generate C++ definitions.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/Support/LogicalResult.h"
14 #include "mlir/TableGen/CodeGenHelpers.h"
15 #include "mlir/TableGen/Format.h"
16 #include "mlir/TableGen/GenInfo.h"
17 #include "mlir/TableGen/TypeDef.h"
18 #include "llvm/ADT/SmallSet.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/TableGen/Error.h"
21 #include "llvm/TableGen/TableGenBackend.h"
22 
23 #define DEBUG_TYPE "mlir-tblgen-typedefgen"
24 
25 using namespace mlir;
26 using namespace mlir::tblgen;
27 
28 static llvm::cl::OptionCategory typedefGenCat("Options for -gen-typedef-*");
29 static llvm::cl::opt<std::string>
30     selectedDialect("typedefs-dialect",
31                     llvm::cl::desc("Gen types for this dialect"),
32                     llvm::cl::cat(typedefGenCat), llvm::cl::CommaSeparated);
33 
34 /// Find all the TypeDefs for the specified dialect. If no dialect specified and
35 /// can only find one dialect's types, use that.
findAllTypeDefs(const llvm::RecordKeeper & recordKeeper,SmallVectorImpl<TypeDef> & typeDefs)36 static void findAllTypeDefs(const llvm::RecordKeeper &recordKeeper,
37                             SmallVectorImpl<TypeDef> &typeDefs) {
38   auto recDefs = recordKeeper.getAllDerivedDefinitions("TypeDef");
39   auto defs = llvm::map_range(
40       recDefs, [&](const llvm::Record *rec) { return TypeDef(rec); });
41   if (defs.empty())
42     return;
43 
44   StringRef dialectName;
45   if (selectedDialect.getNumOccurrences() == 0) {
46     if (defs.empty())
47       return;
48 
49     llvm::SmallSet<Dialect, 4> dialects;
50     for (const TypeDef &typeDef : defs)
51       dialects.insert(typeDef.getDialect());
52     if (dialects.size() != 1)
53       llvm::PrintFatalError("TypeDefs belonging to more than one dialect. Must "
54                             "select one via '--typedefs-dialect'");
55 
56     dialectName = (*dialects.begin()).getName();
57   } else if (selectedDialect.getNumOccurrences() == 1) {
58     dialectName = selectedDialect.getValue();
59   } else {
60     llvm::PrintFatalError("Cannot select multiple dialects for which to "
61                           "generate types via '--typedefs-dialect'.");
62   }
63 
64   for (const TypeDef &typeDef : defs)
65     if (typeDef.getDialect().getName().equals(dialectName))
66       typeDefs.push_back(typeDef);
67 }
68 
69 namespace {
70 
71 /// Pass an instance of this class to llvm::formatv() to emit a comma separated
72 /// list of parameters in the format by 'EmitFormat'.
73 class TypeParamCommaFormatter : public llvm::detail::format_adapter {
74 public:
75   /// Choose the output format
76   enum EmitFormat {
77     /// Emit "parameter1Type parameter1Name, parameter2Type parameter2Name,
78     /// [...]".
79     TypeNamePairs,
80 
81     /// Emit "parameter1(parameter1), parameter2(parameter2), [...]".
82     TypeNameInitializer,
83 
84     /// Emit "param1Name, param2Name, [...]".
85     JustParams,
86   };
87 
TypeParamCommaFormatter(EmitFormat emitFormat,ArrayRef<TypeParameter> params,bool prependComma=true)88   TypeParamCommaFormatter(EmitFormat emitFormat, ArrayRef<TypeParameter> params,
89                           bool prependComma = true)
90       : emitFormat(emitFormat), params(params), prependComma(prependComma) {}
91 
92   /// llvm::formatv will call this function when using an instance as a
93   /// replacement value.
format(raw_ostream & os,StringRef options)94   void format(raw_ostream &os, StringRef options) override {
95     if (params.size() && prependComma)
96       os << ", ";
97 
98     switch (emitFormat) {
99     case EmitFormat::TypeNamePairs:
100       interleaveComma(params, os,
101                       [&](const TypeParameter &p) { emitTypeNamePair(p, os); });
102       break;
103     case EmitFormat::TypeNameInitializer:
104       interleaveComma(params, os, [&](const TypeParameter &p) {
105         emitTypeNameInitializer(p, os);
106       });
107       break;
108     case EmitFormat::JustParams:
109       interleaveComma(params, os,
110                       [&](const TypeParameter &p) { os << p.getName(); });
111       break;
112     }
113   }
114 
115 private:
116   // Emit "paramType paramName".
emitTypeNamePair(const TypeParameter & param,raw_ostream & os)117   static void emitTypeNamePair(const TypeParameter &param, raw_ostream &os) {
118     os << param.getCppType() << " " << param.getName();
119   }
120   // Emit "paramName(paramName)"
emitTypeNameInitializer(const TypeParameter & param,raw_ostream & os)121   void emitTypeNameInitializer(const TypeParameter &param, raw_ostream &os) {
122     os << param.getName() << "(" << param.getName() << ")";
123   }
124 
125   EmitFormat emitFormat;
126   ArrayRef<TypeParameter> params;
127   bool prependComma;
128 };
129 
130 } // end anonymous namespace
131 
132 //===----------------------------------------------------------------------===//
133 // GEN: TypeDef declarations
134 //===----------------------------------------------------------------------===//
135 
136 /// The code block for the start of a typeDef class declaration -- singleton
137 /// case.
138 ///
139 /// {0}: The name of the typeDef class.
140 static const char *const typeDefDeclSingletonBeginStr = R"(
141   class {0}: public ::mlir::Type::TypeBase<{0}, ::mlir::Type, ::mlir::TypeStorage> {{
142   public:
143     /// Inherit some necessary constructors from 'TypeBase'.
144     using Base::Base;
145 
146 )";
147 
148 /// The code block for the start of a typeDef class declaration -- parametric
149 /// case.
150 ///
151 /// {0}: The name of the typeDef class.
152 /// {1}: The typeDef storage class namespace.
153 /// {2}: The storage class name.
154 /// {3}: The list of parameters with types.
155 static const char *const typeDefDeclParametricBeginStr = R"(
156   namespace {1} {
157     struct {2};
158   }
159   class {0}: public ::mlir::Type::TypeBase<{0}, ::mlir::Type,
160                                         {1}::{2}> {{
161   public:
162     /// Inherit some necessary constructors from 'TypeBase'.
163     using Base::Base;
164 
165 )";
166 
167 /// The snippet for print/parse.
168 static const char *const typeDefParsePrint = R"(
169     static ::mlir::Type parse(::mlir::MLIRContext* ctxt, ::mlir::DialectAsmParser& parser);
170     void print(::mlir::DialectAsmPrinter& printer) const;
171 )";
172 
173 /// The code block for the verifyConstructionInvariants and getChecked.
174 ///
175 /// {0}: List of parameters, parameters style.
176 static const char *const typeDefDeclVerifyStr = R"(
177     static ::mlir::LogicalResult verifyConstructionInvariants(Location loc{0});
178     static ::mlir::Type getChecked(Location loc{0});
179 )";
180 
181 /// Generate the declaration for the given typeDef class.
emitTypeDefDecl(const TypeDef & typeDef,raw_ostream & os)182 static void emitTypeDefDecl(const TypeDef &typeDef, raw_ostream &os) {
183   SmallVector<TypeParameter, 4> params;
184   typeDef.getParameters(params);
185 
186   // Emit the beginning string template: either the singleton or parametric
187   // template.
188   if (typeDef.getNumParameters() == 0)
189     os << formatv(typeDefDeclSingletonBeginStr, typeDef.getCppClassName(),
190                   typeDef.getStorageNamespace(), typeDef.getStorageClassName());
191   else
192     os << formatv(typeDefDeclParametricBeginStr, typeDef.getCppClassName(),
193                   typeDef.getStorageNamespace(), typeDef.getStorageClassName());
194 
195   // Emit the extra declarations first in case there's a type definition in
196   // there.
197   if (Optional<StringRef> extraDecl = typeDef.getExtraDecls())
198     os << *extraDecl << "\n";
199 
200   TypeParamCommaFormatter emitTypeNamePairsAfterComma(
201       TypeParamCommaFormatter::EmitFormat::TypeNamePairs, params);
202   os << llvm::formatv("    static {0} get(::mlir::MLIRContext* ctxt{1});\n",
203                       typeDef.getCppClassName(), emitTypeNamePairsAfterComma);
204 
205   // Emit the verify invariants declaration.
206   if (typeDef.genVerifyInvariantsDecl())
207     os << llvm::formatv(typeDefDeclVerifyStr, emitTypeNamePairsAfterComma);
208 
209   // Emit the mnenomic, if specified.
210   if (auto mnenomic = typeDef.getMnemonic()) {
211     os << "    static ::llvm::StringRef getMnemonic() { return \"" << mnenomic
212        << "\"; }\n";
213 
214     // If mnemonic specified, emit print/parse declarations.
215     os << typeDefParsePrint;
216   }
217 
218   if (typeDef.genAccessors()) {
219     SmallVector<TypeParameter, 4> parameters;
220     typeDef.getParameters(parameters);
221 
222     for (TypeParameter &parameter : parameters) {
223       SmallString<16> name = parameter.getName();
224       name[0] = llvm::toUpper(name[0]);
225       os << formatv("    {0} get{1}() const;\n", parameter.getCppType(), name);
226     }
227   }
228 
229   // End the typeDef decl.
230   os << "  };\n";
231 }
232 
233 /// Main entry point for decls.
emitTypeDefDecls(const llvm::RecordKeeper & recordKeeper,raw_ostream & os)234 static bool emitTypeDefDecls(const llvm::RecordKeeper &recordKeeper,
235                              raw_ostream &os) {
236   emitSourceFileHeader("TypeDef Declarations", os);
237 
238   SmallVector<TypeDef, 16> typeDefs;
239   findAllTypeDefs(recordKeeper, typeDefs);
240 
241   IfDefScope scope("GET_TYPEDEF_CLASSES", os);
242   if (typeDefs.size() > 0) {
243     NamespaceEmitter nsEmitter(os, typeDefs.begin()->getDialect());
244 
245     // Well known print/parse dispatch function declarations. These are called
246     // from Dialect::parseType() and Dialect::printType() methods.
247     os << "  ::mlir::Type generatedTypeParser(::mlir::MLIRContext* ctxt, "
248           "::mlir::DialectAsmParser& parser, ::llvm::StringRef mnenomic);\n";
249     os << "  ::mlir::LogicalResult generatedTypePrinter(::mlir::Type type, "
250           "::mlir::DialectAsmPrinter& printer);\n";
251     os << "\n";
252 
253     // Declare all the type classes first (in case they reference each other).
254     for (const TypeDef &typeDef : typeDefs)
255       os << "  class " << typeDef.getCppClassName() << ";\n";
256 
257     // Declare all the typedefs.
258     for (const TypeDef &typeDef : typeDefs)
259       emitTypeDefDecl(typeDef, os);
260   }
261 
262   return false;
263 }
264 
265 //===----------------------------------------------------------------------===//
266 // GEN: TypeDef list
267 //===----------------------------------------------------------------------===//
268 
emitTypeDefList(SmallVectorImpl<TypeDef> & typeDefs,raw_ostream & os)269 static void emitTypeDefList(SmallVectorImpl<TypeDef> &typeDefs,
270                             raw_ostream &os) {
271   IfDefScope scope("GET_TYPEDEF_LIST", os);
272   for (auto *i = typeDefs.begin(); i != typeDefs.end(); i++) {
273     os << i->getDialect().getCppNamespace() << "::" << i->getCppClassName();
274     if (i < typeDefs.end() - 1)
275       os << ",\n";
276     else
277       os << "\n";
278   }
279 }
280 
281 //===----------------------------------------------------------------------===//
282 // GEN: TypeDef definitions
283 //===----------------------------------------------------------------------===//
284 
285 /// Beginning of storage class.
286 /// {0}: Storage class namespace.
287 /// {1}: Storage class c++ name.
288 /// {2}: Parameters parameters.
289 /// {3}: Parameter initialzer string.
290 /// {4}: Parameter name list.
291 /// {5}: Parameter types.
292 static const char *const typeDefStorageClassBegin = R"(
293 namespace {0} {{
294   struct {1} : public ::mlir::TypeStorage {{
295     {1} ({2})
296       : {3} {{ }
297 
298     /// The hash key for this storage is a pair of the integer and type params.
299     using KeyTy = std::tuple<{5}>;
300 
301     /// Define the comparison function for the key type.
302     bool operator==(const KeyTy &key) const {{
303       return key == KeyTy({4});
304     }
305 )";
306 
307 /// The storage class' constructor template.
308 /// {0}: storage class name.
309 static const char *const typeDefStorageClassConstructorBegin = R"(
310     /// Define a construction method for creating a new instance of this storage.
311     static {0} *construct(::mlir::TypeStorageAllocator &allocator, const KeyTy &key) {{
312 )";
313 
314 /// The storage class' constructor return template.
315 /// {0}: storage class name.
316 /// {1}: list of parameters.
317 static const char *const typeDefStorageClassConstructorReturn = R"(
318       return new (allocator.allocate<{0}>())
319           {0}({1});
320     }
321 )";
322 
323 /// The code block for the getChecked definition.
324 ///
325 /// {0}: List of parameters, parameters style.
326 /// {1}: C++ type class name.
327 /// {2}: Comma separated list of parameter names.
328 static const char *const typeDefDefGetCheckeStr = R"(
329     ::mlir::Type {1}::getChecked(Location loc{0}) {{
330       return Base::getChecked(loc{2});
331     }
332 )";
333 
334 /// Use tgfmt to emit custom allocation code for each parameter, if necessary.
emitParameterAllocationCode(TypeDef & typeDef,raw_ostream & os)335 static void emitParameterAllocationCode(TypeDef &typeDef, raw_ostream &os) {
336   SmallVector<TypeParameter, 4> parameters;
337   typeDef.getParameters(parameters);
338   auto fmtCtxt = FmtContext().addSubst("_allocator", "allocator");
339   for (TypeParameter &parameter : parameters) {
340     auto allocCode = parameter.getAllocator();
341     if (allocCode) {
342       fmtCtxt.withSelf(parameter.getName());
343       fmtCtxt.addSubst("_dst", parameter.getName());
344       os << "      " << tgfmt(*allocCode, &fmtCtxt) << "\n";
345     }
346   }
347 }
348 
349 /// Emit the storage class code for type 'typeDef'.
350 /// This includes (in-order):
351 ///  1) typeDefStorageClassBegin, which includes:
352 ///      - The class constructor.
353 ///      - The KeyTy definition.
354 ///      - The equality (==) operator.
355 ///  2) The hashKey method.
356 ///  3) The construct method.
357 ///  4) The list of parameters as the storage class member variables.
emitStorageClass(TypeDef typeDef,raw_ostream & os)358 static void emitStorageClass(TypeDef typeDef, raw_ostream &os) {
359   SmallVector<TypeParameter, 4> parameters;
360   typeDef.getParameters(parameters);
361 
362   // Initialize a bunch of variables to be used later on.
363   auto parameterNames = map_range(
364       parameters, [](TypeParameter parameter) { return parameter.getName(); });
365   auto parameterTypes = map_range(parameters, [](TypeParameter parameter) {
366     return parameter.getCppType();
367   });
368   auto parameterList = join(parameterNames, ", ");
369   auto parameterTypeList = join(parameterTypes, ", ");
370 
371   // 1) Emit most of the storage class up until the hashKey body.
372   os << formatv(typeDefStorageClassBegin, typeDef.getStorageNamespace(),
373                 typeDef.getStorageClassName(),
374                 TypeParamCommaFormatter(
375                     TypeParamCommaFormatter::EmitFormat::TypeNamePairs,
376                     parameters, /*prependComma=*/false),
377                 TypeParamCommaFormatter(
378                     TypeParamCommaFormatter::EmitFormat::TypeNameInitializer,
379                     parameters, /*prependComma=*/false),
380                 parameterList, parameterTypeList);
381 
382   // 2) Emit the haskKey method.
383   os << "  static ::llvm::hash_code hashKey(const KeyTy &key) {\n";
384   // Extract each parameter from the key.
385   for (size_t i = 0, e = parameters.size(); i < e; ++i)
386     os << llvm::formatv("      const auto &{0} = std::get<{1}>(key);\n",
387                         parameters[i].getName(), i);
388   // Then combine them all. This requires all the parameters types to have a
389   // hash_value defined.
390   os << llvm::formatv(
391       "      return ::llvm::hash_combine({0});\n    }\n",
392       TypeParamCommaFormatter(TypeParamCommaFormatter::EmitFormat::JustParams,
393                               parameters, /* prependComma */ false));
394 
395   // 3) Emit the construct method.
396   if (typeDef.hasStorageCustomConstructor())
397     // If user wants to build the storage constructor themselves, declare it
398     // here and then they can write the definition elsewhere.
399     os << "    static " << typeDef.getStorageClassName()
400        << " *construct(::mlir::TypeStorageAllocator &allocator, const KeyTy "
401           "&key);\n";
402   else {
403     // If not, autogenerate one.
404 
405     // First, unbox the parameters.
406     os << formatv(typeDefStorageClassConstructorBegin,
407                   typeDef.getStorageClassName());
408     for (size_t i = 0; i < parameters.size(); ++i) {
409       os << formatv("      auto {0} = std::get<{1}>(key);\n",
410                     parameters[i].getName(), i);
411     }
412     // Second, reassign the parameter variables with allocation code, if it's
413     // specified.
414     emitParameterAllocationCode(typeDef, os);
415 
416     // Last, return an allocated copy.
417     os << formatv(typeDefStorageClassConstructorReturn,
418                   typeDef.getStorageClassName(), parameterList);
419   }
420 
421   // 4) Emit the parameters as storage class members.
422   for (auto parameter : parameters) {
423     os << "      " << parameter.getCppType() << " " << parameter.getName()
424        << ";\n";
425   }
426   os << "  };\n";
427 
428   os << "} // namespace " << typeDef.getStorageNamespace() << "\n";
429 }
430 
431 /// Emit the parser and printer for a particular type, if they're specified.
emitParserPrinter(TypeDef typeDef,raw_ostream & os)432 void emitParserPrinter(TypeDef typeDef, raw_ostream &os) {
433   // Emit the printer code, if specified.
434   if (auto printerCode = typeDef.getPrinterCode()) {
435     // Both the mnenomic and printerCode must be defined (for parity with
436     // parserCode).
437     os << "void " << typeDef.getCppClassName()
438        << "::print(::mlir::DialectAsmPrinter& printer) const {\n";
439     if (*printerCode == "") {
440       // If no code specified, emit error.
441       PrintFatalError(typeDef.getLoc(),
442                       typeDef.getName() +
443                           ": printer (if specified) must have non-empty code");
444     }
445     auto fmtCtxt = FmtContext().addSubst("_printer", "printer");
446     os << tgfmt(*printerCode, &fmtCtxt) << "\n}\n";
447   }
448 
449   // emit a parser, if specified.
450   if (auto parserCode = typeDef.getParserCode()) {
451     // The mnenomic must be defined so the dispatcher knows how to dispatch.
452     os << "::mlir::Type " << typeDef.getCppClassName()
453        << "::parse(::mlir::MLIRContext* ctxt, ::mlir::DialectAsmParser& "
454           "parser) "
455           "{\n";
456     if (*parserCode == "") {
457       // if no code specified, emit error.
458       PrintFatalError(typeDef.getLoc(),
459                       typeDef.getName() +
460                           ": parser (if specified) must have non-empty code");
461     }
462     auto fmtCtxt =
463         FmtContext().addSubst("_parser", "parser").addSubst("_ctxt", "ctxt");
464     os << tgfmt(*parserCode, &fmtCtxt) << "\n}\n";
465   }
466 }
467 
468 /// Print all the typedef-specific definition code.
emitTypeDefDef(TypeDef typeDef,raw_ostream & os)469 static void emitTypeDefDef(TypeDef typeDef, raw_ostream &os) {
470   NamespaceEmitter ns(os, typeDef.getDialect());
471   SmallVector<TypeParameter, 4> parameters;
472   typeDef.getParameters(parameters);
473 
474   // Emit the storage class, if requested and necessary.
475   if (typeDef.genStorageClass() && typeDef.getNumParameters() > 0)
476     emitStorageClass(typeDef, os);
477 
478   os << llvm::formatv(
479       "{0} {0}::get(::mlir::MLIRContext* ctxt{1}) {{\n"
480       "  return Base::get(ctxt{2});\n}\n",
481       typeDef.getCppClassName(),
482       TypeParamCommaFormatter(
483           TypeParamCommaFormatter::EmitFormat::TypeNamePairs, parameters),
484       TypeParamCommaFormatter(TypeParamCommaFormatter::EmitFormat::JustParams,
485                               parameters));
486 
487   // Emit the parameter accessors.
488   if (typeDef.genAccessors())
489     for (const TypeParameter &parameter : parameters) {
490       SmallString<16> name = parameter.getName();
491       name[0] = llvm::toUpper(name[0]);
492       os << formatv("{0} {3}::get{1}() const { return getImpl()->{2}; }\n",
493                     parameter.getCppType(), name, parameter.getName(),
494                     typeDef.getCppClassName());
495     }
496 
497   // Generate getChecked() method.
498   if (typeDef.genVerifyInvariantsDecl()) {
499     os << llvm::formatv(
500         typeDefDefGetCheckeStr,
501         TypeParamCommaFormatter(
502             TypeParamCommaFormatter::EmitFormat::TypeNamePairs, parameters),
503         typeDef.getCppClassName(),
504         TypeParamCommaFormatter(TypeParamCommaFormatter::EmitFormat::JustParams,
505                                 parameters));
506   }
507 
508   // If mnemonic is specified maybe print definitions for the parser and printer
509   // code, if they're specified.
510   if (typeDef.getMnemonic())
511     emitParserPrinter(typeDef, os);
512 }
513 
514 /// Emit the dialect printer/parser dispatcher. User's code should call these
515 /// functions from their dialect's print/parse methods.
emitParsePrintDispatch(SmallVectorImpl<TypeDef> & typeDefs,raw_ostream & os)516 static void emitParsePrintDispatch(SmallVectorImpl<TypeDef> &typeDefs,
517                                    raw_ostream &os) {
518   if (typeDefs.size() == 0)
519     return;
520   const Dialect &dialect = typeDefs.begin()->getDialect();
521   NamespaceEmitter ns(os, dialect);
522 
523   // The parser dispatch is just a list of if-elses, matching on the mnemonic
524   // and calling the class's parse function.
525   os << "::mlir::Type generatedTypeParser(::mlir::MLIRContext* ctxt, "
526         "::mlir::DialectAsmParser& parser, ::llvm::StringRef mnemonic) {\n";
527   for (const TypeDef &typeDef : typeDefs)
528     if (typeDef.getMnemonic())
529       os << formatv("  if (mnemonic == {0}::{1}::getMnemonic()) return "
530                     "{0}::{1}::parse(ctxt, parser);\n",
531                     typeDef.getDialect().getCppNamespace(),
532                     typeDef.getCppClassName());
533   os << "  return ::mlir::Type();\n";
534   os << "}\n\n";
535 
536   // The printer dispatch uses llvm::TypeSwitch to find and call the correct
537   // printer.
538   os << "::mlir::LogicalResult generatedTypePrinter(::mlir::Type type, "
539         "::mlir::DialectAsmPrinter& printer) {\n"
540      << "  ::mlir::LogicalResult found = ::mlir::success();\n"
541      << "  ::llvm::TypeSwitch<::mlir::Type>(type)\n";
542   for (auto typeDef : typeDefs)
543     if (typeDef.getMnemonic())
544       os << formatv("    .Case<{0}::{1}>([&](::mlir::Type t) {{ "
545                     "t.dyn_cast<{0}::{1}>().print(printer); })\n",
546                     typeDef.getDialect().getCppNamespace(),
547                     typeDef.getCppClassName());
548   os << "    .Default([&found](::mlir::Type) { found = ::mlir::failure(); "
549         "});\n"
550      << "  return found;\n"
551      << "}\n\n";
552 }
553 
554 /// Entry point for typedef definitions.
emitTypeDefDefs(const llvm::RecordKeeper & recordKeeper,raw_ostream & os)555 static bool emitTypeDefDefs(const llvm::RecordKeeper &recordKeeper,
556                             raw_ostream &os) {
557   emitSourceFileHeader("TypeDef Definitions", os);
558 
559   SmallVector<TypeDef, 16> typeDefs;
560   findAllTypeDefs(recordKeeper, typeDefs);
561   emitTypeDefList(typeDefs, os);
562 
563   IfDefScope scope("GET_TYPEDEF_CLASSES", os);
564   emitParsePrintDispatch(typeDefs, os);
565   for (auto typeDef : typeDefs)
566     emitTypeDefDef(typeDef, os);
567 
568   return false;
569 }
570 
571 //===----------------------------------------------------------------------===//
572 // GEN: TypeDef registration hooks
573 //===----------------------------------------------------------------------===//
574 
575 static mlir::GenRegistration
576     genTypeDefDefs("gen-typedef-defs", "Generate TypeDef definitions",
__anon99a013530802(const llvm::RecordKeeper &records, raw_ostream &os) 577                    [](const llvm::RecordKeeper &records, raw_ostream &os) {
578                      return emitTypeDefDefs(records, os);
579                    });
580 
581 static mlir::GenRegistration
582     genTypeDefDecls("gen-typedef-decls", "Generate TypeDef declarations",
__anon99a013530902(const llvm::RecordKeeper &records, raw_ostream &os) 583                     [](const llvm::RecordKeeper &records, raw_ostream &os) {
584                       return emitTypeDefDecls(records, os);
585                     });
586