MLIR  22.0.0git
Operator.cpp
Go to the documentation of this file.
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/Argument.h"
16 #include "mlir/TableGen/Trait.h"
17 #include "mlir/TableGen/Type.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::Init;
37 using llvm::ListInit;
38 using llvm::Record;
39 using llvm::StringInit;
40 
41 Operator::Operator(const Record &def)
42  : dialect(def.getValueAsDef("opDialect")), def(def) {
43  // The first `_` in the op's TableGen def name is treated as separating the
44  // dialect prefix and the op class name. The dialect prefix will be ignored if
45  // not empty. Otherwise, if def name starts with a `_`, the `_` is considered
46  // as part of the class name.
47  StringRef prefix;
48  std::tie(prefix, cppClassName) = def.getName().split('_');
49  if (prefix.empty()) {
50  // Class name with a leading underscore and without dialect prefix
51  cppClassName = def.getName();
52  } else if (cppClassName.empty()) {
53  // Class name without dialect prefix
54  cppClassName = prefix;
55  }
56 
57  cppNamespace = def.getValueAsString("cppNamespace");
58 
59  populateOpStructure();
60  assertInvariants();
61 }
62 
63 std::string Operator::getOperationName() const {
64  auto prefix = dialect.getName();
65  auto opName = def.getValueAsString("opName");
66  if (prefix.empty())
67  return std::string(opName);
68  return std::string(llvm::formatv("{0}.{1}", prefix, opName));
69 }
70 
71 std::string Operator::getAdaptorName() const {
72  return std::string(llvm::formatv("{0}Adaptor", getCppClassName()));
73 }
74 
75 std::string Operator::getGenericAdaptorName() const {
76  return std::string(llvm::formatv("{0}GenericAdaptor", getCppClassName()));
77 }
78 
79 /// Assert the invariants of accessors generated for the given name.
80 static void assertAccessorInvariants(const Operator &op, StringRef name) {
81  std::string accessorName =
82  convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true);
83 
84  // Functor used to detect when an accessor will cause an overlap with an
85  // operation API.
86  //
87  // There are a little bit more invasive checks possible for cases where not
88  // all ops have the trait that would cause overlap. For many cases here,
89  // renaming would be better (e.g., we can only guard in limited manner
90  // against methods from traits and interfaces here, so avoiding these in op
91  // definition is safer).
92  auto nameOverlapsWithOpAPI = [&](StringRef newName) {
93  if (newName == "AttributeNames" || newName == "Attributes" ||
94  newName == "Operation")
95  return true;
96  if (newName == "Operands")
97  return op.getNumOperands() != 1 || op.getNumVariableLengthOperands() != 1;
98  if (newName == "Regions")
99  return op.getNumRegions() != 1 || op.getNumVariadicRegions() != 1;
100  if (newName == "Type")
101  return op.getNumResults() != 1;
102  return false;
103  };
104  if (nameOverlapsWithOpAPI(accessorName)) {
105  // This error could be avoided in situations where the final function is
106  // identical, but preferably the op definition should avoid using generic
107  // names.
108  PrintFatalError(op.getLoc(), "generated accessor for `" + name +
109  "` overlaps with a default one; please "
110  "rename to avoid overlap");
111  }
112 }
113 
115  // Check that the name of arguments/results/regions/successors don't overlap.
116  DenseMap<StringRef, StringRef> existingNames;
117  auto checkName = [&](StringRef name, StringRef entity) {
118  if (name.empty())
119  return;
120  auto insertion = existingNames.insert({name, entity});
121  if (insertion.second) {
122  // Assert invariants for accessors generated for this name.
123  assertAccessorInvariants(*this, name);
124  return;
125  }
126  if (entity == insertion.first->second)
127  PrintFatalError(getLoc(), "op has a conflict with two " + entity +
128  " having the same name '" + name + "'");
129  PrintFatalError(getLoc(), "op has a conflict with " +
130  insertion.first->second + " and " + entity +
131  " both having an entry with the name '" +
132  name + "'");
133  };
134  // Check operands amongst themselves.
135  for (int i : llvm::seq<int>(0, getNumOperands()))
136  checkName(getOperand(i).name, "operands");
137 
138  // Check results amongst themselves and against operands.
139  for (int i : llvm::seq<int>(0, getNumResults()))
140  checkName(getResult(i).name, "results");
141 
142  // Check regions amongst themselves and against operands and results.
143  for (int i : llvm::seq<int>(0, getNumRegions()))
144  checkName(getRegion(i).name, "regions");
145 
146  // Check successors amongst themselves and against operands, results, and
147  // regions.
148  for (int i : llvm::seq<int>(0, getNumSuccessors()))
149  checkName(getSuccessor(i).name, "successors");
150 }
151 
152 StringRef Operator::getDialectName() const { return dialect.getName(); }
153 
154 StringRef Operator::getCppClassName() const { return cppClassName; }
155 
156 std::string Operator::getQualCppClassName() const {
157  if (cppNamespace.empty())
158  return std::string(cppClassName);
159  return std::string(llvm::formatv("{0}::{1}", cppNamespace, cppClassName));
160 }
161 
162 StringRef Operator::getCppNamespace() const { return cppNamespace; }
163 
165  const DagInit *results = def.getValueAsDag("results");
166  return results->getNumArgs();
167 }
168 
170  constexpr auto attr = "extraClassDeclaration";
171  if (def.isValueUnset(attr))
172  return {};
173  return def.getValueAsString(attr);
174 }
175 
177  constexpr auto attr = "extraClassDefinition";
178  if (def.isValueUnset(attr))
179  return {};
180  return def.getValueAsString(attr);
181 }
182 
183 const Record &Operator::getDef() const { return def; }
184 
186  return def.getValueAsBit("skipDefaultBuilders");
187 }
188 
190  return results.begin();
191 }
192 
194  return results.end();
195 }
196 
198  return {result_begin(), result_end()};
199 }
200 
202  const DagInit *results = def.getValueAsDag("results");
203  return TypeConstraint(cast<DefInit>(results->getArg(index)));
204 }
205 
206 StringRef Operator::getResultName(int index) const {
207  const DagInit *results = def.getValueAsDag("results");
208  return results->getArgNameStr(index);
209 }
210 
212  const Record *result =
213  cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef();
214  if (!result->isSubClassOf("OpVariable"))
215  return var_decorator_range(nullptr, nullptr);
216  return *result->getValueAsListInit("decorators");
217 }
218 
220  return llvm::count_if(results, [](const NamedTypeConstraint &c) {
221  return c.constraint.isVariableLength();
222  });
223 }
224 
226  return llvm::count_if(operands, [](const NamedTypeConstraint &c) {
227  return c.constraint.isVariableLength();
228  });
229 }
230 
232  return getNumArgs() == 1 && isa<NamedTypeConstraint *>(getArg(0)) &&
233  getOperand(0).isVariadic();
234 }
235 
236 Operator::arg_iterator Operator::arg_begin() const { return arguments.begin(); }
237 
238 Operator::arg_iterator Operator::arg_end() const { return arguments.end(); }
239 
241  return {arg_begin(), arg_end()};
242 }
243 
244 StringRef Operator::getArgName(int index) const {
245  const DagInit *argumentValues = def.getValueAsDag("arguments");
246  return argumentValues->getArgNameStr(index);
247 }
248 
250  const Record *arg =
251  cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef();
252  if (!arg->isSubClassOf("OpVariable"))
253  return var_decorator_range(nullptr, nullptr);
254  return *arg->getValueAsListInit("decorators");
255 }
256 
257 const Trait *Operator::getTrait(StringRef trait) const {
258  for (const auto &t : traits) {
259  if (const auto *traitDef = dyn_cast<NativeTrait>(&t)) {
260  if (traitDef->getFullyQualifiedTraitName() == trait)
261  return traitDef;
262  } else if (const auto *traitDef = dyn_cast<InternalTrait>(&t)) {
263  if (traitDef->getFullyQualifiedTraitName() == trait)
264  return traitDef;
265  } else if (const auto *traitDef = dyn_cast<InterfaceTrait>(&t)) {
266  if (traitDef->getFullyQualifiedTraitName() == trait)
267  return traitDef;
268  }
269  }
270  return nullptr;
271 }
272 
274  return regions.begin();
275 }
277  return regions.end();
278 }
281  return {region_begin(), region_end()};
282 }
283 
284 unsigned Operator::getNumRegions() const { return regions.size(); }
285 
286 const NamedRegion &Operator::getRegion(unsigned index) const {
287  return regions[index];
288 }
289 
291  return llvm::count_if(regions,
292  [](const NamedRegion &c) { return c.isVariadic(); });
293 }
294 
296  return successors.begin();
297 }
299  return successors.end();
300 }
303  return {successor_begin(), successor_end()};
304 }
305 
306 unsigned Operator::getNumSuccessors() const { return successors.size(); }
307 
308 const NamedSuccessor &Operator::getSuccessor(unsigned index) const {
309  return successors[index];
310 }
311 
313  return llvm::count_if(successors,
314  [](const NamedSuccessor &c) { return c.isVariadic(); });
315 }
316 
318  return traits.begin();
319 }
321  return traits.end();
322 }
324  return {trait_begin(), trait_end()};
325 }
326 
328  return attributes.begin();
329 }
331  return attributes.end();
332 }
335  return {attribute_begin(), attribute_end()};
336 }
338  return attributes.begin();
339 }
341  return attributes.end();
342 }
344  return {attribute_begin(), attribute_end()};
345 }
346 
348  return operands.begin();
349 }
351  return operands.end();
352 }
354  return {operand_begin(), operand_end()};
355 }
356 
357 auto Operator::getArg(int index) const -> Argument { return arguments[index]; }
358 
359 bool Operator::isVariadic() const {
360  return any_of(llvm::concat<const NamedTypeConstraint>(operands, results),
361  [](const NamedTypeConstraint &op) { return op.isVariadic(); });
362 }
363 
364 void Operator::populateTypeInferenceInfo(
365  const llvm::StringMap<int> &argumentsAndResultsIndex) {
366  // If the type inference op interface is not registered, then do not attempt
367  // to determine if the result types an be inferred.
368  auto &recordKeeper = def.getRecords();
369  auto *inferTrait = recordKeeper.getDef(inferTypeOpInterface);
370  allResultsHaveKnownTypes = false;
371  if (!inferTrait)
372  return;
373 
374  // If there are no results, the skip this else the build method generated
375  // overlaps with another autogenerated builder.
376  if (getNumResults() == 0)
377  return;
378 
379  // Skip ops with variadic or optional results.
380  if (getNumVariableLengthResults() > 0)
381  return;
382 
383  // Skip cases currently being custom generated.
384  // TODO: Remove special cases.
385  if (getTrait("::mlir::OpTrait::SameOperandsAndResultType")) {
386  // Check for a non-variable length operand to use as the type anchor.
387  auto *operandI = llvm::find_if(arguments, [](const Argument &arg) {
388  NamedTypeConstraint *operand = llvm::dyn_cast_if_present<NamedTypeConstraint *>(arg);
389  return operand && !operand->isVariableLength();
390  });
391  if (operandI == arguments.end())
392  return;
393 
394  // All result types are inferred from the operand type.
395  int operandIdx = operandI - arguments.begin();
396  for (int i = 0; i < getNumResults(); ++i)
397  resultTypeMapping.emplace_back(operandIdx, "$_self");
398 
399  allResultsHaveKnownTypes = true;
400  traits.push_back(Trait::create(inferTrait->getDefInit()));
401  return;
402  }
403 
404  /// This struct represents a node in this operation's result type inferenece
405  /// graph. Each node has a list of incoming type inference edges `sources`.
406  /// Each edge represents a "source" from which the result type can be
407  /// inferred, either an operand (leaf) or another result (node). When a node
408  /// is known to have a fully-inferred type, `inferred` is set to true.
409  struct ResultTypeInference {
410  /// The list of incoming type inference edges.
412  /// This flag is set to true when the result type is known to be inferrable.
413  bool inferred = false;
414  };
415 
416  // This vector represents the type inference graph, with one node for each
417  // operation result. The nth element is the node for the nth result.
419 
420  // For all results whose types are buildable, initialize their type inference
421  // nodes with an edge to themselves. Mark those nodes are fully-inferred.
422  for (auto [idx, infer] : llvm::enumerate(inference)) {
423  if (getResult(idx).constraint.getBuilderCall()) {
424  infer.sources.emplace_back(InferredResultType::mapResultIndex(idx),
425  "$_self");
426  infer.inferred = true;
427  }
428  }
429 
430  // Use `AllTypesMatch` and `TypesMatchWith` operation traits to build the
431  // result type inference graph.
432  for (const Trait &trait : traits) {
433  const Record &def = trait.getDef();
434 
435  // If the infer type op interface was manually added, then treat it as
436  // intention that the op needs special handling.
437  // TODO: Reconsider whether to always generate, this is more conservative
438  // and keeps existing behavior so starting that way for now.
439  if (def.isSubClassOf(
440  llvm::formatv("{0}::Trait", inferTypeOpInterface).str()))
441  return;
442  if (const auto *traitDef = dyn_cast<InterfaceTrait>(&trait))
443  if (&traitDef->getDef() == inferTrait)
444  return;
445 
446  // The `TypesMatchWith` trait represents a 1 -> 1 type inference edge with a
447  // type transformer.
448  if (def.isSubClassOf("TypesMatchWith")) {
449  int target = argumentsAndResultsIndex.lookup(def.getValueAsString("rhs"));
450  // Ignore operand type inference.
451  if (InferredResultType::isArgIndex(target))
452  continue;
453  int resultIndex = InferredResultType::unmapResultIndex(target);
454  ResultTypeInference &infer = inference[resultIndex];
455  // If the type of the result has already been inferred, do nothing.
456  if (infer.inferred)
457  continue;
458  int sourceIndex =
459  argumentsAndResultsIndex.lookup(def.getValueAsString("lhs"));
460  infer.sources.emplace_back(sourceIndex,
461  def.getValueAsString("transformer").str());
462  // Locally propagate inferredness.
463  infer.inferred =
464  InferredResultType::isArgIndex(sourceIndex) ||
465  inference[InferredResultType::unmapResultIndex(sourceIndex)].inferred;
466  continue;
467  }
468 
469  // The `ShapedTypeMatchesElementCountAndTypes` trait represents a 1 -> 1
470  // type inference edge where a shaped type matches element count and types
471  // of variadic elements.
472  if (def.isSubClassOf("ShapedTypeMatchesElementCountAndTypes")) {
473  StringRef shapedArg = def.getValueAsString("shaped");
474  StringRef elementsArg = def.getValueAsString("elements");
475 
476  int shapedIndex = argumentsAndResultsIndex.lookup(shapedArg);
477  int elementsIndex = argumentsAndResultsIndex.lookup(elementsArg);
478 
479  // Handle result type inference from shaped type to variadic elements.
480  if (InferredResultType::isResultIndex(elementsIndex) &&
481  InferredResultType::isArgIndex(shapedIndex)) {
482  int resultIndex = InferredResultType::unmapResultIndex(elementsIndex);
483  ResultTypeInference &infer = inference[resultIndex];
484  if (!infer.inferred) {
485  infer.sources.emplace_back(
486  shapedIndex,
487  "::llvm::SmallVector<::mlir::Type>(::llvm::cast<::mlir::"
488  "ShapedType>($_self).getNumElements(), "
489  "::llvm::cast<::mlir::ShapedType>($_self).getElementType())");
490  infer.inferred = true;
491  }
492  }
493 
494  // Type inference in the opposite direction is not possible as the actual
495  // shaped type can't be inferred from the variadic elements.
496 
497  continue;
498  }
499 
500  if (!def.isSubClassOf("AllTypesMatch"))
501  continue;
502 
503  auto values = def.getValueAsListOfStrings("values");
504  // The `AllTypesMatch` trait represents an N <-> N fanin and fanout. That
505  // is, every result type has an edge from every other type. However, if any
506  // one of the values refers to an operand or a result with a fully-inferred
507  // type, we can infer all other types from that value. Try to find a
508  // fully-inferred type in the list.
509  std::optional<int> fullyInferredIndex;
510  SmallVector<int> resultIndices;
511  for (StringRef name : values) {
512  int index = argumentsAndResultsIndex.lookup(name);
514  resultIndices.push_back(InferredResultType::unmapResultIndex(index));
515  if (InferredResultType::isArgIndex(index) ||
516  inference[InferredResultType::unmapResultIndex(index)].inferred)
517  fullyInferredIndex = index;
518  }
519  if (fullyInferredIndex) {
520  // Make the fully-inferred type the only source for all results that
521  // aren't already inferred -- a 1 -> N fanout.
522  for (int resultIndex : resultIndices) {
523  ResultTypeInference &infer = inference[resultIndex];
524  if (!infer.inferred) {
525  infer.sources.assign(1, {*fullyInferredIndex, "$_self"});
526  infer.inferred = true;
527  }
528  }
529  } else {
530  // Add an edge between every result and every other type; N <-> N.
531  for (int resultIndex : resultIndices) {
532  for (int otherResultIndex : resultIndices) {
533  if (resultIndex == otherResultIndex)
534  continue;
535  inference[resultIndex].sources.emplace_back(
536  InferredResultType::unmapResultIndex(otherResultIndex), "$_self");
537  }
538  }
539  }
540  }
541 
542  // Propagate inferredness until a fixed point.
543  std::vector<ResultTypeInference *> worklist;
544  for (ResultTypeInference &infer : inference)
545  if (!infer.inferred)
546  worklist.push_back(&infer);
547  bool changed;
548  do {
549  changed = false;
550  for (auto cur = worklist.begin(); cur != worklist.end();) {
551  ResultTypeInference &infer = **cur;
552 
553  InferredResultType *iter =
554  llvm::find_if(infer.sources, [&](const InferredResultType &source) {
555  assert(InferredResultType::isResultIndex(source.getIndex()));
556  return inference[InferredResultType::unmapResultIndex(
557  source.getIndex())]
558  .inferred;
559  });
560  if (iter == infer.sources.end()) {
561  ++cur;
562  continue;
563  }
564 
565  changed = true;
566  infer.inferred = true;
567  // Make this the only source for the result. This breaks any cycles.
568  infer.sources.assign(1, *iter);
569  cur = worklist.erase(cur);
570  }
571  } while (changed);
572 
573  allResultsHaveKnownTypes = worklist.empty();
574 
575  // If the types could be computed, then add type inference trait.
576  if (allResultsHaveKnownTypes) {
577  traits.push_back(Trait::create(inferTrait->getDefInit()));
578  for (const ResultTypeInference &infer : inference)
579  resultTypeMapping.push_back(infer.sources.front());
580  }
581 }
582 
583 void Operator::populateOpStructure() {
584  auto &recordKeeper = def.getRecords();
585  auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint");
586  auto *attrClass = recordKeeper.getClass("Attr");
587  auto *propertyClass = recordKeeper.getClass("Property");
588  auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr");
589  auto *opVarClass = recordKeeper.getClass("OpVariable");
590  numNativeAttributes = 0;
591 
592  const DagInit *argumentValues = def.getValueAsDag("arguments");
593  unsigned numArgs = argumentValues->getNumArgs();
594 
595  // Mapping from name of to argument or result index. Arguments are indexed
596  // to match getArg index, while the results are negatively indexed.
597  llvm::StringMap<int> argumentsAndResultsIndex;
598 
599  // Handle operands and native attributes.
600  for (unsigned i = 0; i != numArgs; ++i) {
601  auto *arg = argumentValues->getArg(i);
602  auto givenName = argumentValues->getArgNameStr(i);
603  auto *argDefInit = dyn_cast<DefInit>(arg);
604  if (!argDefInit)
605  PrintFatalError(def.getLoc(),
606  Twine("undefined type for argument #") + Twine(i));
607  const Record *argDef = argDefInit->getDef();
608  if (argDef->isSubClassOf(opVarClass))
609  argDef = argDef->getValueAsDef("constraint");
610 
611  if (argDef->isSubClassOf(typeConstraintClass)) {
612  operands.push_back(
613  NamedTypeConstraint{givenName, TypeConstraint(argDef)});
614  } else if (argDef->isSubClassOf(attrClass)) {
615  if (givenName.empty())
616  PrintFatalError(argDef->getLoc(), "attributes must be named");
617  if (argDef->isSubClassOf(derivedAttrClass))
618  PrintFatalError(argDef->getLoc(),
619  "derived attributes not allowed in argument list");
620  attributes.push_back({givenName, Attribute(argDef)});
621  ++numNativeAttributes;
622  } else if (argDef->isSubClassOf(propertyClass)) {
623  if (givenName.empty())
624  PrintFatalError(argDef->getLoc(), "properties must be named");
625  properties.push_back({givenName, Property(argDef)});
626  } else {
627  PrintFatalError(def.getLoc(),
628  "unexpected def type; only defs deriving "
629  "from TypeConstraint or Attr or Property are allowed");
630  }
631  if (!givenName.empty())
632  argumentsAndResultsIndex[givenName] = i;
633  }
634 
635  // Handle derived attributes.
636  for (const auto &val : def.getValues()) {
637  if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) {
638  if (!record->isSubClassOf(attrClass))
639  continue;
640  if (!record->isSubClassOf(derivedAttrClass))
641  PrintFatalError(def.getLoc(),
642  "unexpected Attr where only DerivedAttr is allowed");
643 
644  if (record->getClasses().size() != 1) {
645  PrintFatalError(
646  def.getLoc(),
647  "unsupported attribute modelling, only single class expected");
648  }
649  attributes.push_back({cast<StringInit>(val.getNameInit())->getValue(),
650  Attribute(cast<DefInit>(val.getValue()))});
651  }
652  }
653 
654  // Populate `arguments`. This must happen after we've finalized `operands` and
655  // `attributes` because we will put their elements' pointers in `arguments`.
656  // SmallVector may perform re-allocation under the hood when adding new
657  // elements.
658  int operandIndex = 0, attrIndex = 0, propIndex = 0;
659  for (unsigned i = 0; i != numArgs; ++i) {
660  const Record *argDef =
661  dyn_cast<DefInit>(argumentValues->getArg(i))->getDef();
662  if (argDef->isSubClassOf(opVarClass))
663  argDef = argDef->getValueAsDef("constraint");
664 
665  if (argDef->isSubClassOf(typeConstraintClass)) {
666  attrOrOperandMapping.push_back(
667  {OperandOrAttribute::Kind::Operand, operandIndex});
668  arguments.emplace_back(&operands[operandIndex++]);
669  } else if (argDef->isSubClassOf(attrClass)) {
670  attrOrOperandMapping.push_back(
672  arguments.emplace_back(&attributes[attrIndex++]);
673  } else {
674  assert(argDef->isSubClassOf(propertyClass));
675  arguments.emplace_back(&properties[propIndex++]);
676  }
677  }
678 
679  auto *resultsDag = def.getValueAsDag("results");
680  auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator());
681  if (!outsOp || outsOp->getDef()->getName() != "outs") {
682  PrintFatalError(def.getLoc(), "'results' must have 'outs' directive");
683  }
684 
685  // Handle results.
686  for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) {
687  auto name = resultsDag->getArgNameStr(i);
688  auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i));
689  if (!resultInit) {
690  PrintFatalError(def.getLoc(),
691  Twine("undefined type for result #") + Twine(i));
692  }
693  auto *resultDef = resultInit->getDef();
694  if (resultDef->isSubClassOf(opVarClass))
695  resultDef = resultDef->getValueAsDef("constraint");
696  results.push_back({name, TypeConstraint(resultDef)});
697  if (!name.empty())
698  argumentsAndResultsIndex[name] = InferredResultType::mapResultIndex(i);
699 
700  // We currently only support VariadicOfVariadic operands.
701  if (results.back().constraint.isVariadicOfVariadic()) {
702  PrintFatalError(
703  def.getLoc(),
704  "'VariadicOfVariadic' results are currently not supported");
705  }
706  }
707 
708  // Handle successors
709  auto *successorsDag = def.getValueAsDag("successors");
710  auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator());
711  if (!successorsOp || successorsOp->getDef()->getName() != "successor") {
712  PrintFatalError(def.getLoc(),
713  "'successors' must have 'successor' directive");
714  }
715 
716  for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) {
717  auto name = successorsDag->getArgNameStr(i);
718  auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i));
719  if (!successorInit) {
720  PrintFatalError(def.getLoc(),
721  Twine("undefined kind for successor #") + Twine(i));
722  }
723  Successor successor(successorInit->getDef());
724 
725  // Only support variadic successors if it is the last one for now.
726  if (i != e - 1 && successor.isVariadic())
727  PrintFatalError(def.getLoc(), "only the last successor can be variadic");
728  successors.push_back({name, successor});
729  }
730 
731  // Create list of traits, skipping over duplicates: appending to lists in
732  // tablegen is easy, making them unique less so, so dedupe here.
733  if (auto *traitList = def.getValueAsListInit("traits")) {
734  // This is uniquing based on pointers of the trait.
736  traits.reserve(traitSet.size());
737 
738  // The declaration order of traits imply the verification order of traits.
739  // Some traits may require other traits to be verified first then they can
740  // do further verification based on those verified facts. If you see this
741  // error, fix the traits declaration order by checking the `dependentTraits`
742  // field.
743  auto verifyTraitValidity = [&](const Record *trait) {
744  auto *dependentTraits = trait->getValueAsListInit("dependentTraits");
745  for (auto *traitInit : *dependentTraits)
746  if (!traitSet.contains(traitInit))
747  PrintFatalError(
748  def.getLoc(),
749  trait->getValueAsString("trait") + " requires " +
750  cast<DefInit>(traitInit)->getDef()->getValueAsString(
751  "trait") +
752  " to precede it in traits list");
753  };
754 
755  std::function<void(const ListInit *)> insert;
756  insert = [&](const ListInit *traitList) {
757  for (auto *traitInit : *traitList) {
758  auto *def = cast<DefInit>(traitInit)->getDef();
759  if (def->isSubClassOf("TraitList")) {
760  insert(def->getValueAsListInit("traits"));
761  continue;
762  }
763 
764  // Ignore duplicates.
765  if (!traitSet.insert(traitInit).second)
766  continue;
767 
768  // If this is an interface with base classes, add the bases to the
769  // trait list.
770  if (def->isSubClassOf("Interface"))
771  insert(def->getValueAsListInit("baseInterfaces"));
772 
773  // Verify if the trait has all the dependent traits declared before
774  // itself.
775  verifyTraitValidity(def);
776  traits.push_back(Trait::create(traitInit));
777  }
778  };
779  insert(traitList);
780  }
781 
782  populateTypeInferenceInfo(argumentsAndResultsIndex);
783 
784  // Handle regions
785  auto *regionsDag = def.getValueAsDag("regions");
786  auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator());
787  if (!regionsOp || regionsOp->getDef()->getName() != "region") {
788  PrintFatalError(def.getLoc(), "'regions' must have 'region' directive");
789  }
790 
791  for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) {
792  auto name = regionsDag->getArgNameStr(i);
793  auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i));
794  if (!regionInit) {
795  PrintFatalError(def.getLoc(),
796  Twine("undefined kind for region #") + Twine(i));
797  }
798  Region region(regionInit->getDef());
799  if (region.isVariadic()) {
800  // Only support variadic regions if it is the last one for now.
801  if (i != e - 1)
802  PrintFatalError(def.getLoc(), "only the last region can be variadic");
803  if (name.empty())
804  PrintFatalError(def.getLoc(), "variadic regions must be named");
805  }
806 
807  regions.push_back({name, region});
808  }
809 
810  // Populate the builders.
811  auto *builderList = dyn_cast_or_null<ListInit>(def.getValueInit("builders"));
812  if (builderList && !builderList->empty()) {
813  for (const Init *init : builderList->getElements())
814  builders.emplace_back(cast<DefInit>(init)->getDef(), def.getLoc());
815  } else if (skipDefaultBuilders()) {
816  PrintFatalError(
817  def.getLoc(),
818  "default builders are skipped and no custom builders provided");
819  }
820 
821  LLVM_DEBUG(print(llvm::dbgs()));
822 }
823 
825  assert(allResultTypesKnown());
826  return resultTypeMapping[index];
827 }
828 
829 ArrayRef<SMLoc> Operator::getLoc() const { return def.getLoc(); }
830 
832  return !getDescription().trim().empty();
833 }
834 
835 StringRef Operator::getDescription() const {
836  return def.getValueAsString("description");
837 }
838 
839 bool Operator::hasSummary() const { return !getSummary().trim().empty(); }
840 
841 StringRef Operator::getSummary() const {
842  return def.getValueAsString("summary");
843 }
844 
846  auto *valueInit = def.getValueInit("assemblyFormat");
847  return isa<StringInit>(valueInit);
848 }
849 
850 StringRef Operator::getAssemblyFormat() const {
851  return TypeSwitch<const Init *, StringRef>(def.getValueInit("assemblyFormat"))
852  .Case<StringInit>([&](auto *init) { return init->getValue(); });
853 }
854 
855 void Operator::print(llvm::raw_ostream &os) const {
856  os << "op '" << getOperationName() << "'\n";
857  for (Argument arg : arguments) {
858  if (auto *attr = llvm::dyn_cast_if_present<NamedAttribute *>(arg))
859  os << "[attribute] " << attr->name << '\n';
860  else
861  os << "[operand] " << cast<NamedTypeConstraint *>(arg)->name << '\n';
862  }
863 }
864 
866  -> VariableDecorator {
867  return VariableDecorator(cast<DefInit>(init)->getDef());
868 }
869 
871  -> OperandOrAttribute {
872  return attrOrOperandMapping[index];
873 }
874 
875 std::string Operator::getGetterName(StringRef name) const {
876  return "get" + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true);
877 }
878 
879 std::string Operator::getSetterName(StringRef name) const {
880  return "set" + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true);
881 }
882 
883 std::string Operator::getRemoverName(StringRef name) const {
884  return "remove" + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true);
885 }
886 
887 bool Operator::hasFolder() const { return def.getValueAsBit("hasFolder"); }
888 
890  return def.getValueAsBit("useCustomPropertiesEncoding");
891 }
static void assertAccessorInvariants(const Operator &op, StringRef name)
Assert the invariants of accessors generated for the given name.
Definition: Operator.cpp:80
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
StringRef getName() const
This class represents an inferred result type.
Definition: Operator.h:44
static int mapResultIndex(int i)
Definition: Operator.h:59
static int unmapResultIndex(int i)
Definition: Operator.h:60
static bool isResultIndex(int i)
Definition: Operator.h:61
static bool isArgIndex(int i)
Definition: Operator.h:62
Wrapper class that contains a MLIR op's information (e.g., operands, attributes) defined in TableGen ...
Definition: Operator.h:77
std::string getQualCppClassName() const
Returns this op's C++ class name prefixed with namespaces.
Definition: Operator.cpp:156
unsigned getNumSuccessors() const
Returns the number of successors.
Definition: Operator.cpp:306
const NamedRegion & getRegion(unsigned index) const
Returns the index-th region.
Definition: Operator.cpp:286
TypeConstraint getResultTypeConstraint(int index) const
Returns the index-th result's type constraint.
Definition: Operator.cpp:201
ArrayRef< SMLoc > getLoc() const
Definition: Operator.cpp:829
Operator(const llvm::Record &def)
llvm::iterator_range< const_region_iterator > getRegions() const
Definition: Operator.cpp:279
OperandOrAttribute getArgToOperandOrAttribute(int index) const
Returns the OperandOrAttribute corresponding to the index.
Definition: Operator.cpp:870
NamedTypeConstraint & getOperand(int index)
Definition: Operator.h:216
StringRef getCppNamespace() const
Returns this op's C++ namespace.
Definition: Operator.cpp:162
const_attribute_iterator attribute_begin() const
Definition: Operator.cpp:327
std::string getGetterName(StringRef name) const
Returns the getter name for the accessor of name.
Definition: Operator.cpp:875
const_successor_iterator successor_end() const
Definition: Operator.cpp:298
int getNumOperands() const
Definition: Operator.h:215
StringRef getDescription() const
Definition: Operator.cpp:835
const_value_range getResults() const
Definition: Operator.cpp:197
arg_range getArgs() const
Definition: Operator.cpp:240
const_value_range getOperands() const
Definition: Operator.cpp:353
const_region_iterator region_begin() const
Definition: Operator.cpp:273
bool useCustomPropertiesEncoding() const
Whether to generate the readProperty/writeProperty methods for bytecode emission.
Definition: Operator.cpp:889
StringRef getResultName(int index) const
Returns the index-th result's name.
Definition: Operator.cpp:206
var_decorator_range getArgDecorators(int index) const
Definition: Operator.cpp:249
unsigned getNumVariableLengthOperands() const
Returns the number of variadic operands in this operation.
Definition: Operator.cpp:225
var_decorator_range getResultDecorators(int index) const
Returns the index-th result's decorators.
Definition: Operator.cpp:211
std::string getGenericAdaptorName() const
Returns the name of op's generic adaptor C++ class.
Definition: Operator.cpp:75
StringRef getExtraClassDefinition() const
Returns this op's extra class definition code.
Definition: Operator.cpp:176
NamedTypeConstraint & getResult(int index)
Returns the op result at the given index.
Definition: Operator.h:155
const_value_iterator result_begin() const
Op result iterators.
Definition: Operator.cpp:189
const_attribute_iterator attribute_end() const
Definition: Operator.cpp:330
const_trait_iterator trait_end() const
Definition: Operator.cpp:320
std::string getAdaptorName() const
Returns the name of op's adaptor C++ class.
Definition: Operator.cpp:71
int getNumResults() const
Returns the number of results this op produces.
Definition: Operator.cpp:164
llvm::iterator_range< const_attribute_iterator > getAttributes() const
Definition: Operator.cpp:333
bool hasFolder() const
Definition: Operator.cpp:887
const_value_iterator operand_end() const
Definition: Operator.cpp:350
arg_iterator arg_end() const
Definition: Operator.cpp:238
int getNumArgs() const
Returns the total number of arguments.
Definition: Operator.h:225
const_value_iterator operand_begin() const
Op operand iterators.
Definition: Operator.cpp:347
void assertInvariants() const
Check invariants (like no duplicated or conflicted names) and abort the process if any invariant is b...
Definition: Operator.cpp:114
StringRef getArgName(int index) const
Definition: Operator.cpp:244
StringRef getDialectName() const
Returns this op's dialect name.
Definition: Operator.cpp:152
const_region_iterator region_end() const
Definition: Operator.cpp:276
unsigned getNumVariableLengthResults() const
Returns the number of variable length results in this operation.
Definition: Operator.cpp:219
bool hasSingleVariadicArg() const
Returns true of the operation has a single variadic arg.
Definition: Operator.cpp:231
unsigned getNumVariadicSuccessors() const
Returns the number of variadic successors in this operation.
Definition: Operator.cpp:312
StringRef getSummary() const
Definition: Operator.cpp:841
bool isVariadic() const
Returns true if this op has variable length operands or results.
Definition: Operator.cpp:359
llvm::iterator_range< const_trait_iterator > getTraits() const
Definition: Operator.cpp:323
const Trait * getTrait(llvm::StringRef trait) const
Returns the trait wrapper for the given MLIR C++ trait.
Definition: Operator.cpp:257
llvm::iterator_range< const_successor_iterator > getSuccessors() const
Definition: Operator.cpp:301
bool hasSummary() const
Definition: Operator.cpp:839
const_successor_iterator successor_begin() const
Definition: Operator.cpp:295
void print(llvm::raw_ostream &os) const
Prints the contents in this operator to the given os.
Definition: Operator.cpp:855
unsigned getNumRegions() const
Returns the number of regions.
Definition: Operator.cpp:284
const_trait_iterator trait_begin() const
Definition: Operator.cpp:317
StringRef getExtraClassDeclaration() const
Returns this op's extra class declaration code.
Definition: Operator.cpp:169
StringRef getAssemblyFormat() const
Definition: Operator.cpp:850
std::string getSetterName(StringRef name) const
Returns the setter name for the accessor of name.
Definition: Operator.cpp:879
std::string getOperationName() const
Returns the operation name.
Definition: Operator.cpp:63
const NamedSuccessor & getSuccessor(unsigned index) const
Returns the index-th successor.
Definition: Operator.cpp:308
StringRef getCppClassName() const
Returns this op's C++ class name.
Definition: Operator.cpp:154
bool allResultTypesKnown() const
Return whether all the result types are known.
Definition: Operator.h:320
bool hasAssemblyFormat() const
Query functions for the assembly format of the operator.
Definition: Operator.cpp:845
unsigned getNumVariadicRegions() const
Returns the number of variadic regions in this operation.
Definition: Operator.cpp:290
bool skipDefaultBuilders() const
Returns true if default builders should not be generated.
Definition: Operator.cpp:185
arg_iterator arg_begin() const
Op argument (attribute or operand) iterators.
Definition: Operator.cpp:236
const InferredResultType & getInferredResultType(int index) const
Return all arguments or type constraints with same type as result[index].
Definition: Operator.cpp:824
const llvm::Record & getDef() const
Returns the Tablegen definition this operator was constructed from.
Definition: Operator.cpp:183
const_value_iterator result_end() const
Definition: Operator.cpp:193
std::string getRemoverName(StringRef name) const
Returns the remove name for the accessor of name.
Definition: Operator.cpp:883
Argument getArg(int index) const
Op argument (attribute or operand) accessors.
Definition: Operator.cpp:357
bool hasDescription() const
Query functions for the documentation of the operator.
Definition: Operator.cpp:831
static Trait create(const llvm::Init *init)
Definition: Trait.cpp:26
bool isVariableLength() const
Definition: Type.h:53
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
const char * inferTypeOpInterface
Definition: Attribute.cpp:148
Include the generated interface declarations.
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
bool isVariadic() const
Definition: Region.h:33
Pair consisting kind of argument and index into operands or attributes.
Definition: Operator.h:327
static VariableDecorator unwrap(const llvm::Init *init)
Definition: Operator.cpp:865
A class used to represent the decorators of an operator variable, i.e.
Definition: Operator.h:110