1 //===- Operator.cpp - Operator class --------------------------------------===//
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 // Operator wrapper to simplify using TableGen Record defining a MLIR Op.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "mlir/TableGen/Operator.h"
14 #include "mlir/TableGen/Predicate.h"
15 #include "mlir/TableGen/Trait.h"
16 #include "mlir/TableGen/Type.h"
17 #include "llvm/ADT/EquivalenceClasses.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/Sequence.h"
20 #include "llvm/ADT/SmallPtrSet.h"
21 #include "llvm/ADT/StringExtras.h"
22 #include "llvm/ADT/TypeSwitch.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/FormatVariadic.h"
26 #include "llvm/TableGen/Error.h"
27 #include "llvm/TableGen/Record.h"
28
29 #define DEBUG_TYPE "mlir-tblgen-operator"
30
31 using namespace mlir;
32 using namespace mlir::tblgen;
33
34 using llvm::DagInit;
35 using llvm::DefInit;
36 using llvm::Record;
37
Operator(const llvm::Record & def)38 Operator::Operator(const llvm::Record &def)
39 : dialect(def.getValueAsDef("opDialect")), def(def) {
40 // The first `_` in the op's TableGen def name is treated as separating the
41 // dialect prefix and the op class name. The dialect prefix will be ignored if
42 // not empty. Otherwise, if def name starts with a `_`, the `_` is considered
43 // as part of the class name.
44 StringRef prefix;
45 std::tie(prefix, cppClassName) = def.getName().split('_');
46 if (prefix.empty()) {
47 // Class name with a leading underscore and without dialect prefix
48 cppClassName = def.getName();
49 } else if (cppClassName.empty()) {
50 // Class name without dialect prefix
51 cppClassName = prefix;
52 }
53
54 cppNamespace = def.getValueAsString("cppNamespace");
55
56 populateOpStructure();
57 assertInvariants();
58 }
59
getOperationName() const60 std::string Operator::getOperationName() const {
61 auto prefix = dialect.getName();
62 auto opName = def.getValueAsString("opName");
63 if (prefix.empty())
64 return std::string(opName);
65 return std::string(llvm::formatv("{0}.{1}", prefix, opName));
66 }
67
getAdaptorName() const68 std::string Operator::getAdaptorName() const {
69 return std::string(llvm::formatv("{0}Adaptor", getCppClassName()));
70 }
71
assertInvariants() const72 void Operator::assertInvariants() const {
73 // Check that the name of arguments/results/regions/successors don't overlap.
74 DenseMap<StringRef, StringRef> existingNames;
75 auto checkName = [&](StringRef name, StringRef entity) {
76 if (name.empty())
77 return;
78 auto insertion = existingNames.insert({name, entity});
79 if (insertion.second)
80 return;
81 if (entity == insertion.first->second)
82 PrintFatalError(getLoc(), "op has a conflict with two " + entity +
83 " having the same name '" + name + "'");
84 PrintFatalError(getLoc(), "op has a conflict with " +
85 insertion.first->second + " and " + entity +
86 " both having an entry with the name '" +
87 name + "'");
88 };
89 // Check operands amongst themselves.
90 for (int i : llvm::seq<int>(0, getNumOperands()))
91 checkName(getOperand(i).name, "operands");
92
93 // Check results amongst themselves and against operands.
94 for (int i : llvm::seq<int>(0, getNumResults()))
95 checkName(getResult(i).name, "results");
96
97 // Check regions amongst themselves and against operands and results.
98 for (int i : llvm::seq<int>(0, getNumRegions()))
99 checkName(getRegion(i).name, "regions");
100
101 // Check successors amongst themselves and against operands, results, and
102 // regions.
103 for (int i : llvm::seq<int>(0, getNumSuccessors()))
104 checkName(getSuccessor(i).name, "successors");
105 }
106
getDialectName() const107 StringRef Operator::getDialectName() const { return dialect.getName(); }
108
getCppClassName() const109 StringRef Operator::getCppClassName() const { return cppClassName; }
110
getQualCppClassName() const111 std::string Operator::getQualCppClassName() const {
112 if (cppNamespace.empty())
113 return std::string(cppClassName);
114 return std::string(llvm::formatv("{0}::{1}", cppNamespace, cppClassName));
115 }
116
getCppNamespace() const117 StringRef Operator::getCppNamespace() const { return cppNamespace; }
118
getNumResults() const119 int Operator::getNumResults() const {
120 DagInit *results = def.getValueAsDag("results");
121 return results->getNumArgs();
122 }
123
getExtraClassDeclaration() const124 StringRef Operator::getExtraClassDeclaration() const {
125 constexpr auto attr = "extraClassDeclaration";
126 if (def.isValueUnset(attr))
127 return {};
128 return def.getValueAsString(attr);
129 }
130
getExtraClassDefinition() const131 StringRef Operator::getExtraClassDefinition() const {
132 constexpr auto attr = "extraClassDefinition";
133 if (def.isValueUnset(attr))
134 return {};
135 return def.getValueAsString(attr);
136 }
137
getDef() const138 const llvm::Record &Operator::getDef() const { return def; }
139
skipDefaultBuilders() const140 bool Operator::skipDefaultBuilders() const {
141 return def.getValueAsBit("skipDefaultBuilders");
142 }
143
result_begin() const144 auto Operator::result_begin() const -> const_value_iterator {
145 return results.begin();
146 }
147
result_end() const148 auto Operator::result_end() const -> const_value_iterator {
149 return results.end();
150 }
151
getResults() const152 auto Operator::getResults() const -> const_value_range {
153 return {result_begin(), result_end()};
154 }
155
getResultTypeConstraint(int index) const156 TypeConstraint Operator::getResultTypeConstraint(int index) const {
157 DagInit *results = def.getValueAsDag("results");
158 return TypeConstraint(cast<DefInit>(results->getArg(index)));
159 }
160
getResultName(int index) const161 StringRef Operator::getResultName(int index) const {
162 DagInit *results = def.getValueAsDag("results");
163 return results->getArgNameStr(index);
164 }
165
getResultDecorators(int index) const166 auto Operator::getResultDecorators(int index) const -> var_decorator_range {
167 Record *result =
168 cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef();
169 if (!result->isSubClassOf("OpVariable"))
170 return var_decorator_range(nullptr, nullptr);
171 return *result->getValueAsListInit("decorators");
172 }
173
getNumVariableLengthResults() const174 unsigned Operator::getNumVariableLengthResults() const {
175 return llvm::count_if(results, [](const NamedTypeConstraint &c) {
176 return c.constraint.isVariableLength();
177 });
178 }
179
getNumVariableLengthOperands() const180 unsigned Operator::getNumVariableLengthOperands() const {
181 return llvm::count_if(operands, [](const NamedTypeConstraint &c) {
182 return c.constraint.isVariableLength();
183 });
184 }
185
hasSingleVariadicArg() const186 bool Operator::hasSingleVariadicArg() const {
187 return getNumArgs() == 1 && getArg(0).is<NamedTypeConstraint *>() &&
188 getOperand(0).isVariadic();
189 }
190
arg_begin() const191 Operator::arg_iterator Operator::arg_begin() const { return arguments.begin(); }
192
arg_end() const193 Operator::arg_iterator Operator::arg_end() const { return arguments.end(); }
194
getArgs() const195 Operator::arg_range Operator::getArgs() const {
196 return {arg_begin(), arg_end()};
197 }
198
getArgName(int index) const199 StringRef Operator::getArgName(int index) const {
200 DagInit *argumentValues = def.getValueAsDag("arguments");
201 return argumentValues->getArgNameStr(index);
202 }
203
getArgDecorators(int index) const204 auto Operator::getArgDecorators(int index) const -> var_decorator_range {
205 Record *arg =
206 cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef();
207 if (!arg->isSubClassOf("OpVariable"))
208 return var_decorator_range(nullptr, nullptr);
209 return *arg->getValueAsListInit("decorators");
210 }
211
getTrait(StringRef trait) const212 const Trait *Operator::getTrait(StringRef trait) const {
213 for (const auto &t : traits) {
214 if (const auto *traitDef = dyn_cast<NativeTrait>(&t)) {
215 if (traitDef->getFullyQualifiedTraitName() == trait)
216 return traitDef;
217 } else if (const auto *traitDef = dyn_cast<InternalTrait>(&t)) {
218 if (traitDef->getFullyQualifiedTraitName() == trait)
219 return traitDef;
220 } else if (const auto *traitDef = dyn_cast<InterfaceTrait>(&t)) {
221 if (traitDef->getFullyQualifiedTraitName() == trait)
222 return traitDef;
223 }
224 }
225 return nullptr;
226 }
227
region_begin() const228 auto Operator::region_begin() const -> const_region_iterator {
229 return regions.begin();
230 }
region_end() const231 auto Operator::region_end() const -> const_region_iterator {
232 return regions.end();
233 }
getRegions() const234 auto Operator::getRegions() const
235 -> llvm::iterator_range<const_region_iterator> {
236 return {region_begin(), region_end()};
237 }
238
getNumRegions() const239 unsigned Operator::getNumRegions() const { return regions.size(); }
240
getRegion(unsigned index) const241 const NamedRegion &Operator::getRegion(unsigned index) const {
242 return regions[index];
243 }
244
getNumVariadicRegions() const245 unsigned Operator::getNumVariadicRegions() const {
246 return llvm::count_if(regions,
247 [](const NamedRegion &c) { return c.isVariadic(); });
248 }
249
successor_begin() const250 auto Operator::successor_begin() const -> const_successor_iterator {
251 return successors.begin();
252 }
successor_end() const253 auto Operator::successor_end() const -> const_successor_iterator {
254 return successors.end();
255 }
getSuccessors() const256 auto Operator::getSuccessors() const
257 -> llvm::iterator_range<const_successor_iterator> {
258 return {successor_begin(), successor_end()};
259 }
260
getNumSuccessors() const261 unsigned Operator::getNumSuccessors() const { return successors.size(); }
262
getSuccessor(unsigned index) const263 const NamedSuccessor &Operator::getSuccessor(unsigned index) const {
264 return successors[index];
265 }
266
getNumVariadicSuccessors() const267 unsigned Operator::getNumVariadicSuccessors() const {
268 return llvm::count_if(successors,
269 [](const NamedSuccessor &c) { return c.isVariadic(); });
270 }
271
trait_begin() const272 auto Operator::trait_begin() const -> const_trait_iterator {
273 return traits.begin();
274 }
trait_end() const275 auto Operator::trait_end() const -> const_trait_iterator {
276 return traits.end();
277 }
getTraits() const278 auto Operator::getTraits() const -> llvm::iterator_range<const_trait_iterator> {
279 return {trait_begin(), trait_end()};
280 }
281
attribute_begin() const282 auto Operator::attribute_begin() const -> attribute_iterator {
283 return attributes.begin();
284 }
attribute_end() const285 auto Operator::attribute_end() const -> attribute_iterator {
286 return attributes.end();
287 }
getAttributes() const288 auto Operator::getAttributes() const
289 -> llvm::iterator_range<attribute_iterator> {
290 return {attribute_begin(), attribute_end()};
291 }
292
operand_begin() const293 auto Operator::operand_begin() const -> const_value_iterator {
294 return operands.begin();
295 }
operand_end() const296 auto Operator::operand_end() const -> const_value_iterator {
297 return operands.end();
298 }
getOperands() const299 auto Operator::getOperands() const -> const_value_range {
300 return {operand_begin(), operand_end()};
301 }
302
getArg(int index) const303 auto Operator::getArg(int index) const -> Argument { return arguments[index]; }
304
305 // Mapping from result index to combined argument and result index. Arguments
306 // are indexed to match getArg index, while the result indexes are mapped to
307 // avoid overlap.
resultIndex(int i)308 static int resultIndex(int i) { return -1 - i; }
309
isVariadic() const310 bool Operator::isVariadic() const {
311 return any_of(llvm::concat<const NamedTypeConstraint>(operands, results),
312 [](const NamedTypeConstraint &op) { return op.isVariadic(); });
313 }
314
populateTypeInferenceInfo(const llvm::StringMap<int> & argumentsAndResultsIndex)315 void Operator::populateTypeInferenceInfo(
316 const llvm::StringMap<int> &argumentsAndResultsIndex) {
317 // If the type inference op interface is not registered, then do not attempt
318 // to determine if the result types an be inferred.
319 auto &recordKeeper = def.getRecords();
320 auto *inferTrait = recordKeeper.getDef(inferTypeOpInterface);
321 allResultsHaveKnownTypes = false;
322 if (!inferTrait)
323 return;
324
325 // If there are no results, the skip this else the build method generated
326 // overlaps with another autogenerated builder.
327 if (getNumResults() == 0)
328 return;
329
330 // Skip ops with variadic or optional results.
331 if (getNumVariableLengthResults() > 0)
332 return;
333
334 // Skip cases currently being custom generated.
335 // TODO: Remove special cases.
336 if (getTrait("::mlir::OpTrait::SameOperandsAndResultType")) {
337 // Check for a non-variable length operand to use as the type anchor.
338 auto *operandI = llvm::find_if(arguments, [](const Argument &arg) {
339 NamedTypeConstraint *operand = arg.dyn_cast<NamedTypeConstraint *>();
340 return operand && !operand->isVariableLength();
341 });
342 if (operandI == arguments.end())
343 return;
344
345 // Map each of the result types to the anchor operation.
346 int operandIdx = operandI - arguments.begin();
347 resultTypeMapping.resize(getNumResults());
348 for (int i = 0; i < getNumResults(); ++i)
349 resultTypeMapping[i].emplace_back(operandIdx);
350
351 allResultsHaveKnownTypes = true;
352 traits.push_back(Trait::create(inferTrait->getDefInit()));
353 return;
354 }
355
356 // We create equivalence classes of argument/result types where arguments
357 // and results are mapped into the same index space and indices corresponding
358 // to the same type are in the same equivalence class.
359 llvm::EquivalenceClasses<int> ecs;
360 resultTypeMapping.resize(getNumResults());
361 // Captures the argument whose type matches a given result type. Preference
362 // towards capturing operands first before attributes.
363 auto captureMapping = [&](int i) {
364 bool found = false;
365 ecs.insert(resultIndex(i));
366 auto mi = ecs.findLeader(resultIndex(i));
367 for (auto me = ecs.member_end(); mi != me; ++mi) {
368 if (*mi < 0) {
369 auto tc = getResultTypeConstraint(i);
370 if (tc.getBuilderCall()) {
371 resultTypeMapping[i].emplace_back(tc);
372 found = true;
373 }
374 continue;
375 }
376
377 resultTypeMapping[i].emplace_back(*mi);
378 found = true;
379 }
380 return found;
381 };
382
383 for (const Trait &trait : traits) {
384 const llvm::Record &def = trait.getDef();
385 // If the infer type op interface was manually added, then treat it as
386 // intention that the op needs special handling.
387 // TODO: Reconsider whether to always generate, this is more conservative
388 // and keeps existing behavior so starting that way for now.
389 if (def.isSubClassOf(
390 llvm::formatv("{0}::Trait", inferTypeOpInterface).str()))
391 return;
392 if (const auto *traitDef = dyn_cast<InterfaceTrait>(&trait))
393 if (&traitDef->getDef() == inferTrait)
394 return;
395
396 if (!def.isSubClassOf("AllTypesMatch"))
397 continue;
398
399 auto values = def.getValueAsListOfStrings("values");
400 auto root = argumentsAndResultsIndex.lookup(values.front());
401 for (StringRef str : values)
402 ecs.unionSets(argumentsAndResultsIndex.lookup(str), root);
403 }
404
405 // Verifies that all output types have a corresponding known input type
406 // and chooses matching operand or attribute (in that order) that
407 // matches it.
408 allResultsHaveKnownTypes =
409 all_of(llvm::seq<int>(0, getNumResults()), captureMapping);
410
411 // If the types could be computed, then add type inference trait.
412 if (allResultsHaveKnownTypes)
413 traits.push_back(Trait::create(inferTrait->getDefInit()));
414 }
415
populateOpStructure()416 void Operator::populateOpStructure() {
417 auto &recordKeeper = def.getRecords();
418 auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint");
419 auto *attrClass = recordKeeper.getClass("Attr");
420 auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr");
421 auto *opVarClass = recordKeeper.getClass("OpVariable");
422 numNativeAttributes = 0;
423
424 DagInit *argumentValues = def.getValueAsDag("arguments");
425 unsigned numArgs = argumentValues->getNumArgs();
426
427 // Mapping from name of to argument or result index. Arguments are indexed
428 // to match getArg index, while the results are negatively indexed.
429 llvm::StringMap<int> argumentsAndResultsIndex;
430
431 // Handle operands and native attributes.
432 for (unsigned i = 0; i != numArgs; ++i) {
433 auto *arg = argumentValues->getArg(i);
434 auto givenName = argumentValues->getArgNameStr(i);
435 auto *argDefInit = dyn_cast<DefInit>(arg);
436 if (!argDefInit)
437 PrintFatalError(def.getLoc(),
438 Twine("undefined type for argument #") + Twine(i));
439 Record *argDef = argDefInit->getDef();
440 if (argDef->isSubClassOf(opVarClass))
441 argDef = argDef->getValueAsDef("constraint");
442
443 if (argDef->isSubClassOf(typeConstraintClass)) {
444 operands.push_back(
445 NamedTypeConstraint{givenName, TypeConstraint(argDef)});
446 } else if (argDef->isSubClassOf(attrClass)) {
447 if (givenName.empty())
448 PrintFatalError(argDef->getLoc(), "attributes must be named");
449 if (argDef->isSubClassOf(derivedAttrClass))
450 PrintFatalError(argDef->getLoc(),
451 "derived attributes not allowed in argument list");
452 attributes.push_back({givenName, Attribute(argDef)});
453 ++numNativeAttributes;
454 } else {
455 PrintFatalError(def.getLoc(), "unexpected def type; only defs deriving "
456 "from TypeConstraint or Attr are allowed");
457 }
458 if (!givenName.empty())
459 argumentsAndResultsIndex[givenName] = i;
460 }
461
462 // Handle derived attributes.
463 for (const auto &val : def.getValues()) {
464 if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) {
465 if (!record->isSubClassOf(attrClass))
466 continue;
467 if (!record->isSubClassOf(derivedAttrClass))
468 PrintFatalError(def.getLoc(),
469 "unexpected Attr where only DerivedAttr is allowed");
470
471 if (record->getClasses().size() != 1) {
472 PrintFatalError(
473 def.getLoc(),
474 "unsupported attribute modelling, only single class expected");
475 }
476 attributes.push_back(
477 {cast<llvm::StringInit>(val.getNameInit())->getValue(),
478 Attribute(cast<DefInit>(val.getValue()))});
479 }
480 }
481
482 // Populate `arguments`. This must happen after we've finalized `operands` and
483 // `attributes` because we will put their elements' pointers in `arguments`.
484 // SmallVector may perform re-allocation under the hood when adding new
485 // elements.
486 int operandIndex = 0, attrIndex = 0;
487 for (unsigned i = 0; i != numArgs; ++i) {
488 Record *argDef = dyn_cast<DefInit>(argumentValues->getArg(i))->getDef();
489 if (argDef->isSubClassOf(opVarClass))
490 argDef = argDef->getValueAsDef("constraint");
491
492 if (argDef->isSubClassOf(typeConstraintClass)) {
493 attrOrOperandMapping.push_back(
494 {OperandOrAttribute::Kind::Operand, operandIndex});
495 arguments.emplace_back(&operands[operandIndex++]);
496 } else {
497 assert(argDef->isSubClassOf(attrClass));
498 attrOrOperandMapping.push_back(
499 {OperandOrAttribute::Kind::Attribute, attrIndex});
500 arguments.emplace_back(&attributes[attrIndex++]);
501 }
502 }
503
504 auto *resultsDag = def.getValueAsDag("results");
505 auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator());
506 if (!outsOp || outsOp->getDef()->getName() != "outs") {
507 PrintFatalError(def.getLoc(), "'results' must have 'outs' directive");
508 }
509
510 // Handle results.
511 for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) {
512 auto name = resultsDag->getArgNameStr(i);
513 auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i));
514 if (!resultInit) {
515 PrintFatalError(def.getLoc(),
516 Twine("undefined type for result #") + Twine(i));
517 }
518 auto *resultDef = resultInit->getDef();
519 if (resultDef->isSubClassOf(opVarClass))
520 resultDef = resultDef->getValueAsDef("constraint");
521 results.push_back({name, TypeConstraint(resultDef)});
522 if (!name.empty())
523 argumentsAndResultsIndex[name] = resultIndex(i);
524
525 // We currently only support VariadicOfVariadic operands.
526 if (results.back().constraint.isVariadicOfVariadic()) {
527 PrintFatalError(
528 def.getLoc(),
529 "'VariadicOfVariadic' results are currently not supported");
530 }
531 }
532
533 // Handle successors
534 auto *successorsDag = def.getValueAsDag("successors");
535 auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator());
536 if (!successorsOp || successorsOp->getDef()->getName() != "successor") {
537 PrintFatalError(def.getLoc(),
538 "'successors' must have 'successor' directive");
539 }
540
541 for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) {
542 auto name = successorsDag->getArgNameStr(i);
543 auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i));
544 if (!successorInit) {
545 PrintFatalError(def.getLoc(),
546 Twine("undefined kind for successor #") + Twine(i));
547 }
548 Successor successor(successorInit->getDef());
549
550 // Only support variadic successors if it is the last one for now.
551 if (i != e - 1 && successor.isVariadic())
552 PrintFatalError(def.getLoc(), "only the last successor can be variadic");
553 successors.push_back({name, successor});
554 }
555
556 // Create list of traits, skipping over duplicates: appending to lists in
557 // tablegen is easy, making them unique less so, so dedupe here.
558 if (auto *traitList = def.getValueAsListInit("traits")) {
559 // This is uniquing based on pointers of the trait.
560 SmallPtrSet<const llvm::Init *, 32> traitSet;
561 traits.reserve(traitSet.size());
562
563 // The declaration order of traits imply the verification order of traits.
564 // Some traits may require other traits to be verified first then they can
565 // do further verification based on those verified facts. If you see this
566 // error, fix the traits declaration order by checking the `dependentTraits`
567 // field.
568 auto verifyTraitValidity = [&](Record *trait) {
569 auto *dependentTraits = trait->getValueAsListInit("dependentTraits");
570 for (auto *traitInit : *dependentTraits)
571 if (traitSet.find(traitInit) == traitSet.end())
572 PrintFatalError(
573 def.getLoc(),
574 trait->getValueAsString("trait") + " requires " +
575 cast<DefInit>(traitInit)->getDef()->getValueAsString(
576 "trait") +
577 " to precede it in traits list");
578 };
579
580 std::function<void(llvm::ListInit *)> insert;
581 insert = [&](llvm::ListInit *traitList) {
582 for (auto *traitInit : *traitList) {
583 auto *def = cast<DefInit>(traitInit)->getDef();
584 if (def->isSubClassOf("TraitList")) {
585 insert(def->getValueAsListInit("traits"));
586 continue;
587 }
588
589 // Verify if the trait has all the dependent traits declared before
590 // itself.
591 verifyTraitValidity(def);
592
593 // Keep traits in the same order while skipping over duplicates.
594 if (traitSet.insert(traitInit).second)
595 traits.push_back(Trait::create(traitInit));
596 }
597 };
598 insert(traitList);
599 }
600
601 populateTypeInferenceInfo(argumentsAndResultsIndex);
602
603 // Handle regions
604 auto *regionsDag = def.getValueAsDag("regions");
605 auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator());
606 if (!regionsOp || regionsOp->getDef()->getName() != "region") {
607 PrintFatalError(def.getLoc(), "'regions' must have 'region' directive");
608 }
609
610 for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) {
611 auto name = regionsDag->getArgNameStr(i);
612 auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i));
613 if (!regionInit) {
614 PrintFatalError(def.getLoc(),
615 Twine("undefined kind for region #") + Twine(i));
616 }
617 Region region(regionInit->getDef());
618 if (region.isVariadic()) {
619 // Only support variadic regions if it is the last one for now.
620 if (i != e - 1)
621 PrintFatalError(def.getLoc(), "only the last region can be variadic");
622 if (name.empty())
623 PrintFatalError(def.getLoc(), "variadic regions must be named");
624 }
625
626 regions.push_back({name, region});
627 }
628
629 // Populate the builders.
630 auto *builderList =
631 dyn_cast_or_null<llvm::ListInit>(def.getValueInit("builders"));
632 if (builderList && !builderList->empty()) {
633 for (llvm::Init *init : builderList->getValues())
634 builders.emplace_back(cast<llvm::DefInit>(init)->getDef(), def.getLoc());
635 } else if (skipDefaultBuilders()) {
636 PrintFatalError(
637 def.getLoc(),
638 "default builders are skipped and no custom builders provided");
639 }
640
641 LLVM_DEBUG(print(llvm::dbgs()));
642 }
643
getSameTypeAsResult(int index) const644 auto Operator::getSameTypeAsResult(int index) const -> ArrayRef<ArgOrType> {
645 assert(allResultTypesKnown());
646 return resultTypeMapping[index];
647 }
648
getLoc() const649 ArrayRef<SMLoc> Operator::getLoc() const { return def.getLoc(); }
650
hasDescription() const651 bool Operator::hasDescription() const {
652 return def.getValue("description") != nullptr;
653 }
654
getDescription() const655 StringRef Operator::getDescription() const {
656 return def.getValueAsString("description");
657 }
658
hasSummary() const659 bool Operator::hasSummary() const { return def.getValue("summary") != nullptr; }
660
getSummary() const661 StringRef Operator::getSummary() const {
662 return def.getValueAsString("summary");
663 }
664
hasAssemblyFormat() const665 bool Operator::hasAssemblyFormat() const {
666 auto *valueInit = def.getValueInit("assemblyFormat");
667 return isa<llvm::StringInit>(valueInit);
668 }
669
getAssemblyFormat() const670 StringRef Operator::getAssemblyFormat() const {
671 return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat"))
672 .Case<llvm::StringInit>([&](auto *init) { return init->getValue(); });
673 }
674
print(llvm::raw_ostream & os) const675 void Operator::print(llvm::raw_ostream &os) const {
676 os << "op '" << getOperationName() << "'\n";
677 for (Argument arg : arguments) {
678 if (auto *attr = arg.dyn_cast<NamedAttribute *>())
679 os << "[attribute] " << attr->name << '\n';
680 else
681 os << "[operand] " << arg.get<NamedTypeConstraint *>()->name << '\n';
682 }
683 }
684
unwrap(llvm::Init * init)685 auto Operator::VariableDecoratorIterator::unwrap(llvm::Init *init)
686 -> VariableDecorator {
687 return VariableDecorator(cast<llvm::DefInit>(init)->getDef());
688 }
689
getArgToOperandOrAttribute(int index) const690 auto Operator::getArgToOperandOrAttribute(int index) const
691 -> OperandOrAttribute {
692 return attrOrOperandMapping[index];
693 }
694
695 // Helper to return the names for accessor.
696 static SmallVector<std::string, 2>
getGetterOrSetterNames(bool isGetter,const Operator & op,StringRef name)697 getGetterOrSetterNames(bool isGetter, const Operator &op, StringRef name) {
698 Dialect::EmitPrefix prefixType = op.getDialect().getEmitAccessorPrefix();
699 std::string prefix;
700 if (prefixType != Dialect::EmitPrefix::Raw)
701 prefix = isGetter ? "get" : "set";
702
703 SmallVector<std::string, 2> names;
704 bool rawToo = prefixType == Dialect::EmitPrefix::Both;
705
706 // Whether to skip generating prefixed form for argument. This just does some
707 // basic checks.
708 //
709 // There are a little bit more invasive checks possible for cases where not
710 // all ops have the trait that would cause overlap. For many cases here,
711 // renaming would be better (e.g., we can only guard in limited manner against
712 // methods from traits and interfaces here, so avoiding these in op definition
713 // is safer).
714 auto skip = [&](StringRef newName) {
715 bool shouldSkip = newName == "getAttributeNames" ||
716 newName == "getAttributes" || newName == "getOperation";
717 if (newName == "getOperands") {
718 // To reduce noise, skip generating the prefixed form and the warning if
719 // $operands correspond to single variadic argument.
720 if (op.getNumOperands() == 1 && op.getNumVariableLengthOperands() == 1)
721 return true;
722 shouldSkip = true;
723 }
724 if (newName == "getRegions") {
725 if (op.getNumRegions() == 1 && op.getNumVariadicRegions() == 1)
726 return true;
727 shouldSkip = true;
728 }
729 if (newName == "getType") {
730 if (op.getNumResults() == 0)
731 return false;
732 shouldSkip = true;
733 }
734 if (!shouldSkip)
735 return false;
736
737 // This note could be avoided where the final function generated would
738 // have been identical. But preferably in the op definition avoiding using
739 // the generic name and then getting a more specialize type is better.
740 PrintNote(op.getLoc(),
741 "Skipping generation of prefixed accessor `" + newName +
742 "` as it overlaps with default one; generating raw form (`" +
743 name + "`) still");
744 return true;
745 };
746
747 if (!prefix.empty()) {
748 names.push_back(
749 prefix + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true));
750 // Skip cases which would overlap with default ones for now.
751 if (skip(names.back())) {
752 rawToo = true;
753 names.clear();
754 } else if (rawToo) {
755 LLVM_DEBUG(llvm::errs() << "WITH_GETTER(\"" << op.getQualCppClassName()
756 << "::" << name << "\")\n"
757 << "WITH_GETTER(\"" << op.getQualCppClassName()
758 << "Adaptor::" << name << "\")\n";);
759 }
760 }
761
762 if (prefix.empty() || rawToo)
763 names.push_back(name.str());
764 return names;
765 }
766
getGetterNames(StringRef name) const767 SmallVector<std::string, 2> Operator::getGetterNames(StringRef name) const {
768 return getGetterOrSetterNames(/*isGetter=*/true, *this, name);
769 }
770
getSetterNames(StringRef name) const771 SmallVector<std::string, 2> Operator::getSetterNames(StringRef name) const {
772 return getGetterOrSetterNames(/*isGetter=*/false, *this, name);
773 }
774