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" 141725b485SJacques Pienaar #include "mlir/TableGen/OpTrait.h" 158f249438SJacques Pienaar #include "mlir/TableGen/Predicate.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" 21ebf190fcSRiver Riddle #include "llvm/ADT/TypeSwitch.h" 22b12a7c88SMehdi Amini #include "llvm/Support/Debug.h" 232a463c36SJacques Pienaar #include "llvm/Support/FormatVariadic.h" 242a463c36SJacques Pienaar #include "llvm/TableGen/Error.h" 252a463c36SJacques Pienaar #include "llvm/TableGen/Record.h" 262a463c36SJacques Pienaar 27796ca609SLei Zhang #define DEBUG_TYPE "mlir-tblgen-operator" 28796ca609SLei Zhang 292a463c36SJacques Pienaar using namespace mlir; 30*12d16de5SRahul Joshi using namespace mlir::tblgen; 313e5ee82bSLei Zhang 322a463c36SJacques Pienaar using llvm::DagInit; 332a463c36SJacques Pienaar using llvm::DefInit; 342a463c36SJacques Pienaar using llvm::Record; 352a463c36SJacques Pienaar 36*12d16de5SRahul Joshi Operator::Operator(const llvm::Record &def) 3720e0cedfSLei Zhang : dialect(def.getValueAsDef("opDialect")), def(def) { 3820e0cedfSLei Zhang // The first `_` in the op's TableGen def name is treated as separating the 3920e0cedfSLei Zhang // dialect prefix and the op class name. The dialect prefix will be ignored if 4020e0cedfSLei Zhang // not empty. Otherwise, if def name starts with a `_`, the `_` is considered 4120e0cedfSLei Zhang // as part of the class name. 4220e0cedfSLei Zhang StringRef prefix; 4320e0cedfSLei Zhang std::tie(prefix, cppClassName) = def.getName().split('_'); 4420e0cedfSLei Zhang if (prefix.empty()) { 4520e0cedfSLei Zhang // Class name with a leading underscore and without dialect prefix 468bb83517SLei Zhang cppClassName = def.getName(); 478bb83517SLei Zhang } else if (cppClassName.empty()) { 4820e0cedfSLei Zhang // Class name without dialect prefix 4920e0cedfSLei Zhang cppClassName = prefix; 502a463c36SJacques Pienaar } 512a463c36SJacques Pienaar 528bb83517SLei Zhang populateOpStructure(); 532a463c36SJacques Pienaar } 542a463c36SJacques Pienaar 55*12d16de5SRahul Joshi std::string Operator::getOperationName() const { 5620e0cedfSLei Zhang auto prefix = dialect.getName(); 5720e0cedfSLei Zhang auto opName = def.getValueAsString("opName"); 580ea6154bSJacques Pienaar if (prefix.empty()) 59adcd0268SBenjamin Kramer return std::string(opName); 60adcd0268SBenjamin Kramer return std::string(llvm::formatv("{0}.{1}", prefix, opName)); 612a463c36SJacques Pienaar } 622a463c36SJacques Pienaar 63*12d16de5SRahul Joshi std::string Operator::getAdaptorName() const { 642d2c73c5SJacques Pienaar return std::string(llvm::formatv("{0}Adaptor", getCppClassName())); 65fefe4366SJacques Pienaar } 66fefe4366SJacques Pienaar 67*12d16de5SRahul Joshi StringRef Operator::getDialectName() const { return dialect.getName(); } 6820e0cedfSLei Zhang 69*12d16de5SRahul Joshi StringRef Operator::getCppClassName() const { return cppClassName; } 708bb83517SLei Zhang 71*12d16de5SRahul Joshi std::string Operator::getQualCppClassName() const { 7220e0cedfSLei Zhang auto prefix = dialect.getCppNamespace(); 7320e0cedfSLei Zhang if (prefix.empty()) 74adcd0268SBenjamin Kramer return std::string(cppClassName); 75adcd0268SBenjamin Kramer return std::string(llvm::formatv("{0}::{1}", prefix, cppClassName)); 76c396c044SJacques Pienaar } 772a463c36SJacques Pienaar 78*12d16de5SRahul Joshi int Operator::getNumResults() const { 79c224a518SLei Zhang DagInit *results = def.getValueAsDag("results"); 80c224a518SLei Zhang return results->getNumArgs(); 81c224a518SLei Zhang } 82c224a518SLei Zhang 83*12d16de5SRahul Joshi StringRef Operator::getExtraClassDeclaration() const { 84041e9618SJacques Pienaar constexpr auto attr = "extraClassDeclaration"; 85041e9618SJacques Pienaar if (def.isValueUnset(attr)) 86041e9618SJacques Pienaar return {}; 87041e9618SJacques Pienaar return def.getValueAsString(attr); 88041e9618SJacques Pienaar } 89041e9618SJacques Pienaar 90*12d16de5SRahul Joshi const llvm::Record &Operator::getDef() const { return def; } 91252de8ecSAlex Zinenko 92*12d16de5SRahul Joshi bool Operator::skipDefaultBuilders() const { 93ead1acaeSAlex Zinenko return def.getValueAsBit("skipDefaultBuilders"); 94ead1acaeSAlex Zinenko } 95ead1acaeSAlex Zinenko 96*12d16de5SRahul Joshi auto Operator::result_begin() -> value_iterator { return results.begin(); } 973f517af9SLei Zhang 98*12d16de5SRahul Joshi auto Operator::result_end() -> value_iterator { return results.end(); } 993f517af9SLei Zhang 100*12d16de5SRahul Joshi auto Operator::getResults() -> value_range { 1013f517af9SLei Zhang return {result_begin(), result_end()}; 1023f517af9SLei Zhang } 1033f517af9SLei Zhang 104*12d16de5SRahul Joshi TypeConstraint Operator::getResultTypeConstraint(int index) const { 1051725b485SJacques Pienaar DagInit *results = def.getValueAsDag("results"); 1068f5fa566SLei Zhang return TypeConstraint(cast<DefInit>(results->getArg(index))); 107c224a518SLei Zhang } 108c224a518SLei Zhang 109*12d16de5SRahul Joshi StringRef Operator::getResultName(int index) const { 1101725b485SJacques Pienaar DagInit *results = def.getValueAsDag("results"); 1111725b485SJacques Pienaar return results->getArgNameStr(index); 112e0fc5038SLei Zhang } 113e0fc5038SLei Zhang 114*12d16de5SRahul Joshi auto Operator::getResultDecorators(int index) const -> var_decorator_range { 11520dca522SRiver Riddle Record *result = 11620dca522SRiver Riddle cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef(); 11720dca522SRiver Riddle if (!result->isSubClassOf("OpVariable")) 11820dca522SRiver Riddle return var_decorator_range(nullptr, nullptr); 11920dca522SRiver Riddle return *result->getValueAsListInit("decorators"); 12020dca522SRiver Riddle } 12120dca522SRiver Riddle 122*12d16de5SRahul Joshi unsigned Operator::getNumVariableLengthResults() const { 123aba1acc8SRiver Riddle return llvm::count_if(results, [](const NamedTypeConstraint &c) { 124aba1acc8SRiver Riddle return c.constraint.isVariableLength(); 125aba1acc8SRiver Riddle }); 126c224a518SLei Zhang } 127c224a518SLei Zhang 128*12d16de5SRahul Joshi unsigned Operator::getNumVariableLengthOperands() const { 129aba1acc8SRiver Riddle return llvm::count_if(operands, [](const NamedTypeConstraint &c) { 130aba1acc8SRiver Riddle return c.constraint.isVariableLength(); 131aba1acc8SRiver Riddle }); 1321df6ca50SLei Zhang } 1331df6ca50SLei Zhang 134*12d16de5SRahul Joshi bool Operator::hasSingleVariadicArg() const { 135*12d16de5SRahul Joshi return getNumArgs() == 1 && getArg(0).is<NamedTypeConstraint *>() && 13613d05787SRahul Joshi getOperand(0).isVariadic(); 13713d05787SRahul Joshi } 13813d05787SRahul Joshi 139*12d16de5SRahul Joshi Operator::arg_iterator Operator::arg_begin() const { return arguments.begin(); } 140020f9eb6SLei Zhang 141*12d16de5SRahul Joshi Operator::arg_iterator Operator::arg_end() const { return arguments.end(); } 142020f9eb6SLei Zhang 143*12d16de5SRahul Joshi Operator::arg_range Operator::getArgs() const { 144020f9eb6SLei Zhang return {arg_begin(), arg_end()}; 145020f9eb6SLei Zhang } 146020f9eb6SLei Zhang 147*12d16de5SRahul Joshi StringRef Operator::getArgName(int index) const { 1482a463c36SJacques Pienaar DagInit *argumentValues = def.getValueAsDag("arguments"); 1492a463c36SJacques Pienaar return argumentValues->getArgName(index)->getValue(); 1502a463c36SJacques Pienaar } 1512a463c36SJacques Pienaar 152*12d16de5SRahul Joshi auto Operator::getArgDecorators(int index) const -> var_decorator_range { 15320dca522SRiver Riddle Record *arg = 15420dca522SRiver Riddle cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef(); 15520dca522SRiver Riddle if (!arg->isSubClassOf("OpVariable")) 15620dca522SRiver Riddle return var_decorator_range(nullptr, nullptr); 15720dca522SRiver Riddle return *arg->getValueAsListInit("decorators"); 15820dca522SRiver Riddle } 15920dca522SRiver Riddle 160*12d16de5SRahul Joshi const OpTrait *Operator::getTrait(StringRef trait) const { 16113c6e419SLei Zhang for (const auto &t : traits) { 162*12d16de5SRahul Joshi if (const auto *opTrait = dyn_cast<NativeOpTrait>(&t)) { 1631725b485SJacques Pienaar if (opTrait->getTrait() == trait) 16413c6e419SLei Zhang return opTrait; 165*12d16de5SRahul Joshi } else if (const auto *opTrait = dyn_cast<InternalOpTrait>(&t)) { 166c489f50eSFeng Liu if (opTrait->getTrait() == trait) 16713c6e419SLei Zhang return opTrait; 168*12d16de5SRahul Joshi } else if (const auto *opTrait = dyn_cast<InterfaceOpTrait>(&t)) { 169c3537800SRiver Riddle if (opTrait->getTrait() == trait) 17013c6e419SLei Zhang return opTrait; 171c489f50eSFeng Liu } 1721725b485SJacques Pienaar } 17313c6e419SLei Zhang return nullptr; 174eb3f8dcbSLei Zhang } 175eb3f8dcbSLei Zhang 176*12d16de5SRahul Joshi auto Operator::region_begin() const -> const_region_iterator { 1770359b86dSRiver Riddle return regions.begin(); 1780359b86dSRiver Riddle } 179*12d16de5SRahul Joshi auto Operator::region_end() const -> const_region_iterator { 1800359b86dSRiver Riddle return regions.end(); 1810359b86dSRiver Riddle } 182*12d16de5SRahul Joshi auto Operator::getRegions() const 1830359b86dSRiver Riddle -> llvm::iterator_range<const_region_iterator> { 1840359b86dSRiver Riddle return {region_begin(), region_end()}; 1850359b86dSRiver Riddle } 1860359b86dSRiver Riddle 187*12d16de5SRahul Joshi unsigned Operator::getNumRegions() const { return regions.size(); } 1883650df50SLei Zhang 189*12d16de5SRahul Joshi const NamedRegion &Operator::getRegion(unsigned index) const { 1903650df50SLei Zhang return regions[index]; 1913650df50SLei Zhang } 192d4c8c8deSLei Zhang 193*12d16de5SRahul Joshi unsigned Operator::getNumVariadicRegions() const { 1940359b86dSRiver Riddle return llvm::count_if(regions, 1950359b86dSRiver Riddle [](const NamedRegion &c) { return c.isVariadic(); }); 1960359b86dSRiver Riddle } 1970359b86dSRiver Riddle 198*12d16de5SRahul Joshi auto Operator::successor_begin() const -> const_successor_iterator { 199b1de971bSRiver Riddle return successors.begin(); 200b1de971bSRiver Riddle } 201*12d16de5SRahul Joshi auto Operator::successor_end() const -> const_successor_iterator { 202b1de971bSRiver Riddle return successors.end(); 203b1de971bSRiver Riddle } 204*12d16de5SRahul Joshi auto Operator::getSuccessors() const 205b1de971bSRiver Riddle -> llvm::iterator_range<const_successor_iterator> { 206b1de971bSRiver Riddle return {successor_begin(), successor_end()}; 207b1de971bSRiver Riddle } 208b1de971bSRiver Riddle 209*12d16de5SRahul Joshi unsigned Operator::getNumSuccessors() const { return successors.size(); } 210b1de971bSRiver Riddle 211*12d16de5SRahul Joshi const NamedSuccessor &Operator::getSuccessor(unsigned index) const { 212b1de971bSRiver Riddle return successors[index]; 213b1de971bSRiver Riddle } 214b1de971bSRiver Riddle 215*12d16de5SRahul Joshi unsigned Operator::getNumVariadicSuccessors() const { 216b1de971bSRiver Riddle return llvm::count_if(successors, 217b1de971bSRiver Riddle [](const NamedSuccessor &c) { return c.isVariadic(); }); 218b1de971bSRiver Riddle } 219b1de971bSRiver Riddle 220*12d16de5SRahul Joshi auto Operator::trait_begin() const -> const_trait_iterator { 2211725b485SJacques Pienaar return traits.begin(); 2221725b485SJacques Pienaar } 223*12d16de5SRahul Joshi auto Operator::trait_end() const -> const_trait_iterator { 2241725b485SJacques Pienaar return traits.end(); 2251725b485SJacques Pienaar } 226*12d16de5SRahul Joshi auto Operator::getTraits() const -> llvm::iterator_range<const_trait_iterator> { 2271725b485SJacques Pienaar return {trait_begin(), trait_end()}; 2281725b485SJacques Pienaar } 2291725b485SJacques Pienaar 230*12d16de5SRahul Joshi auto Operator::attribute_begin() const -> attribute_iterator { 2312a463c36SJacques Pienaar return attributes.begin(); 2322a463c36SJacques Pienaar } 233*12d16de5SRahul Joshi auto Operator::attribute_end() const -> attribute_iterator { 2342a463c36SJacques Pienaar return attributes.end(); 2352a463c36SJacques Pienaar } 236*12d16de5SRahul Joshi auto Operator::getAttributes() const 2373e5ee82bSLei Zhang -> llvm::iterator_range<attribute_iterator> { 2382a463c36SJacques Pienaar return {attribute_begin(), attribute_end()}; 2392a463c36SJacques Pienaar } 2402a463c36SJacques Pienaar 241*12d16de5SRahul Joshi auto Operator::operand_begin() -> value_iterator { return operands.begin(); } 242*12d16de5SRahul Joshi auto Operator::operand_end() -> value_iterator { return operands.end(); } 243*12d16de5SRahul Joshi auto Operator::getOperands() -> value_range { 2442a463c36SJacques Pienaar return {operand_begin(), operand_end()}; 2452a463c36SJacques Pienaar } 2462a463c36SJacques Pienaar 247*12d16de5SRahul Joshi auto Operator::getArg(int index) const -> Argument { return arguments[index]; } 2482a463c36SJacques Pienaar 24931f40f60SJacques Pienaar // Mapping from result index to combined argument and result index. Arguments 25031f40f60SJacques Pienaar // are indexed to match getArg index, while the result indexes are mapped to 25131f40f60SJacques Pienaar // avoid overlap. 25231f40f60SJacques Pienaar static int resultIndex(int i) { return -1 - i; } 25331f40f60SJacques Pienaar 254*12d16de5SRahul Joshi bool Operator::isVariadic() const { 25531f40f60SJacques Pienaar return any_of(llvm::concat<const NamedTypeConstraint>(operands, results), 25631f40f60SJacques Pienaar [](const NamedTypeConstraint &op) { return op.isVariadic(); }); 25731f40f60SJacques Pienaar } 25831f40f60SJacques Pienaar 259*12d16de5SRahul Joshi void Operator::populateTypeInferenceInfo( 26031f40f60SJacques Pienaar const llvm::StringMap<int> &argumentsAndResultsIndex) { 26131f40f60SJacques Pienaar // If the type inference op interface is not registered, then do not attempt 26231f40f60SJacques Pienaar // to determine if the result types an be inferred. 26331f40f60SJacques Pienaar auto &recordKeeper = def.getRecords(); 26431f40f60SJacques Pienaar auto *inferTrait = recordKeeper.getDef(inferTypeOpInterface); 26531f40f60SJacques Pienaar allResultsHaveKnownTypes = false; 26631f40f60SJacques Pienaar if (!inferTrait) 26731f40f60SJacques Pienaar return; 26831f40f60SJacques Pienaar 26931f40f60SJacques Pienaar // If there are no results, the skip this else the build method generated 27031f40f60SJacques Pienaar // overlaps with another autogenerated builder. 27131f40f60SJacques Pienaar if (getNumResults() == 0) 27231f40f60SJacques Pienaar return; 27331f40f60SJacques Pienaar 27431f40f60SJacques Pienaar // Skip for ops with variadic operands/results. 27531f40f60SJacques Pienaar // TODO: This can be relaxed. 27631f40f60SJacques Pienaar if (isVariadic()) 27731f40f60SJacques Pienaar return; 27831f40f60SJacques Pienaar 27931f40f60SJacques Pienaar // Skip cases currently being custom generated. 28031f40f60SJacques Pienaar // TODO: Remove special cases. 28131f40f60SJacques Pienaar if (getTrait("OpTrait::SameOperandsAndResultType")) 28231f40f60SJacques Pienaar return; 28331f40f60SJacques Pienaar 28431f40f60SJacques Pienaar // We create equivalence classes of argument/result types where arguments 28531f40f60SJacques Pienaar // and results are mapped into the same index space and indices corresponding 28631f40f60SJacques Pienaar // to the same type are in the same equivalence class. 28731f40f60SJacques Pienaar llvm::EquivalenceClasses<int> ecs; 28831f40f60SJacques Pienaar resultTypeMapping.resize(getNumResults()); 28931f40f60SJacques Pienaar // Captures the argument whose type matches a given result type. Preference 29031f40f60SJacques Pienaar // towards capturing operands first before attributes. 29131f40f60SJacques Pienaar auto captureMapping = [&](int i) { 29231f40f60SJacques Pienaar bool found = false; 29331f40f60SJacques Pienaar ecs.insert(resultIndex(i)); 29431f40f60SJacques Pienaar auto mi = ecs.findLeader(resultIndex(i)); 29531f40f60SJacques Pienaar for (auto me = ecs.member_end(); mi != me; ++mi) { 29631f40f60SJacques Pienaar if (*mi < 0) { 29731f40f60SJacques Pienaar auto tc = getResultTypeConstraint(i); 29831f40f60SJacques Pienaar if (tc.getBuilderCall().hasValue()) { 29931f40f60SJacques Pienaar resultTypeMapping[i].emplace_back(tc); 30031f40f60SJacques Pienaar found = true; 30131f40f60SJacques Pienaar } 30231f40f60SJacques Pienaar continue; 30331f40f60SJacques Pienaar } 30431f40f60SJacques Pienaar 30548c800ccSMehdi Amini if (getArg(*mi).is<NamedAttribute *>()) { 30631f40f60SJacques Pienaar // TODO: Handle attributes. 30731f40f60SJacques Pienaar continue; 30831f40f60SJacques Pienaar } else { 30931f40f60SJacques Pienaar resultTypeMapping[i].emplace_back(*mi); 31031f40f60SJacques Pienaar found = true; 31131f40f60SJacques Pienaar } 31231f40f60SJacques Pienaar } 31331f40f60SJacques Pienaar return found; 31431f40f60SJacques Pienaar }; 31531f40f60SJacques Pienaar 31631f40f60SJacques Pienaar for (const OpTrait &trait : traits) { 31731f40f60SJacques Pienaar const llvm::Record &def = trait.getDef(); 31831f40f60SJacques Pienaar // If the infer type op interface was manually added, then treat it as 31931f40f60SJacques Pienaar // intention that the op needs special handling. 32031f40f60SJacques Pienaar // TODO: Reconsider whether to always generate, this is more conservative 32131f40f60SJacques Pienaar // and keeps existing behavior so starting that way for now. 32231f40f60SJacques Pienaar if (def.isSubClassOf( 32331f40f60SJacques Pienaar llvm::formatv("{0}::Trait", inferTypeOpInterface).str())) 32431f40f60SJacques Pienaar return; 325*12d16de5SRahul Joshi if (const auto *opTrait = dyn_cast<InterfaceOpTrait>(&trait)) 326572c2905SRiver Riddle if (&opTrait->getDef() == inferTrait) 32731f40f60SJacques Pienaar return; 32831f40f60SJacques Pienaar 32931f40f60SJacques Pienaar if (!def.isSubClassOf("AllTypesMatch")) 33031f40f60SJacques Pienaar continue; 33131f40f60SJacques Pienaar 33231f40f60SJacques Pienaar auto values = def.getValueAsListOfStrings("values"); 33331f40f60SJacques Pienaar auto root = argumentsAndResultsIndex.lookup(values.front()); 33431f40f60SJacques Pienaar for (StringRef str : values) 33531f40f60SJacques Pienaar ecs.unionSets(argumentsAndResultsIndex.lookup(str), root); 33631f40f60SJacques Pienaar } 33731f40f60SJacques Pienaar 33831f40f60SJacques Pienaar // Verifies that all output types have a corresponding known input type 33931f40f60SJacques Pienaar // and chooses matching operand or attribute (in that order) that 34031f40f60SJacques Pienaar // matches it. 34131f40f60SJacques Pienaar allResultsHaveKnownTypes = 34231f40f60SJacques Pienaar all_of(llvm::seq<int>(0, getNumResults()), captureMapping); 34331f40f60SJacques Pienaar 34431f40f60SJacques Pienaar // If the types could be computed, then add type inference trait. 34531f40f60SJacques Pienaar if (allResultsHaveKnownTypes) 34631f40f60SJacques Pienaar traits.push_back(OpTrait::create(inferTrait->getDefInit())); 34731f40f60SJacques Pienaar } 34831f40f60SJacques Pienaar 349*12d16de5SRahul Joshi void Operator::populateOpStructure() { 3502a463c36SJacques Pienaar auto &recordKeeper = def.getRecords(); 35131f40f60SJacques Pienaar auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint"); 35231f40f60SJacques Pienaar auto *attrClass = recordKeeper.getClass("Attr"); 35331f40f60SJacques Pienaar auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr"); 35431f40f60SJacques Pienaar auto *opVarClass = recordKeeper.getClass("OpVariable"); 35595949a0dSAlex Zinenko numNativeAttributes = 0; 3562a463c36SJacques Pienaar 3572a463c36SJacques Pienaar DagInit *argumentValues = def.getValueAsDag("arguments"); 358796ca609SLei Zhang unsigned numArgs = argumentValues->getNumArgs(); 359796ca609SLei Zhang 36031f40f60SJacques Pienaar // Mapping from name of to argument or result index. Arguments are indexed 36131f40f60SJacques Pienaar // to match getArg index, while the results are negatively indexed. 36231f40f60SJacques Pienaar llvm::StringMap<int> argumentsAndResultsIndex; 36331f40f60SJacques Pienaar 36495949a0dSAlex Zinenko // Handle operands and native attributes. 365796ca609SLei Zhang for (unsigned i = 0; i != numArgs; ++i) { 36631f40f60SJacques Pienaar auto *arg = argumentValues->getArg(i); 36766647a31SLei Zhang auto givenName = argumentValues->getArgNameStr(i); 36831f40f60SJacques Pienaar auto *argDefInit = dyn_cast<DefInit>(arg); 3692a463c36SJacques Pienaar if (!argDefInit) 3702a463c36SJacques Pienaar PrintFatalError(def.getLoc(), 371e0fc5038SLei Zhang Twine("undefined type for argument #") + Twine(i)); 3722a463c36SJacques Pienaar Record *argDef = argDefInit->getDef(); 37320dca522SRiver Riddle if (argDef->isSubClassOf(opVarClass)) 37420dca522SRiver Riddle argDef = argDef->getValueAsDef("constraint"); 37595949a0dSAlex Zinenko 37695949a0dSAlex Zinenko if (argDef->isSubClassOf(typeConstraintClass)) { 377509cd739SJacques Pienaar operands.push_back( 37820dca522SRiver Riddle NamedTypeConstraint{givenName, TypeConstraint(argDef)}); 37995949a0dSAlex Zinenko } else if (argDef->isSubClassOf(attrClass)) { 38066647a31SLei Zhang if (givenName.empty()) 3812a463c36SJacques Pienaar PrintFatalError(argDef->getLoc(), "attributes must be named"); 38295949a0dSAlex Zinenko if (argDef->isSubClassOf(derivedAttrClass)) 38395949a0dSAlex Zinenko PrintFatalError(argDef->getLoc(), 384dde5bf23SJacques Pienaar "derived attributes not allowed in argument list"); 3859b034f0bSLei Zhang attributes.push_back({givenName, Attribute(argDef)}); 38695949a0dSAlex Zinenko ++numNativeAttributes; 38795949a0dSAlex Zinenko } else { 38895949a0dSAlex Zinenko PrintFatalError(def.getLoc(), "unexpected def type; only defs deriving " 38995949a0dSAlex Zinenko "from TypeConstraint or Attr are allowed"); 39095949a0dSAlex Zinenko } 39131f40f60SJacques Pienaar if (!givenName.empty()) 39231f40f60SJacques Pienaar argumentsAndResultsIndex[givenName] = i; 393dde5bf23SJacques Pienaar } 394dde5bf23SJacques Pienaar 395f8bbe5deSLei Zhang // Handle derived attributes. 396dde5bf23SJacques Pienaar for (const auto &val : def.getValues()) { 397dde5bf23SJacques Pienaar if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) { 398dde5bf23SJacques Pienaar if (!record->isSubClassOf(attrClass)) 399dde5bf23SJacques Pienaar continue; 400dde5bf23SJacques Pienaar if (!record->isSubClassOf(derivedAttrClass)) 401dde5bf23SJacques Pienaar PrintFatalError(def.getLoc(), 402dde5bf23SJacques Pienaar "unexpected Attr where only DerivedAttr is allowed"); 403dde5bf23SJacques Pienaar 404dde5bf23SJacques Pienaar if (record->getClasses().size() != 1) { 4052a463c36SJacques Pienaar PrintFatalError( 4062a463c36SJacques Pienaar def.getLoc(), 407dde5bf23SJacques Pienaar "unsupported attribute modelling, only single class expected"); 4082a463c36SJacques Pienaar } 40966647a31SLei Zhang attributes.push_back( 41066647a31SLei Zhang {cast<llvm::StringInit>(val.getNameInit())->getValue(), 4119b034f0bSLei Zhang Attribute(cast<DefInit>(val.getValue()))}); 412dde5bf23SJacques Pienaar } 4132a463c36SJacques Pienaar } 4141df6ca50SLei Zhang 415796ca609SLei Zhang // Populate `arguments`. This must happen after we've finalized `operands` and 416796ca609SLei Zhang // `attributes` because we will put their elements' pointers in `arguments`. 417796ca609SLei Zhang // SmallVector may perform re-allocation under the hood when adding new 418796ca609SLei Zhang // elements. 419796ca609SLei Zhang int operandIndex = 0, attrIndex = 0; 420796ca609SLei Zhang for (unsigned i = 0; i != numArgs; ++i) { 421796ca609SLei Zhang Record *argDef = dyn_cast<DefInit>(argumentValues->getArg(i))->getDef(); 42220dca522SRiver Riddle if (argDef->isSubClassOf(opVarClass)) 42320dca522SRiver Riddle argDef = argDef->getValueAsDef("constraint"); 424796ca609SLei Zhang 425796ca609SLei Zhang if (argDef->isSubClassOf(typeConstraintClass)) { 42671b9d89dSJacques Pienaar attrOrOperandMapping.push_back( 42771b9d89dSJacques Pienaar {OperandOrAttribute::Kind::Operand, operandIndex}); 428796ca609SLei Zhang arguments.emplace_back(&operands[operandIndex++]); 429796ca609SLei Zhang } else { 430796ca609SLei Zhang assert(argDef->isSubClassOf(attrClass)); 43171b9d89dSJacques Pienaar attrOrOperandMapping.push_back( 43271b9d89dSJacques Pienaar {OperandOrAttribute::Kind::Attribute, attrIndex}); 433796ca609SLei Zhang arguments.emplace_back(&attributes[attrIndex++]); 434796ca609SLei Zhang } 435796ca609SLei Zhang } 436796ca609SLei Zhang 437e0fc5038SLei Zhang auto *resultsDag = def.getValueAsDag("results"); 438e0fc5038SLei Zhang auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator()); 439e0fc5038SLei Zhang if (!outsOp || outsOp->getDef()->getName() != "outs") { 440e0fc5038SLei Zhang PrintFatalError(def.getLoc(), "'results' must have 'outs' directive"); 441e0fc5038SLei Zhang } 442e0fc5038SLei Zhang 443e0fc5038SLei Zhang // Handle results. 444e0fc5038SLei Zhang for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) { 445e0fc5038SLei Zhang auto name = resultsDag->getArgNameStr(i); 44620dca522SRiver Riddle auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i)); 44720dca522SRiver Riddle if (!resultInit) { 448e0fc5038SLei Zhang PrintFatalError(def.getLoc(), 449e0fc5038SLei Zhang Twine("undefined type for result #") + Twine(i)); 450e0fc5038SLei Zhang } 45120dca522SRiver Riddle auto *resultDef = resultInit->getDef(); 45220dca522SRiver Riddle if (resultDef->isSubClassOf(opVarClass)) 45320dca522SRiver Riddle resultDef = resultDef->getValueAsDef("constraint"); 4548f5fa566SLei Zhang results.push_back({name, TypeConstraint(resultDef)}); 45531f40f60SJacques Pienaar if (!name.empty()) 45631f40f60SJacques Pienaar argumentsAndResultsIndex[name] = resultIndex(i); 457e0fc5038SLei Zhang } 458e0fc5038SLei Zhang 459b1de971bSRiver Riddle // Handle successors 460b1de971bSRiver Riddle auto *successorsDag = def.getValueAsDag("successors"); 461b1de971bSRiver Riddle auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator()); 462b1de971bSRiver Riddle if (!successorsOp || successorsOp->getDef()->getName() != "successor") { 463b1de971bSRiver Riddle PrintFatalError(def.getLoc(), 464b1de971bSRiver Riddle "'successors' must have 'successor' directive"); 465b1de971bSRiver Riddle } 466b1de971bSRiver Riddle 467b1de971bSRiver Riddle for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) { 468b1de971bSRiver Riddle auto name = successorsDag->getArgNameStr(i); 469b1de971bSRiver Riddle auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i)); 470b1de971bSRiver Riddle if (!successorInit) { 471b1de971bSRiver Riddle PrintFatalError(def.getLoc(), 472b1de971bSRiver Riddle Twine("undefined kind for successor #") + Twine(i)); 473b1de971bSRiver Riddle } 474b1de971bSRiver Riddle Successor successor(successorInit->getDef()); 475b1de971bSRiver Riddle 476b1de971bSRiver Riddle // Only support variadic successors if it is the last one for now. 477b1de971bSRiver Riddle if (i != e - 1 && successor.isVariadic()) 478b1de971bSRiver Riddle PrintFatalError(def.getLoc(), "only the last successor can be variadic"); 479b1de971bSRiver Riddle successors.push_back({name, successor}); 480b1de971bSRiver Riddle } 481b1de971bSRiver Riddle 482b6d54a1bSJacques Pienaar // Create list of traits, skipping over duplicates: appending to lists in 483b6d54a1bSJacques Pienaar // tablegen is easy, making them unique less so, so dedupe here. 48431f40f60SJacques Pienaar if (auto *traitList = def.getValueAsListInit("traits")) { 485b6d54a1bSJacques Pienaar // This is uniquing based on pointers of the trait. 486b6d54a1bSJacques Pienaar SmallPtrSet<const llvm::Init *, 32> traitSet; 487b6d54a1bSJacques Pienaar traits.reserve(traitSet.size()); 48831f40f60SJacques Pienaar for (auto *traitInit : *traitList) { 489b6d54a1bSJacques Pienaar // Keep traits in the same order while skipping over duplicates. 490b6d54a1bSJacques Pienaar if (traitSet.insert(traitInit).second) 4911725b485SJacques Pienaar traits.push_back(OpTrait::create(traitInit)); 492b6d54a1bSJacques Pienaar } 493b6d54a1bSJacques Pienaar } 494d4c8c8deSLei Zhang 49531f40f60SJacques Pienaar populateTypeInferenceInfo(argumentsAndResultsIndex); 49631f40f60SJacques Pienaar 497d4c8c8deSLei Zhang // Handle regions 4983650df50SLei Zhang auto *regionsDag = def.getValueAsDag("regions"); 4993650df50SLei Zhang auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator()); 5003650df50SLei Zhang if (!regionsOp || regionsOp->getDef()->getName() != "region") { 5013650df50SLei Zhang PrintFatalError(def.getLoc(), "'regions' must have 'region' directive"); 5023650df50SLei Zhang } 5033650df50SLei Zhang 5043650df50SLei Zhang for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) { 5053650df50SLei Zhang auto name = regionsDag->getArgNameStr(i); 5063650df50SLei Zhang auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i)); 5073650df50SLei Zhang if (!regionInit) { 5083650df50SLei Zhang PrintFatalError(def.getLoc(), 5093650df50SLei Zhang Twine("undefined kind for region #") + Twine(i)); 5103650df50SLei Zhang } 5110359b86dSRiver Riddle Region region(regionInit->getDef()); 5120359b86dSRiver Riddle if (region.isVariadic()) { 5130359b86dSRiver Riddle // Only support variadic regions if it is the last one for now. 5140359b86dSRiver Riddle if (i != e - 1) 5150359b86dSRiver Riddle PrintFatalError(def.getLoc(), "only the last region can be variadic"); 5160359b86dSRiver Riddle if (name.empty()) 5170359b86dSRiver Riddle PrintFatalError(def.getLoc(), "variadic regions must be named"); 5180359b86dSRiver Riddle } 5190359b86dSRiver Riddle 5200359b86dSRiver Riddle regions.push_back({name, region}); 5213650df50SLei Zhang } 522796ca609SLei Zhang 523796ca609SLei Zhang LLVM_DEBUG(print(llvm::dbgs())); 5242a463c36SJacques Pienaar } 5258f249438SJacques Pienaar 526*12d16de5SRahul Joshi auto Operator::getSameTypeAsResult(int index) const -> ArrayRef<ArgOrType> { 52731f40f60SJacques Pienaar assert(allResultTypesKnown()); 52831f40f60SJacques Pienaar return resultTypeMapping[index]; 52931f40f60SJacques Pienaar } 53031f40f60SJacques Pienaar 531*12d16de5SRahul Joshi ArrayRef<llvm::SMLoc> Operator::getLoc() const { return def.getLoc(); } 5322927297aSSmit Hinsu 533*12d16de5SRahul Joshi bool Operator::hasDescription() const { 534a280e399SJacques Pienaar return def.getValue("description") != nullptr; 535a280e399SJacques Pienaar } 536a280e399SJacques Pienaar 537*12d16de5SRahul Joshi StringRef Operator::getDescription() const { 538a280e399SJacques Pienaar return def.getValueAsString("description"); 539a280e399SJacques Pienaar } 540a280e399SJacques Pienaar 541*12d16de5SRahul Joshi bool Operator::hasSummary() const { return def.getValue("summary") != nullptr; } 542a280e399SJacques Pienaar 543*12d16de5SRahul Joshi StringRef Operator::getSummary() const { 544a280e399SJacques Pienaar return def.getValueAsString("summary"); 545a280e399SJacques Pienaar } 546796ca609SLei Zhang 547*12d16de5SRahul Joshi bool Operator::hasAssemblyFormat() const { 5481a083f02SRiver Riddle auto *valueInit = def.getValueInit("assemblyFormat"); 549d891d738SRahul Joshi return isa<llvm::CodeInit, llvm::StringInit>(valueInit); 5501a083f02SRiver Riddle } 5511a083f02SRiver Riddle 552*12d16de5SRahul Joshi StringRef Operator::getAssemblyFormat() const { 5531a083f02SRiver Riddle return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat")) 5541a083f02SRiver Riddle .Case<llvm::StringInit, llvm::CodeInit>( 5551a083f02SRiver Riddle [&](auto *init) { return init->getValue(); }); 5561a083f02SRiver Riddle } 5571a083f02SRiver Riddle 558*12d16de5SRahul Joshi void Operator::print(llvm::raw_ostream &os) const { 559796ca609SLei Zhang os << "op '" << getOperationName() << "'\n"; 560796ca609SLei Zhang for (Argument arg : arguments) { 561796ca609SLei Zhang if (auto *attr = arg.dyn_cast<NamedAttribute *>()) 562796ca609SLei Zhang os << "[attribute] " << attr->name << '\n'; 563796ca609SLei Zhang else 564796ca609SLei Zhang os << "[operand] " << arg.get<NamedTypeConstraint *>()->name << '\n'; 565796ca609SLei Zhang } 566796ca609SLei Zhang } 56720dca522SRiver Riddle 568*12d16de5SRahul Joshi auto Operator::VariableDecoratorIterator::unwrap(llvm::Init *init) 56920dca522SRiver Riddle -> VariableDecorator { 57020dca522SRiver Riddle return VariableDecorator(cast<llvm::DefInit>(init)->getDef()); 57120dca522SRiver Riddle } 57271b9d89dSJacques Pienaar 573*12d16de5SRahul Joshi auto Operator::getArgToOperandOrAttribute(int index) const 57471b9d89dSJacques Pienaar -> OperandOrAttribute { 57571b9d89dSJacques Pienaar return attrOrOperandMapping[index]; 57671b9d89dSJacques Pienaar } 577