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 ¶m, 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 ¶m, 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 ¶meter : 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 ¶meter : 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 ¶meter : 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