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