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