12a463c36SJacques Pienaar //===- Operator.cpp - Operator class --------------------------------------===//
22a463c36SJacques Pienaar //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62a463c36SJacques Pienaar //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
82a463c36SJacques Pienaar //
9f8bbe5deSLei Zhang // Operator wrapper to simplify using TableGen Record defining a MLIR Op.
102a463c36SJacques Pienaar //
112a463c36SJacques Pienaar //===----------------------------------------------------------------------===//
122a463c36SJacques Pienaar 
132a463c36SJacques Pienaar #include "mlir/TableGen/Operator.h"
148f249438SJacques Pienaar #include "mlir/TableGen/Predicate.h"
1594662ee0SRiver Riddle #include "mlir/TableGen/Trait.h"
16b2cc2c34SLei Zhang #include "mlir/TableGen/Type.h"
1731f40f60SJacques Pienaar #include "llvm/ADT/EquivalenceClasses.h"
1831f40f60SJacques Pienaar #include "llvm/ADT/STLExtras.h"
1931f40f60SJacques Pienaar #include "llvm/ADT/Sequence.h"
20b6d54a1bSJacques Pienaar #include "llvm/ADT/SmallPtrSet.h"
217d1ed69cSFederico Lebrón #include "llvm/ADT/StringExtras.h"
22ebf190fcSRiver Riddle #include "llvm/ADT/TypeSwitch.h"
23b12a7c88SMehdi Amini #include "llvm/Support/Debug.h"
246a994233SJacques Pienaar #include "llvm/Support/ErrorHandling.h"
252a463c36SJacques Pienaar #include "llvm/Support/FormatVariadic.h"
262a463c36SJacques Pienaar #include "llvm/TableGen/Error.h"
272a463c36SJacques Pienaar #include "llvm/TableGen/Record.h"
282a463c36SJacques Pienaar 
29796ca609SLei Zhang #define DEBUG_TYPE "mlir-tblgen-operator"
30796ca609SLei Zhang 
312a463c36SJacques Pienaar using namespace mlir;
3212d16de5SRahul Joshi using namespace mlir::tblgen;
333e5ee82bSLei Zhang 
342a463c36SJacques Pienaar using llvm::DagInit;
352a463c36SJacques Pienaar using llvm::DefInit;
362a463c36SJacques Pienaar using llvm::Record;
372a463c36SJacques Pienaar 
Operator(const llvm::Record & def)3812d16de5SRahul Joshi Operator::Operator(const llvm::Record &def)
3920e0cedfSLei Zhang     : dialect(def.getValueAsDef("opDialect")), def(def) {
4020e0cedfSLei Zhang   // The first `_` in the op's TableGen def name is treated as separating the
4120e0cedfSLei Zhang   // dialect prefix and the op class name. The dialect prefix will be ignored if
4220e0cedfSLei Zhang   // not empty. Otherwise, if def name starts with a `_`, the `_` is considered
4320e0cedfSLei Zhang   // as part of the class name.
4420e0cedfSLei Zhang   StringRef prefix;
4520e0cedfSLei Zhang   std::tie(prefix, cppClassName) = def.getName().split('_');
4620e0cedfSLei Zhang   if (prefix.empty()) {
4720e0cedfSLei Zhang     // Class name with a leading underscore and without dialect prefix
488bb83517SLei Zhang     cppClassName = def.getName();
498bb83517SLei Zhang   } else if (cppClassName.empty()) {
5020e0cedfSLei Zhang     // Class name without dialect prefix
5120e0cedfSLei Zhang     cppClassName = prefix;
522a463c36SJacques Pienaar   }
532a463c36SJacques Pienaar 
5449755871SSean Silva   cppNamespace = def.getValueAsString("cppNamespace");
5549755871SSean Silva 
568bb83517SLei Zhang   populateOpStructure();
577fb2394aSMehdi Amini   assertInvariants();
582a463c36SJacques Pienaar }
592a463c36SJacques Pienaar 
getOperationName() const6012d16de5SRahul Joshi std::string Operator::getOperationName() const {
6120e0cedfSLei Zhang   auto prefix = dialect.getName();
6220e0cedfSLei Zhang   auto opName = def.getValueAsString("opName");
630ea6154bSJacques Pienaar   if (prefix.empty())
64adcd0268SBenjamin Kramer     return std::string(opName);
65adcd0268SBenjamin Kramer   return std::string(llvm::formatv("{0}.{1}", prefix, opName));
662a463c36SJacques Pienaar }
672a463c36SJacques Pienaar 
getAdaptorName() const6812d16de5SRahul Joshi std::string Operator::getAdaptorName() const {
692d2c73c5SJacques Pienaar   return std::string(llvm::formatv("{0}Adaptor", getCppClassName()));
70fefe4366SJacques Pienaar }
71fefe4366SJacques Pienaar 
assertInvariants() const727fb2394aSMehdi Amini void Operator::assertInvariants() const {
737fb2394aSMehdi Amini   // Check that the name of arguments/results/regions/successors don't overlap.
747fb2394aSMehdi Amini   DenseMap<StringRef, StringRef> existingNames;
757fb2394aSMehdi Amini   auto checkName = [&](StringRef name, StringRef entity) {
767fb2394aSMehdi Amini     if (name.empty())
777fb2394aSMehdi Amini       return;
787fb2394aSMehdi Amini     auto insertion = existingNames.insert({name, entity});
797fb2394aSMehdi Amini     if (insertion.second)
807fb2394aSMehdi Amini       return;
817fb2394aSMehdi Amini     if (entity == insertion.first->second)
827fb2394aSMehdi Amini       PrintFatalError(getLoc(), "op has a conflict with two " + entity +
837fb2394aSMehdi Amini                                     " having the same name '" + name + "'");
847fb2394aSMehdi Amini     PrintFatalError(getLoc(), "op has a conflict with " +
857fb2394aSMehdi Amini                                   insertion.first->second + " and " + entity +
867fb2394aSMehdi Amini                                   " both having an entry with the name '" +
877fb2394aSMehdi Amini                                   name + "'");
887fb2394aSMehdi Amini   };
897fb2394aSMehdi Amini   // Check operands amongst themselves.
907fb2394aSMehdi Amini   for (int i : llvm::seq<int>(0, getNumOperands()))
917fb2394aSMehdi Amini     checkName(getOperand(i).name, "operands");
927fb2394aSMehdi Amini 
937fb2394aSMehdi Amini   // Check results amongst themselves and against operands.
947fb2394aSMehdi Amini   for (int i : llvm::seq<int>(0, getNumResults()))
957fb2394aSMehdi Amini     checkName(getResult(i).name, "results");
967fb2394aSMehdi Amini 
977fb2394aSMehdi Amini   // Check regions amongst themselves and against operands and results.
987fb2394aSMehdi Amini   for (int i : llvm::seq<int>(0, getNumRegions()))
997fb2394aSMehdi Amini     checkName(getRegion(i).name, "regions");
1007fb2394aSMehdi Amini 
1017fb2394aSMehdi Amini   // Check successors amongst themselves and against operands, results, and
1027fb2394aSMehdi Amini   // regions.
1037fb2394aSMehdi Amini   for (int i : llvm::seq<int>(0, getNumSuccessors()))
1047fb2394aSMehdi Amini     checkName(getSuccessor(i).name, "successors");
1057fb2394aSMehdi Amini }
1067fb2394aSMehdi Amini 
getDialectName() const10712d16de5SRahul Joshi StringRef Operator::getDialectName() const { return dialect.getName(); }
10820e0cedfSLei Zhang 
getCppClassName() const10912d16de5SRahul Joshi StringRef Operator::getCppClassName() const { return cppClassName; }
1108bb83517SLei Zhang 
getQualCppClassName() const11112d16de5SRahul Joshi std::string Operator::getQualCppClassName() const {
11249755871SSean Silva   if (cppNamespace.empty())
113adcd0268SBenjamin Kramer     return std::string(cppClassName);
11449755871SSean Silva   return std::string(llvm::formatv("{0}::{1}", cppNamespace, cppClassName));
115c396c044SJacques Pienaar }
1162a463c36SJacques Pienaar 
getCppNamespace() const11749755871SSean Silva StringRef Operator::getCppNamespace() const { return cppNamespace; }
11849755871SSean Silva 
getNumResults() const11912d16de5SRahul Joshi int Operator::getNumResults() const {
120c224a518SLei Zhang   DagInit *results = def.getValueAsDag("results");
121c224a518SLei Zhang   return results->getNumArgs();
122c224a518SLei Zhang }
123c224a518SLei Zhang 
getExtraClassDeclaration() const12412d16de5SRahul Joshi StringRef Operator::getExtraClassDeclaration() const {
125041e9618SJacques Pienaar   constexpr auto attr = "extraClassDeclaration";
126041e9618SJacques Pienaar   if (def.isValueUnset(attr))
127041e9618SJacques Pienaar     return {};
128041e9618SJacques Pienaar   return def.getValueAsString(attr);
129041e9618SJacques Pienaar }
130041e9618SJacques Pienaar 
getExtraClassDefinition() const131b0774e5fSMogball StringRef Operator::getExtraClassDefinition() const {
132b0774e5fSMogball   constexpr auto attr = "extraClassDefinition";
133b0774e5fSMogball   if (def.isValueUnset(attr))
134b0774e5fSMogball     return {};
135b0774e5fSMogball   return def.getValueAsString(attr);
136b0774e5fSMogball }
137b0774e5fSMogball 
getDef() const13812d16de5SRahul Joshi const llvm::Record &Operator::getDef() const { return def; }
139252de8ecSAlex Zinenko 
skipDefaultBuilders() const14012d16de5SRahul Joshi bool Operator::skipDefaultBuilders() const {
141ead1acaeSAlex Zinenko   return def.getValueAsBit("skipDefaultBuilders");
142ead1acaeSAlex Zinenko }
143ead1acaeSAlex Zinenko 
result_begin() const14478fdbdbfSMehdi Amini auto Operator::result_begin() const -> const_value_iterator {
14578fdbdbfSMehdi Amini   return results.begin();
14678fdbdbfSMehdi Amini }
1473f517af9SLei Zhang 
result_end() const14878fdbdbfSMehdi Amini auto Operator::result_end() const -> const_value_iterator {
14978fdbdbfSMehdi Amini   return results.end();
15078fdbdbfSMehdi Amini }
1513f517af9SLei Zhang 
getResults() const15278fdbdbfSMehdi Amini auto Operator::getResults() const -> const_value_range {
1533f517af9SLei Zhang   return {result_begin(), result_end()};
1543f517af9SLei Zhang }
1553f517af9SLei Zhang 
getResultTypeConstraint(int index) const15612d16de5SRahul Joshi TypeConstraint Operator::getResultTypeConstraint(int index) const {
1571725b485SJacques Pienaar   DagInit *results = def.getValueAsDag("results");
1588f5fa566SLei Zhang   return TypeConstraint(cast<DefInit>(results->getArg(index)));
159c224a518SLei Zhang }
160c224a518SLei Zhang 
getResultName(int index) const16112d16de5SRahul Joshi StringRef Operator::getResultName(int index) const {
1621725b485SJacques Pienaar   DagInit *results = def.getValueAsDag("results");
1631725b485SJacques Pienaar   return results->getArgNameStr(index);
164e0fc5038SLei Zhang }
165e0fc5038SLei Zhang 
getResultDecorators(int index) const16612d16de5SRahul Joshi auto Operator::getResultDecorators(int index) const -> var_decorator_range {
16720dca522SRiver Riddle   Record *result =
16820dca522SRiver Riddle       cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef();
16920dca522SRiver Riddle   if (!result->isSubClassOf("OpVariable"))
17020dca522SRiver Riddle     return var_decorator_range(nullptr, nullptr);
17120dca522SRiver Riddle   return *result->getValueAsListInit("decorators");
17220dca522SRiver Riddle }
17320dca522SRiver Riddle 
getNumVariableLengthResults() const17412d16de5SRahul Joshi unsigned Operator::getNumVariableLengthResults() const {
175aba1acc8SRiver Riddle   return llvm::count_if(results, [](const NamedTypeConstraint &c) {
176aba1acc8SRiver Riddle     return c.constraint.isVariableLength();
177aba1acc8SRiver Riddle   });
178c224a518SLei Zhang }
179c224a518SLei Zhang 
getNumVariableLengthOperands() const18012d16de5SRahul Joshi unsigned Operator::getNumVariableLengthOperands() const {
181aba1acc8SRiver Riddle   return llvm::count_if(operands, [](const NamedTypeConstraint &c) {
182aba1acc8SRiver Riddle     return c.constraint.isVariableLength();
183aba1acc8SRiver Riddle   });
1841df6ca50SLei Zhang }
1851df6ca50SLei Zhang 
hasSingleVariadicArg() const18612d16de5SRahul Joshi bool Operator::hasSingleVariadicArg() const {
18712d16de5SRahul Joshi   return getNumArgs() == 1 && getArg(0).is<NamedTypeConstraint *>() &&
18813d05787SRahul Joshi          getOperand(0).isVariadic();
18913d05787SRahul Joshi }
19013d05787SRahul Joshi 
arg_begin() const19112d16de5SRahul Joshi Operator::arg_iterator Operator::arg_begin() const { return arguments.begin(); }
192020f9eb6SLei Zhang 
arg_end() const19312d16de5SRahul Joshi Operator::arg_iterator Operator::arg_end() const { return arguments.end(); }
194020f9eb6SLei Zhang 
getArgs() const19512d16de5SRahul Joshi Operator::arg_range Operator::getArgs() const {
196020f9eb6SLei Zhang   return {arg_begin(), arg_end()};
197020f9eb6SLei Zhang }
198020f9eb6SLei Zhang 
getArgName(int index) const19912d16de5SRahul Joshi StringRef Operator::getArgName(int index) const {
2002a463c36SJacques Pienaar   DagInit *argumentValues = def.getValueAsDag("arguments");
201c5a6712fSAlex Zinenko   return argumentValues->getArgNameStr(index);
2022a463c36SJacques Pienaar }
2032a463c36SJacques Pienaar 
getArgDecorators(int index) const20412d16de5SRahul Joshi auto Operator::getArgDecorators(int index) const -> var_decorator_range {
20520dca522SRiver Riddle   Record *arg =
20620dca522SRiver Riddle       cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef();
20720dca522SRiver Riddle   if (!arg->isSubClassOf("OpVariable"))
20820dca522SRiver Riddle     return var_decorator_range(nullptr, nullptr);
20920dca522SRiver Riddle   return *arg->getValueAsListInit("decorators");
21020dca522SRiver Riddle }
21120dca522SRiver Riddle 
getTrait(StringRef trait) const21294662ee0SRiver Riddle const Trait *Operator::getTrait(StringRef trait) const {
21313c6e419SLei Zhang   for (const auto &t : traits) {
21494662ee0SRiver Riddle     if (const auto *traitDef = dyn_cast<NativeTrait>(&t)) {
21594662ee0SRiver Riddle       if (traitDef->getFullyQualifiedTraitName() == trait)
21694662ee0SRiver Riddle         return traitDef;
21794662ee0SRiver Riddle     } else if (const auto *traitDef = dyn_cast<InternalTrait>(&t)) {
21894662ee0SRiver Riddle       if (traitDef->getFullyQualifiedTraitName() == trait)
21994662ee0SRiver Riddle         return traitDef;
22094662ee0SRiver Riddle     } else if (const auto *traitDef = dyn_cast<InterfaceTrait>(&t)) {
22194662ee0SRiver Riddle       if (traitDef->getFullyQualifiedTraitName() == trait)
22294662ee0SRiver Riddle         return traitDef;
223c489f50eSFeng Liu     }
2241725b485SJacques Pienaar   }
22513c6e419SLei Zhang   return nullptr;
226eb3f8dcbSLei Zhang }
227eb3f8dcbSLei Zhang 
region_begin() const22812d16de5SRahul Joshi auto Operator::region_begin() const -> const_region_iterator {
2290359b86dSRiver Riddle   return regions.begin();
2300359b86dSRiver Riddle }
region_end() const23112d16de5SRahul Joshi auto Operator::region_end() const -> const_region_iterator {
2320359b86dSRiver Riddle   return regions.end();
2330359b86dSRiver Riddle }
getRegions() const23412d16de5SRahul Joshi auto Operator::getRegions() const
2350359b86dSRiver Riddle     -> llvm::iterator_range<const_region_iterator> {
2360359b86dSRiver Riddle   return {region_begin(), region_end()};
2370359b86dSRiver Riddle }
2380359b86dSRiver Riddle 
getNumRegions() const23912d16de5SRahul Joshi unsigned Operator::getNumRegions() const { return regions.size(); }
2403650df50SLei Zhang 
getRegion(unsigned index) const24112d16de5SRahul Joshi const NamedRegion &Operator::getRegion(unsigned index) const {
2423650df50SLei Zhang   return regions[index];
2433650df50SLei Zhang }
244d4c8c8deSLei Zhang 
getNumVariadicRegions() const24512d16de5SRahul Joshi unsigned Operator::getNumVariadicRegions() const {
2460359b86dSRiver Riddle   return llvm::count_if(regions,
2470359b86dSRiver Riddle                         [](const NamedRegion &c) { return c.isVariadic(); });
2480359b86dSRiver Riddle }
2490359b86dSRiver Riddle 
successor_begin() const25012d16de5SRahul Joshi auto Operator::successor_begin() const -> const_successor_iterator {
251b1de971bSRiver Riddle   return successors.begin();
252b1de971bSRiver Riddle }
successor_end() const25312d16de5SRahul Joshi auto Operator::successor_end() const -> const_successor_iterator {
254b1de971bSRiver Riddle   return successors.end();
255b1de971bSRiver Riddle }
getSuccessors() const25612d16de5SRahul Joshi auto Operator::getSuccessors() const
257b1de971bSRiver Riddle     -> llvm::iterator_range<const_successor_iterator> {
258b1de971bSRiver Riddle   return {successor_begin(), successor_end()};
259b1de971bSRiver Riddle }
260b1de971bSRiver Riddle 
getNumSuccessors() const26112d16de5SRahul Joshi unsigned Operator::getNumSuccessors() const { return successors.size(); }
262b1de971bSRiver Riddle 
getSuccessor(unsigned index) const26312d16de5SRahul Joshi const NamedSuccessor &Operator::getSuccessor(unsigned index) const {
264b1de971bSRiver Riddle   return successors[index];
265b1de971bSRiver Riddle }
266b1de971bSRiver Riddle 
getNumVariadicSuccessors() const26712d16de5SRahul Joshi unsigned Operator::getNumVariadicSuccessors() const {
268b1de971bSRiver Riddle   return llvm::count_if(successors,
269b1de971bSRiver Riddle                         [](const NamedSuccessor &c) { return c.isVariadic(); });
270b1de971bSRiver Riddle }
271b1de971bSRiver Riddle 
trait_begin() const27212d16de5SRahul Joshi auto Operator::trait_begin() const -> const_trait_iterator {
2731725b485SJacques Pienaar   return traits.begin();
2741725b485SJacques Pienaar }
trait_end() const27512d16de5SRahul Joshi auto Operator::trait_end() const -> const_trait_iterator {
2761725b485SJacques Pienaar   return traits.end();
2771725b485SJacques Pienaar }
getTraits() const27812d16de5SRahul Joshi auto Operator::getTraits() const -> llvm::iterator_range<const_trait_iterator> {
2791725b485SJacques Pienaar   return {trait_begin(), trait_end()};
2801725b485SJacques Pienaar }
2811725b485SJacques Pienaar 
attribute_begin() const28212d16de5SRahul Joshi auto Operator::attribute_begin() const -> attribute_iterator {
2832a463c36SJacques Pienaar   return attributes.begin();
2842a463c36SJacques Pienaar }
attribute_end() const28512d16de5SRahul Joshi auto Operator::attribute_end() const -> attribute_iterator {
2862a463c36SJacques Pienaar   return attributes.end();
2872a463c36SJacques Pienaar }
getAttributes() const28812d16de5SRahul Joshi auto Operator::getAttributes() const
2893e5ee82bSLei Zhang     -> llvm::iterator_range<attribute_iterator> {
2902a463c36SJacques Pienaar   return {attribute_begin(), attribute_end()};
2912a463c36SJacques Pienaar }
2922a463c36SJacques Pienaar 
operand_begin() const29378fdbdbfSMehdi Amini auto Operator::operand_begin() const -> const_value_iterator {
29478fdbdbfSMehdi Amini   return operands.begin();
29578fdbdbfSMehdi Amini }
operand_end() const29678fdbdbfSMehdi Amini auto Operator::operand_end() const -> const_value_iterator {
29778fdbdbfSMehdi Amini   return operands.end();
29878fdbdbfSMehdi Amini }
getOperands() const29978fdbdbfSMehdi Amini auto Operator::getOperands() const -> const_value_range {
3002a463c36SJacques Pienaar   return {operand_begin(), operand_end()};
3012a463c36SJacques Pienaar }
3022a463c36SJacques Pienaar 
getArg(int index) const30312d16de5SRahul Joshi auto Operator::getArg(int index) const -> Argument { return arguments[index]; }
3042a463c36SJacques Pienaar 
30531f40f60SJacques Pienaar // Mapping from result index to combined argument and result index. Arguments
30631f40f60SJacques Pienaar // are indexed to match getArg index, while the result indexes are mapped to
30731f40f60SJacques Pienaar // avoid overlap.
resultIndex(int i)30831f40f60SJacques Pienaar static int resultIndex(int i) { return -1 - i; }
30931f40f60SJacques Pienaar 
isVariadic() const31012d16de5SRahul Joshi bool Operator::isVariadic() const {
31131f40f60SJacques Pienaar   return any_of(llvm::concat<const NamedTypeConstraint>(operands, results),
31231f40f60SJacques Pienaar                 [](const NamedTypeConstraint &op) { return op.isVariadic(); });
31331f40f60SJacques Pienaar }
31431f40f60SJacques Pienaar 
populateTypeInferenceInfo(const llvm::StringMap<int> & argumentsAndResultsIndex)31512d16de5SRahul Joshi void Operator::populateTypeInferenceInfo(
31631f40f60SJacques Pienaar     const llvm::StringMap<int> &argumentsAndResultsIndex) {
31731f40f60SJacques Pienaar   // If the type inference op interface is not registered, then do not attempt
31831f40f60SJacques Pienaar   // to determine if the result types an be inferred.
31931f40f60SJacques Pienaar   auto &recordKeeper = def.getRecords();
32031f40f60SJacques Pienaar   auto *inferTrait = recordKeeper.getDef(inferTypeOpInterface);
32131f40f60SJacques Pienaar   allResultsHaveKnownTypes = false;
32231f40f60SJacques Pienaar   if (!inferTrait)
32331f40f60SJacques Pienaar     return;
32431f40f60SJacques Pienaar 
32531f40f60SJacques Pienaar   // If there are no results, the skip this else the build method generated
32631f40f60SJacques Pienaar   // overlaps with another autogenerated builder.
32731f40f60SJacques Pienaar   if (getNumResults() == 0)
32831f40f60SJacques Pienaar     return;
32931f40f60SJacques Pienaar 
3303ce2ee28SBenjamin Kramer   // Skip ops with variadic or optional results.
3313ce2ee28SBenjamin Kramer   if (getNumVariableLengthResults() > 0)
33231f40f60SJacques Pienaar     return;
33331f40f60SJacques Pienaar 
33431f40f60SJacques Pienaar   // Skip cases currently being custom generated.
33531f40f60SJacques Pienaar   // TODO: Remove special cases.
33692a836daSRiver Riddle   if (getTrait("::mlir::OpTrait::SameOperandsAndResultType")) {
33792a836daSRiver Riddle     // Check for a non-variable length operand to use as the type anchor.
33892a836daSRiver Riddle     auto *operandI = llvm::find_if(arguments, [](const Argument &arg) {
33992a836daSRiver Riddle       NamedTypeConstraint *operand = arg.dyn_cast<NamedTypeConstraint *>();
34092a836daSRiver Riddle       return operand && !operand->isVariableLength();
34192a836daSRiver Riddle     });
34292a836daSRiver Riddle     if (operandI == arguments.end())
34331f40f60SJacques Pienaar       return;
34431f40f60SJacques Pienaar 
34592a836daSRiver Riddle     // Map each of the result types to the anchor operation.
34692a836daSRiver Riddle     int operandIdx = operandI - arguments.begin();
34792a836daSRiver Riddle     resultTypeMapping.resize(getNumResults());
34892a836daSRiver Riddle     for (int i = 0; i < getNumResults(); ++i)
34992a836daSRiver Riddle       resultTypeMapping[i].emplace_back(operandIdx);
35092a836daSRiver Riddle 
35192a836daSRiver Riddle     allResultsHaveKnownTypes = true;
35292a836daSRiver Riddle     traits.push_back(Trait::create(inferTrait->getDefInit()));
35392a836daSRiver Riddle     return;
35492a836daSRiver Riddle   }
35592a836daSRiver Riddle 
35631f40f60SJacques Pienaar   // We create equivalence classes of argument/result types where arguments
35731f40f60SJacques Pienaar   // and results are mapped into the same index space and indices corresponding
35831f40f60SJacques Pienaar   // to the same type are in the same equivalence class.
35931f40f60SJacques Pienaar   llvm::EquivalenceClasses<int> ecs;
36031f40f60SJacques Pienaar   resultTypeMapping.resize(getNumResults());
36131f40f60SJacques Pienaar   // Captures the argument whose type matches a given result type. Preference
36231f40f60SJacques Pienaar   // towards capturing operands first before attributes.
36331f40f60SJacques Pienaar   auto captureMapping = [&](int i) {
36431f40f60SJacques Pienaar     bool found = false;
36531f40f60SJacques Pienaar     ecs.insert(resultIndex(i));
36631f40f60SJacques Pienaar     auto mi = ecs.findLeader(resultIndex(i));
36731f40f60SJacques Pienaar     for (auto me = ecs.member_end(); mi != me; ++mi) {
36831f40f60SJacques Pienaar       if (*mi < 0) {
36931f40f60SJacques Pienaar         auto tc = getResultTypeConstraint(i);
370*037f0995SKazu Hirata         if (tc.getBuilderCall()) {
37131f40f60SJacques Pienaar           resultTypeMapping[i].emplace_back(tc);
37231f40f60SJacques Pienaar           found = true;
37331f40f60SJacques Pienaar         }
37431f40f60SJacques Pienaar         continue;
37531f40f60SJacques Pienaar       }
37631f40f60SJacques Pienaar 
37731f40f60SJacques Pienaar       resultTypeMapping[i].emplace_back(*mi);
37831f40f60SJacques Pienaar       found = true;
37931f40f60SJacques Pienaar     }
38031f40f60SJacques Pienaar     return found;
38131f40f60SJacques Pienaar   };
38231f40f60SJacques Pienaar 
38394662ee0SRiver Riddle   for (const Trait &trait : traits) {
38431f40f60SJacques Pienaar     const llvm::Record &def = trait.getDef();
38531f40f60SJacques Pienaar     // If the infer type op interface was manually added, then treat it as
38631f40f60SJacques Pienaar     // intention that the op needs special handling.
38731f40f60SJacques Pienaar     // TODO: Reconsider whether to always generate, this is more conservative
38831f40f60SJacques Pienaar     // and keeps existing behavior so starting that way for now.
38931f40f60SJacques Pienaar     if (def.isSubClassOf(
39031f40f60SJacques Pienaar             llvm::formatv("{0}::Trait", inferTypeOpInterface).str()))
39131f40f60SJacques Pienaar       return;
39294662ee0SRiver Riddle     if (const auto *traitDef = dyn_cast<InterfaceTrait>(&trait))
39394662ee0SRiver Riddle       if (&traitDef->getDef() == inferTrait)
39431f40f60SJacques Pienaar         return;
39531f40f60SJacques Pienaar 
39631f40f60SJacques Pienaar     if (!def.isSubClassOf("AllTypesMatch"))
39731f40f60SJacques Pienaar       continue;
39831f40f60SJacques Pienaar 
39931f40f60SJacques Pienaar     auto values = def.getValueAsListOfStrings("values");
40031f40f60SJacques Pienaar     auto root = argumentsAndResultsIndex.lookup(values.front());
40131f40f60SJacques Pienaar     for (StringRef str : values)
40231f40f60SJacques Pienaar       ecs.unionSets(argumentsAndResultsIndex.lookup(str), root);
40331f40f60SJacques Pienaar   }
40431f40f60SJacques Pienaar 
40531f40f60SJacques Pienaar   // Verifies that all output types have a corresponding known input type
40631f40f60SJacques Pienaar   // and chooses matching operand or attribute (in that order) that
40731f40f60SJacques Pienaar   // matches it.
40831f40f60SJacques Pienaar   allResultsHaveKnownTypes =
40931f40f60SJacques Pienaar       all_of(llvm::seq<int>(0, getNumResults()), captureMapping);
41031f40f60SJacques Pienaar 
41131f40f60SJacques Pienaar   // If the types could be computed, then add type inference trait.
41231f40f60SJacques Pienaar   if (allResultsHaveKnownTypes)
41394662ee0SRiver Riddle     traits.push_back(Trait::create(inferTrait->getDefInit()));
41431f40f60SJacques Pienaar }
41531f40f60SJacques Pienaar 
populateOpStructure()41612d16de5SRahul Joshi void Operator::populateOpStructure() {
4172a463c36SJacques Pienaar   auto &recordKeeper = def.getRecords();
41831f40f60SJacques Pienaar   auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint");
41931f40f60SJacques Pienaar   auto *attrClass = recordKeeper.getClass("Attr");
42031f40f60SJacques Pienaar   auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr");
42131f40f60SJacques Pienaar   auto *opVarClass = recordKeeper.getClass("OpVariable");
42295949a0dSAlex Zinenko   numNativeAttributes = 0;
4232a463c36SJacques Pienaar 
4242a463c36SJacques Pienaar   DagInit *argumentValues = def.getValueAsDag("arguments");
425796ca609SLei Zhang   unsigned numArgs = argumentValues->getNumArgs();
426796ca609SLei Zhang 
42731f40f60SJacques Pienaar   // Mapping from name of to argument or result index. Arguments are indexed
42831f40f60SJacques Pienaar   // to match getArg index, while the results are negatively indexed.
42931f40f60SJacques Pienaar   llvm::StringMap<int> argumentsAndResultsIndex;
43031f40f60SJacques Pienaar 
43195949a0dSAlex Zinenko   // Handle operands and native attributes.
432796ca609SLei Zhang   for (unsigned i = 0; i != numArgs; ++i) {
43331f40f60SJacques Pienaar     auto *arg = argumentValues->getArg(i);
43466647a31SLei Zhang     auto givenName = argumentValues->getArgNameStr(i);
43531f40f60SJacques Pienaar     auto *argDefInit = dyn_cast<DefInit>(arg);
4362a463c36SJacques Pienaar     if (!argDefInit)
4372a463c36SJacques Pienaar       PrintFatalError(def.getLoc(),
438e0fc5038SLei Zhang                       Twine("undefined type for argument #") + Twine(i));
4392a463c36SJacques Pienaar     Record *argDef = argDefInit->getDef();
44020dca522SRiver Riddle     if (argDef->isSubClassOf(opVarClass))
44120dca522SRiver Riddle       argDef = argDef->getValueAsDef("constraint");
44295949a0dSAlex Zinenko 
44395949a0dSAlex Zinenko     if (argDef->isSubClassOf(typeConstraintClass)) {
444509cd739SJacques Pienaar       operands.push_back(
44520dca522SRiver Riddle           NamedTypeConstraint{givenName, TypeConstraint(argDef)});
44695949a0dSAlex Zinenko     } else if (argDef->isSubClassOf(attrClass)) {
44766647a31SLei Zhang       if (givenName.empty())
4482a463c36SJacques Pienaar         PrintFatalError(argDef->getLoc(), "attributes must be named");
44995949a0dSAlex Zinenko       if (argDef->isSubClassOf(derivedAttrClass))
45095949a0dSAlex Zinenko         PrintFatalError(argDef->getLoc(),
451dde5bf23SJacques Pienaar                         "derived attributes not allowed in argument list");
4529b034f0bSLei Zhang       attributes.push_back({givenName, Attribute(argDef)});
45395949a0dSAlex Zinenko       ++numNativeAttributes;
45495949a0dSAlex Zinenko     } else {
45595949a0dSAlex Zinenko       PrintFatalError(def.getLoc(), "unexpected def type; only defs deriving "
45695949a0dSAlex Zinenko                                     "from TypeConstraint or Attr are allowed");
45795949a0dSAlex Zinenko     }
45831f40f60SJacques Pienaar     if (!givenName.empty())
45931f40f60SJacques Pienaar       argumentsAndResultsIndex[givenName] = i;
460dde5bf23SJacques Pienaar   }
461dde5bf23SJacques Pienaar 
462f8bbe5deSLei Zhang   // Handle derived attributes.
463dde5bf23SJacques Pienaar   for (const auto &val : def.getValues()) {
464dde5bf23SJacques Pienaar     if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) {
465dde5bf23SJacques Pienaar       if (!record->isSubClassOf(attrClass))
466dde5bf23SJacques Pienaar         continue;
467dde5bf23SJacques Pienaar       if (!record->isSubClassOf(derivedAttrClass))
468dde5bf23SJacques Pienaar         PrintFatalError(def.getLoc(),
469dde5bf23SJacques Pienaar                         "unexpected Attr where only DerivedAttr is allowed");
470dde5bf23SJacques Pienaar 
471dde5bf23SJacques Pienaar       if (record->getClasses().size() != 1) {
4722a463c36SJacques Pienaar         PrintFatalError(
4732a463c36SJacques Pienaar             def.getLoc(),
474dde5bf23SJacques Pienaar             "unsupported attribute modelling, only single class expected");
4752a463c36SJacques Pienaar       }
47666647a31SLei Zhang       attributes.push_back(
47766647a31SLei Zhang           {cast<llvm::StringInit>(val.getNameInit())->getValue(),
4789b034f0bSLei Zhang            Attribute(cast<DefInit>(val.getValue()))});
479dde5bf23SJacques Pienaar     }
4802a463c36SJacques Pienaar   }
4811df6ca50SLei Zhang 
482796ca609SLei Zhang   // Populate `arguments`. This must happen after we've finalized `operands` and
483796ca609SLei Zhang   // `attributes` because we will put their elements' pointers in `arguments`.
484796ca609SLei Zhang   // SmallVector may perform re-allocation under the hood when adding new
485796ca609SLei Zhang   // elements.
486796ca609SLei Zhang   int operandIndex = 0, attrIndex = 0;
487796ca609SLei Zhang   for (unsigned i = 0; i != numArgs; ++i) {
488796ca609SLei Zhang     Record *argDef = dyn_cast<DefInit>(argumentValues->getArg(i))->getDef();
48920dca522SRiver Riddle     if (argDef->isSubClassOf(opVarClass))
49020dca522SRiver Riddle       argDef = argDef->getValueAsDef("constraint");
491796ca609SLei Zhang 
492796ca609SLei Zhang     if (argDef->isSubClassOf(typeConstraintClass)) {
49371b9d89dSJacques Pienaar       attrOrOperandMapping.push_back(
49471b9d89dSJacques Pienaar           {OperandOrAttribute::Kind::Operand, operandIndex});
495796ca609SLei Zhang       arguments.emplace_back(&operands[operandIndex++]);
496796ca609SLei Zhang     } else {
497796ca609SLei Zhang       assert(argDef->isSubClassOf(attrClass));
49871b9d89dSJacques Pienaar       attrOrOperandMapping.push_back(
49971b9d89dSJacques Pienaar           {OperandOrAttribute::Kind::Attribute, attrIndex});
500796ca609SLei Zhang       arguments.emplace_back(&attributes[attrIndex++]);
501796ca609SLei Zhang     }
502796ca609SLei Zhang   }
503796ca609SLei Zhang 
504e0fc5038SLei Zhang   auto *resultsDag = def.getValueAsDag("results");
505e0fc5038SLei Zhang   auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator());
506e0fc5038SLei Zhang   if (!outsOp || outsOp->getDef()->getName() != "outs") {
507e0fc5038SLei Zhang     PrintFatalError(def.getLoc(), "'results' must have 'outs' directive");
508e0fc5038SLei Zhang   }
509e0fc5038SLei Zhang 
510e0fc5038SLei Zhang   // Handle results.
511e0fc5038SLei Zhang   for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) {
512e0fc5038SLei Zhang     auto name = resultsDag->getArgNameStr(i);
51320dca522SRiver Riddle     auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i));
51420dca522SRiver Riddle     if (!resultInit) {
515e0fc5038SLei Zhang       PrintFatalError(def.getLoc(),
516e0fc5038SLei Zhang                       Twine("undefined type for result #") + Twine(i));
517e0fc5038SLei Zhang     }
51820dca522SRiver Riddle     auto *resultDef = resultInit->getDef();
51920dca522SRiver Riddle     if (resultDef->isSubClassOf(opVarClass))
52020dca522SRiver Riddle       resultDef = resultDef->getValueAsDef("constraint");
5218f5fa566SLei Zhang     results.push_back({name, TypeConstraint(resultDef)});
52231f40f60SJacques Pienaar     if (!name.empty())
52331f40f60SJacques Pienaar       argumentsAndResultsIndex[name] = resultIndex(i);
5244e103a12SRiver Riddle 
5254e103a12SRiver Riddle     // We currently only support VariadicOfVariadic operands.
5264e103a12SRiver Riddle     if (results.back().constraint.isVariadicOfVariadic()) {
5274e103a12SRiver Riddle       PrintFatalError(
5284e103a12SRiver Riddle           def.getLoc(),
5294e103a12SRiver Riddle           "'VariadicOfVariadic' results are currently not supported");
5304e103a12SRiver Riddle     }
531e0fc5038SLei Zhang   }
532e0fc5038SLei Zhang 
533b1de971bSRiver Riddle   // Handle successors
534b1de971bSRiver Riddle   auto *successorsDag = def.getValueAsDag("successors");
535b1de971bSRiver Riddle   auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator());
536b1de971bSRiver Riddle   if (!successorsOp || successorsOp->getDef()->getName() != "successor") {
537b1de971bSRiver Riddle     PrintFatalError(def.getLoc(),
538b1de971bSRiver Riddle                     "'successors' must have 'successor' directive");
539b1de971bSRiver Riddle   }
540b1de971bSRiver Riddle 
541b1de971bSRiver Riddle   for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) {
542b1de971bSRiver Riddle     auto name = successorsDag->getArgNameStr(i);
543b1de971bSRiver Riddle     auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i));
544b1de971bSRiver Riddle     if (!successorInit) {
545b1de971bSRiver Riddle       PrintFatalError(def.getLoc(),
546b1de971bSRiver Riddle                       Twine("undefined kind for successor #") + Twine(i));
547b1de971bSRiver Riddle     }
548b1de971bSRiver Riddle     Successor successor(successorInit->getDef());
549b1de971bSRiver Riddle 
550b1de971bSRiver Riddle     // Only support variadic successors if it is the last one for now.
551b1de971bSRiver Riddle     if (i != e - 1 && successor.isVariadic())
552b1de971bSRiver Riddle       PrintFatalError(def.getLoc(), "only the last successor can be variadic");
553b1de971bSRiver Riddle     successors.push_back({name, successor});
554b1de971bSRiver Riddle   }
555b1de971bSRiver Riddle 
556b6d54a1bSJacques Pienaar   // Create list of traits, skipping over duplicates: appending to lists in
557b6d54a1bSJacques Pienaar   // tablegen is easy, making them unique less so, so dedupe here.
55831f40f60SJacques Pienaar   if (auto *traitList = def.getValueAsListInit("traits")) {
559b6d54a1bSJacques Pienaar     // This is uniquing based on pointers of the trait.
560b6d54a1bSJacques Pienaar     SmallPtrSet<const llvm::Init *, 32> traitSet;
561b6d54a1bSJacques Pienaar     traits.reserve(traitSet.size());
5624b897de5SJacques Pienaar 
56391e8a63cSChia-hung Duan     // The declaration order of traits imply the verification order of traits.
56491e8a63cSChia-hung Duan     // Some traits may require other traits to be verified first then they can
56591e8a63cSChia-hung Duan     // do further verification based on those verified facts. If you see this
56691e8a63cSChia-hung Duan     // error, fix the traits declaration order by checking the `dependentTraits`
56791e8a63cSChia-hung Duan     // field.
56891e8a63cSChia-hung Duan     auto verifyTraitValidity = [&](Record *trait) {
56991e8a63cSChia-hung Duan       auto *dependentTraits = trait->getValueAsListInit("dependentTraits");
57091e8a63cSChia-hung Duan       for (auto *traitInit : *dependentTraits)
57191e8a63cSChia-hung Duan         if (traitSet.find(traitInit) == traitSet.end())
57291e8a63cSChia-hung Duan           PrintFatalError(
57391e8a63cSChia-hung Duan               def.getLoc(),
57491e8a63cSChia-hung Duan               trait->getValueAsString("trait") + " requires " +
57591e8a63cSChia-hung Duan                   cast<DefInit>(traitInit)->getDef()->getValueAsString(
57691e8a63cSChia-hung Duan                       "trait") +
57791e8a63cSChia-hung Duan                   " to precede it in traits list");
57891e8a63cSChia-hung Duan     };
57991e8a63cSChia-hung Duan 
5804b897de5SJacques Pienaar     std::function<void(llvm::ListInit *)> insert;
5814b897de5SJacques Pienaar     insert = [&](llvm::ListInit *traitList) {
58231f40f60SJacques Pienaar       for (auto *traitInit : *traitList) {
5834b897de5SJacques Pienaar         auto *def = cast<DefInit>(traitInit)->getDef();
584697a5036SSanjoy Das         if (def->isSubClassOf("TraitList")) {
5854b897de5SJacques Pienaar           insert(def->getValueAsListInit("traits"));
5864b897de5SJacques Pienaar           continue;
5874b897de5SJacques Pienaar         }
58891e8a63cSChia-hung Duan 
58991e8a63cSChia-hung Duan         // Verify if the trait has all the dependent traits declared before
59091e8a63cSChia-hung Duan         // itself.
59191e8a63cSChia-hung Duan         verifyTraitValidity(def);
59291e8a63cSChia-hung Duan 
593b6d54a1bSJacques Pienaar         // Keep traits in the same order while skipping over duplicates.
594b6d54a1bSJacques Pienaar         if (traitSet.insert(traitInit).second)
59594662ee0SRiver Riddle           traits.push_back(Trait::create(traitInit));
596b6d54a1bSJacques Pienaar       }
5974b897de5SJacques Pienaar     };
5984b897de5SJacques Pienaar     insert(traitList);
599b6d54a1bSJacques Pienaar   }
600d4c8c8deSLei Zhang 
60131f40f60SJacques Pienaar   populateTypeInferenceInfo(argumentsAndResultsIndex);
60231f40f60SJacques Pienaar 
603d4c8c8deSLei Zhang   // Handle regions
6043650df50SLei Zhang   auto *regionsDag = def.getValueAsDag("regions");
6053650df50SLei Zhang   auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator());
6063650df50SLei Zhang   if (!regionsOp || regionsOp->getDef()->getName() != "region") {
6073650df50SLei Zhang     PrintFatalError(def.getLoc(), "'regions' must have 'region' directive");
6083650df50SLei Zhang   }
6093650df50SLei Zhang 
6103650df50SLei Zhang   for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) {
6113650df50SLei Zhang     auto name = regionsDag->getArgNameStr(i);
6123650df50SLei Zhang     auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i));
6133650df50SLei Zhang     if (!regionInit) {
6143650df50SLei Zhang       PrintFatalError(def.getLoc(),
6153650df50SLei Zhang                       Twine("undefined kind for region #") + Twine(i));
6163650df50SLei Zhang     }
6170359b86dSRiver Riddle     Region region(regionInit->getDef());
6180359b86dSRiver Riddle     if (region.isVariadic()) {
6190359b86dSRiver Riddle       // Only support variadic regions if it is the last one for now.
6200359b86dSRiver Riddle       if (i != e - 1)
6210359b86dSRiver Riddle         PrintFatalError(def.getLoc(), "only the last region can be variadic");
6220359b86dSRiver Riddle       if (name.empty())
6230359b86dSRiver Riddle         PrintFatalError(def.getLoc(), "variadic regions must be named");
6240359b86dSRiver Riddle     }
6250359b86dSRiver Riddle 
6260359b86dSRiver Riddle     regions.push_back({name, region});
6273650df50SLei Zhang   }
628796ca609SLei Zhang 
62920741773SRiver Riddle   // Populate the builders.
63020741773SRiver Riddle   auto *builderList =
63120741773SRiver Riddle       dyn_cast_or_null<llvm::ListInit>(def.getValueInit("builders"));
63220741773SRiver Riddle   if (builderList && !builderList->empty()) {
63320741773SRiver Riddle     for (llvm::Init *init : builderList->getValues())
63420741773SRiver Riddle       builders.emplace_back(cast<llvm::DefInit>(init)->getDef(), def.getLoc());
63520741773SRiver Riddle   } else if (skipDefaultBuilders()) {
63620741773SRiver Riddle     PrintFatalError(
63720741773SRiver Riddle         def.getLoc(),
63820741773SRiver Riddle         "default builders are skipped and no custom builders provided");
63920741773SRiver Riddle   }
64020741773SRiver Riddle 
641796ca609SLei Zhang   LLVM_DEBUG(print(llvm::dbgs()));
6422a463c36SJacques Pienaar }
6438f249438SJacques Pienaar 
getSameTypeAsResult(int index) const64412d16de5SRahul Joshi auto Operator::getSameTypeAsResult(int index) const -> ArrayRef<ArgOrType> {
64531f40f60SJacques Pienaar   assert(allResultTypesKnown());
64631f40f60SJacques Pienaar   return resultTypeMapping[index];
64731f40f60SJacques Pienaar }
64831f40f60SJacques Pienaar 
getLoc() const6496842ec42SRiver Riddle ArrayRef<SMLoc> Operator::getLoc() const { return def.getLoc(); }
6502927297aSSmit Hinsu 
hasDescription() const65112d16de5SRahul Joshi bool Operator::hasDescription() const {
652a280e399SJacques Pienaar   return def.getValue("description") != nullptr;
653a280e399SJacques Pienaar }
654a280e399SJacques Pienaar 
getDescription() const65512d16de5SRahul Joshi StringRef Operator::getDescription() const {
656a280e399SJacques Pienaar   return def.getValueAsString("description");
657a280e399SJacques Pienaar }
658a280e399SJacques Pienaar 
hasSummary() const65912d16de5SRahul Joshi bool Operator::hasSummary() const { return def.getValue("summary") != nullptr; }
660a280e399SJacques Pienaar 
getSummary() const66112d16de5SRahul Joshi StringRef Operator::getSummary() const {
662a280e399SJacques Pienaar   return def.getValueAsString("summary");
663a280e399SJacques Pienaar }
664796ca609SLei Zhang 
hasAssemblyFormat() const66512d16de5SRahul Joshi bool Operator::hasAssemblyFormat() const {
6661a083f02SRiver Riddle   auto *valueInit = def.getValueInit("assemblyFormat");
667415fab6fSPaul C. Anagnostopoulos   return isa<llvm::StringInit>(valueInit);
6681a083f02SRiver Riddle }
6691a083f02SRiver Riddle 
getAssemblyFormat() const67012d16de5SRahul Joshi StringRef Operator::getAssemblyFormat() const {
6711a083f02SRiver Riddle   return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat"))
6724e103a12SRiver Riddle       .Case<llvm::StringInit>([&](auto *init) { return init->getValue(); });
6731a083f02SRiver Riddle }
6741a083f02SRiver Riddle 
print(llvm::raw_ostream & os) const67512d16de5SRahul Joshi void Operator::print(llvm::raw_ostream &os) const {
676796ca609SLei Zhang   os << "op '" << getOperationName() << "'\n";
677796ca609SLei Zhang   for (Argument arg : arguments) {
678796ca609SLei Zhang     if (auto *attr = arg.dyn_cast<NamedAttribute *>())
679796ca609SLei Zhang       os << "[attribute] " << attr->name << '\n';
680796ca609SLei Zhang     else
681796ca609SLei Zhang       os << "[operand] " << arg.get<NamedTypeConstraint *>()->name << '\n';
682796ca609SLei Zhang   }
683796ca609SLei Zhang }
68420dca522SRiver Riddle 
unwrap(llvm::Init * init)68512d16de5SRahul Joshi auto Operator::VariableDecoratorIterator::unwrap(llvm::Init *init)
68620dca522SRiver Riddle     -> VariableDecorator {
68720dca522SRiver Riddle   return VariableDecorator(cast<llvm::DefInit>(init)->getDef());
68820dca522SRiver Riddle }
68971b9d89dSJacques Pienaar 
getArgToOperandOrAttribute(int index) const69012d16de5SRahul Joshi auto Operator::getArgToOperandOrAttribute(int index) const
69171b9d89dSJacques Pienaar     -> OperandOrAttribute {
69271b9d89dSJacques Pienaar   return attrOrOperandMapping[index];
69371b9d89dSJacques Pienaar }
6946a994233SJacques Pienaar 
6956a994233SJacques Pienaar // Helper to return the names for accessor.
6966a994233SJacques Pienaar static SmallVector<std::string, 2>
getGetterOrSetterNames(bool isGetter,const Operator & op,StringRef name)6976a994233SJacques Pienaar getGetterOrSetterNames(bool isGetter, const Operator &op, StringRef name) {
6986a994233SJacques Pienaar   Dialect::EmitPrefix prefixType = op.getDialect().getEmitAccessorPrefix();
6996a994233SJacques Pienaar   std::string prefix;
7006a994233SJacques Pienaar   if (prefixType != Dialect::EmitPrefix::Raw)
7016a994233SJacques Pienaar     prefix = isGetter ? "get" : "set";
7026a994233SJacques Pienaar 
7036a994233SJacques Pienaar   SmallVector<std::string, 2> names;
7046a994233SJacques Pienaar   bool rawToo = prefixType == Dialect::EmitPrefix::Both;
7056a994233SJacques Pienaar 
706cfb72fd3SJacques Pienaar   // Whether to skip generating prefixed form for argument. This just does some
707cfb72fd3SJacques Pienaar   // basic checks.
708cfb72fd3SJacques Pienaar   //
709cfb72fd3SJacques Pienaar   // There are a little bit more invasive checks possible for cases where not
710cfb72fd3SJacques Pienaar   // all ops have the trait that would cause overlap. For many cases here,
711cfb72fd3SJacques Pienaar   // renaming would be better (e.g., we can only guard in limited manner against
712cfb72fd3SJacques Pienaar   // methods from traits and interfaces here, so avoiding these in op definition
713cfb72fd3SJacques Pienaar   // is safer).
7146a994233SJacques Pienaar   auto skip = [&](StringRef newName) {
715cfb72fd3SJacques Pienaar     bool shouldSkip = newName == "getAttributeNames" ||
716b077ee92SJacques Pienaar                       newName == "getAttributes" || newName == "getOperation";
717cfb72fd3SJacques Pienaar     if (newName == "getOperands") {
718cfb72fd3SJacques Pienaar       // To reduce noise, skip generating the prefixed form and the warning if
719cfb72fd3SJacques Pienaar       // $operands correspond to single variadic argument.
720cfb72fd3SJacques Pienaar       if (op.getNumOperands() == 1 && op.getNumVariableLengthOperands() == 1)
721cfb72fd3SJacques Pienaar         return true;
722cfb72fd3SJacques Pienaar       shouldSkip = true;
723cfb72fd3SJacques Pienaar     }
7240ef217d8SJacques Pienaar     if (newName == "getRegions") {
7250ef217d8SJacques Pienaar       if (op.getNumRegions() == 1 && op.getNumVariadicRegions() == 1)
7260ef217d8SJacques Pienaar         return true;
7270ef217d8SJacques Pienaar       shouldSkip = true;
7280ef217d8SJacques Pienaar     }
729b077ee92SJacques Pienaar     if (newName == "getType") {
730b077ee92SJacques Pienaar       if (op.getNumResults() == 0)
731b077ee92SJacques Pienaar         return false;
732b077ee92SJacques Pienaar       shouldSkip = true;
733b077ee92SJacques Pienaar     }
7346a994233SJacques Pienaar     if (!shouldSkip)
7356a994233SJacques Pienaar       return false;
7366a994233SJacques Pienaar 
7376a994233SJacques Pienaar     // This note could be avoided where the final function generated would
7386a994233SJacques Pienaar     // have been identical. But preferably in the op definition avoiding using
7396a994233SJacques Pienaar     // the generic name and then getting a more specialize type is better.
7406a994233SJacques Pienaar     PrintNote(op.getLoc(),
7416a994233SJacques Pienaar               "Skipping generation of prefixed accessor `" + newName +
7426a994233SJacques Pienaar                   "` as it overlaps with default one; generating raw form (`" +
7436a994233SJacques Pienaar                   name + "`) still");
7446a994233SJacques Pienaar     return true;
7456a994233SJacques Pienaar   };
7466a994233SJacques Pienaar 
7476a994233SJacques Pienaar   if (!prefix.empty()) {
7486a994233SJacques Pienaar     names.push_back(
7496a994233SJacques Pienaar         prefix + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true));
7506a994233SJacques Pienaar     // Skip cases which would overlap with default ones for now.
7516a994233SJacques Pienaar     if (skip(names.back())) {
7526a994233SJacques Pienaar       rawToo = true;
7536a994233SJacques Pienaar       names.clear();
754cfb72fd3SJacques Pienaar     } else if (rawToo) {
7556a994233SJacques Pienaar       LLVM_DEBUG(llvm::errs() << "WITH_GETTER(\"" << op.getQualCppClassName()
756cfb72fd3SJacques Pienaar                               << "::" << name << "\")\n"
7576a994233SJacques Pienaar                               << "WITH_GETTER(\"" << op.getQualCppClassName()
758cfb72fd3SJacques Pienaar                               << "Adaptor::" << name << "\")\n";);
7596a994233SJacques Pienaar     }
7606a994233SJacques Pienaar   }
7616a994233SJacques Pienaar 
7626a994233SJacques Pienaar   if (prefix.empty() || rawToo)
7636a994233SJacques Pienaar     names.push_back(name.str());
7646a994233SJacques Pienaar   return names;
7656a994233SJacques Pienaar }
7666a994233SJacques Pienaar 
getGetterNames(StringRef name) const7676a994233SJacques Pienaar SmallVector<std::string, 2> Operator::getGetterNames(StringRef name) const {
7686a994233SJacques Pienaar   return getGetterOrSetterNames(/*isGetter=*/true, *this, name);
7696a994233SJacques Pienaar }
7706a994233SJacques Pienaar 
getSetterNames(StringRef name) const7716a994233SJacques Pienaar SmallVector<std::string, 2> Operator::getSetterNames(StringRef name) const {
7726a994233SJacques Pienaar   return getGetterOrSetterNames(/*isGetter=*/false, *this, name);
7736a994233SJacques Pienaar }
774