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" 145e118f93SMehdi Amini #include "mlir/TableGen/Argument.h" 158f249438SJacques Pienaar #include "mlir/TableGen/Predicate.h" 1694662ee0SRiver Riddle #include "mlir/TableGen/Trait.h" 17b2cc2c34SLei Zhang #include "mlir/TableGen/Type.h" 1831f40f60SJacques Pienaar #include "llvm/ADT/EquivalenceClasses.h" 1931f40f60SJacques Pienaar #include "llvm/ADT/STLExtras.h" 2031f40f60SJacques Pienaar #include "llvm/ADT/Sequence.h" 21b6d54a1bSJacques Pienaar #include "llvm/ADT/SmallPtrSet.h" 227d1ed69cSFederico Lebrón #include "llvm/ADT/StringExtras.h" 23ebf190fcSRiver Riddle #include "llvm/ADT/TypeSwitch.h" 24b12a7c88SMehdi Amini #include "llvm/Support/Debug.h" 256a994233SJacques Pienaar #include "llvm/Support/ErrorHandling.h" 262a463c36SJacques Pienaar #include "llvm/Support/FormatVariadic.h" 272a463c36SJacques Pienaar #include "llvm/TableGen/Error.h" 282a463c36SJacques Pienaar #include "llvm/TableGen/Record.h" 291b60f0d7SJeff Niu #include <list> 302a463c36SJacques Pienaar 31796ca609SLei Zhang #define DEBUG_TYPE "mlir-tblgen-operator" 32796ca609SLei Zhang 332a463c36SJacques Pienaar using namespace mlir; 3412d16de5SRahul Joshi using namespace mlir::tblgen; 353e5ee82bSLei Zhang 362a463c36SJacques Pienaar using llvm::DagInit; 372a463c36SJacques Pienaar using llvm::DefInit; 38659192b1SRahul Joshi using llvm::Init; 39659192b1SRahul Joshi using llvm::ListInit; 402a463c36SJacques Pienaar using llvm::Record; 41659192b1SRahul Joshi using llvm::StringInit; 422a463c36SJacques Pienaar 43659192b1SRahul Joshi Operator::Operator(const Record &def) 4420e0cedfSLei Zhang : dialect(def.getValueAsDef("opDialect")), def(def) { 4520e0cedfSLei Zhang // The first `_` in the op's TableGen def name is treated as separating the 4620e0cedfSLei Zhang // dialect prefix and the op class name. The dialect prefix will be ignored if 4720e0cedfSLei Zhang // not empty. Otherwise, if def name starts with a `_`, the `_` is considered 4820e0cedfSLei Zhang // as part of the class name. 4920e0cedfSLei Zhang StringRef prefix; 5020e0cedfSLei Zhang std::tie(prefix, cppClassName) = def.getName().split('_'); 5120e0cedfSLei Zhang if (prefix.empty()) { 5220e0cedfSLei Zhang // Class name with a leading underscore and without dialect prefix 538bb83517SLei Zhang cppClassName = def.getName(); 548bb83517SLei Zhang } else if (cppClassName.empty()) { 5520e0cedfSLei Zhang // Class name without dialect prefix 5620e0cedfSLei Zhang cppClassName = prefix; 572a463c36SJacques Pienaar } 582a463c36SJacques Pienaar 5949755871SSean Silva cppNamespace = def.getValueAsString("cppNamespace"); 6049755871SSean Silva 618bb83517SLei Zhang populateOpStructure(); 627fb2394aSMehdi Amini assertInvariants(); 632a463c36SJacques Pienaar } 642a463c36SJacques Pienaar 6512d16de5SRahul Joshi std::string Operator::getOperationName() const { 6620e0cedfSLei Zhang auto prefix = dialect.getName(); 6720e0cedfSLei Zhang auto opName = def.getValueAsString("opName"); 680ea6154bSJacques Pienaar if (prefix.empty()) 69adcd0268SBenjamin Kramer return std::string(opName); 70adcd0268SBenjamin Kramer return std::string(llvm::formatv("{0}.{1}", prefix, opName)); 712a463c36SJacques Pienaar } 722a463c36SJacques Pienaar 7312d16de5SRahul Joshi std::string Operator::getAdaptorName() const { 742d2c73c5SJacques Pienaar return std::string(llvm::formatv("{0}Adaptor", getCppClassName())); 75fefe4366SJacques Pienaar } 76fefe4366SJacques Pienaar 77cf6f2175SMarkus Böck std::string Operator::getGenericAdaptorName() const { 78cf6f2175SMarkus Böck return std::string(llvm::formatv("{0}GenericAdaptor", getCppClassName())); 79cf6f2175SMarkus Böck } 80cf6f2175SMarkus Böck 81b74192b7SRiver Riddle /// Assert the invariants of accessors generated for the given name. 82b74192b7SRiver Riddle static void assertAccessorInvariants(const Operator &op, StringRef name) { 83b74192b7SRiver Riddle std::string accessorName = 84b74192b7SRiver Riddle convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true); 85b74192b7SRiver Riddle 86b74192b7SRiver Riddle // Functor used to detect when an accessor will cause an overlap with an 87b74192b7SRiver Riddle // operation API. 88b74192b7SRiver Riddle // 89b74192b7SRiver Riddle // There are a little bit more invasive checks possible for cases where not 90b74192b7SRiver Riddle // all ops have the trait that would cause overlap. For many cases here, 91b74192b7SRiver Riddle // renaming would be better (e.g., we can only guard in limited manner 92b74192b7SRiver Riddle // against methods from traits and interfaces here, so avoiding these in op 93b74192b7SRiver Riddle // definition is safer). 94b74192b7SRiver Riddle auto nameOverlapsWithOpAPI = [&](StringRef newName) { 95b74192b7SRiver Riddle if (newName == "AttributeNames" || newName == "Attributes" || 96b74192b7SRiver Riddle newName == "Operation") 97b74192b7SRiver Riddle return true; 98b74192b7SRiver Riddle if (newName == "Operands") 99b74192b7SRiver Riddle return op.getNumOperands() != 1 || op.getNumVariableLengthOperands() != 1; 100b74192b7SRiver Riddle if (newName == "Regions") 101b74192b7SRiver Riddle return op.getNumRegions() != 1 || op.getNumVariadicRegions() != 1; 102b74192b7SRiver Riddle if (newName == "Type") 103b74192b7SRiver Riddle return op.getNumResults() != 1; 104b74192b7SRiver Riddle return false; 105b74192b7SRiver Riddle }; 106b74192b7SRiver Riddle if (nameOverlapsWithOpAPI(accessorName)) { 107b74192b7SRiver Riddle // This error could be avoided in situations where the final function is 108b74192b7SRiver Riddle // identical, but preferably the op definition should avoid using generic 109b74192b7SRiver Riddle // names. 110b74192b7SRiver Riddle PrintFatalError(op.getLoc(), "generated accessor for `" + name + 111b74192b7SRiver Riddle "` overlaps with a default one; please " 112b74192b7SRiver Riddle "rename to avoid overlap"); 113b74192b7SRiver Riddle } 114b74192b7SRiver Riddle } 115b74192b7SRiver Riddle 1167fb2394aSMehdi Amini void Operator::assertInvariants() const { 1177fb2394aSMehdi Amini // Check that the name of arguments/results/regions/successors don't overlap. 1187fb2394aSMehdi Amini DenseMap<StringRef, StringRef> existingNames; 1197fb2394aSMehdi Amini auto checkName = [&](StringRef name, StringRef entity) { 1207fb2394aSMehdi Amini if (name.empty()) 1217fb2394aSMehdi Amini return; 1227fb2394aSMehdi Amini auto insertion = existingNames.insert({name, entity}); 123b74192b7SRiver Riddle if (insertion.second) { 124b74192b7SRiver Riddle // Assert invariants for accessors generated for this name. 125b74192b7SRiver Riddle assertAccessorInvariants(*this, name); 1267fb2394aSMehdi Amini return; 127b74192b7SRiver Riddle } 1287fb2394aSMehdi Amini if (entity == insertion.first->second) 1297fb2394aSMehdi Amini PrintFatalError(getLoc(), "op has a conflict with two " + entity + 1307fb2394aSMehdi Amini " having the same name '" + name + "'"); 1317fb2394aSMehdi Amini PrintFatalError(getLoc(), "op has a conflict with " + 1327fb2394aSMehdi Amini insertion.first->second + " and " + entity + 1337fb2394aSMehdi Amini " both having an entry with the name '" + 1347fb2394aSMehdi Amini name + "'"); 1357fb2394aSMehdi Amini }; 1367fb2394aSMehdi Amini // Check operands amongst themselves. 1377fb2394aSMehdi Amini for (int i : llvm::seq<int>(0, getNumOperands())) 1387fb2394aSMehdi Amini checkName(getOperand(i).name, "operands"); 1397fb2394aSMehdi Amini 1407fb2394aSMehdi Amini // Check results amongst themselves and against operands. 1417fb2394aSMehdi Amini for (int i : llvm::seq<int>(0, getNumResults())) 1427fb2394aSMehdi Amini checkName(getResult(i).name, "results"); 1437fb2394aSMehdi Amini 1447fb2394aSMehdi Amini // Check regions amongst themselves and against operands and results. 1457fb2394aSMehdi Amini for (int i : llvm::seq<int>(0, getNumRegions())) 1467fb2394aSMehdi Amini checkName(getRegion(i).name, "regions"); 1477fb2394aSMehdi Amini 1487fb2394aSMehdi Amini // Check successors amongst themselves and against operands, results, and 1497fb2394aSMehdi Amini // regions. 1507fb2394aSMehdi Amini for (int i : llvm::seq<int>(0, getNumSuccessors())) 1517fb2394aSMehdi Amini checkName(getSuccessor(i).name, "successors"); 1527fb2394aSMehdi Amini } 1537fb2394aSMehdi Amini 15412d16de5SRahul Joshi StringRef Operator::getDialectName() const { return dialect.getName(); } 15520e0cedfSLei Zhang 15612d16de5SRahul Joshi StringRef Operator::getCppClassName() const { return cppClassName; } 1578bb83517SLei Zhang 15812d16de5SRahul Joshi std::string Operator::getQualCppClassName() const { 15949755871SSean Silva if (cppNamespace.empty()) 160adcd0268SBenjamin Kramer return std::string(cppClassName); 16149755871SSean Silva return std::string(llvm::formatv("{0}::{1}", cppNamespace, cppClassName)); 162c396c044SJacques Pienaar } 1632a463c36SJacques Pienaar 16449755871SSean Silva StringRef Operator::getCppNamespace() const { return cppNamespace; } 16549755871SSean Silva 16612d16de5SRahul Joshi int Operator::getNumResults() const { 167e768b076SRahul Joshi const DagInit *results = def.getValueAsDag("results"); 168c224a518SLei Zhang return results->getNumArgs(); 169c224a518SLei Zhang } 170c224a518SLei Zhang 17112d16de5SRahul Joshi StringRef Operator::getExtraClassDeclaration() const { 172041e9618SJacques Pienaar constexpr auto attr = "extraClassDeclaration"; 173041e9618SJacques Pienaar if (def.isValueUnset(attr)) 174041e9618SJacques Pienaar return {}; 175041e9618SJacques Pienaar return def.getValueAsString(attr); 176041e9618SJacques Pienaar } 177041e9618SJacques Pienaar 178b0774e5fSMogball StringRef Operator::getExtraClassDefinition() const { 179b0774e5fSMogball constexpr auto attr = "extraClassDefinition"; 180b0774e5fSMogball if (def.isValueUnset(attr)) 181b0774e5fSMogball return {}; 182b0774e5fSMogball return def.getValueAsString(attr); 183b0774e5fSMogball } 184b0774e5fSMogball 185659192b1SRahul Joshi const Record &Operator::getDef() const { return def; } 186252de8ecSAlex Zinenko 18712d16de5SRahul Joshi bool Operator::skipDefaultBuilders() const { 188ead1acaeSAlex Zinenko return def.getValueAsBit("skipDefaultBuilders"); 189ead1acaeSAlex Zinenko } 190ead1acaeSAlex Zinenko 19178fdbdbfSMehdi Amini auto Operator::result_begin() const -> const_value_iterator { 19278fdbdbfSMehdi Amini return results.begin(); 19378fdbdbfSMehdi Amini } 1943f517af9SLei Zhang 19578fdbdbfSMehdi Amini auto Operator::result_end() const -> const_value_iterator { 19678fdbdbfSMehdi Amini return results.end(); 19778fdbdbfSMehdi Amini } 1983f517af9SLei Zhang 19978fdbdbfSMehdi Amini auto Operator::getResults() const -> const_value_range { 2003f517af9SLei Zhang return {result_begin(), result_end()}; 2013f517af9SLei Zhang } 2023f517af9SLei Zhang 20312d16de5SRahul Joshi TypeConstraint Operator::getResultTypeConstraint(int index) const { 204e768b076SRahul Joshi const DagInit *results = def.getValueAsDag("results"); 2058f5fa566SLei Zhang return TypeConstraint(cast<DefInit>(results->getArg(index))); 206c224a518SLei Zhang } 207c224a518SLei Zhang 20812d16de5SRahul Joshi StringRef Operator::getResultName(int index) const { 209e768b076SRahul Joshi const DagInit *results = def.getValueAsDag("results"); 2101725b485SJacques Pienaar return results->getArgNameStr(index); 211e0fc5038SLei Zhang } 212e0fc5038SLei Zhang 21312d16de5SRahul Joshi auto Operator::getResultDecorators(int index) const -> var_decorator_range { 214d256b9e8SRahul Joshi const Record *result = 21520dca522SRiver Riddle cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef(); 21620dca522SRiver Riddle if (!result->isSubClassOf("OpVariable")) 21720dca522SRiver Riddle return var_decorator_range(nullptr, nullptr); 21820dca522SRiver Riddle return *result->getValueAsListInit("decorators"); 21920dca522SRiver Riddle } 22020dca522SRiver Riddle 22112d16de5SRahul Joshi unsigned Operator::getNumVariableLengthResults() const { 222aba1acc8SRiver Riddle return llvm::count_if(results, [](const NamedTypeConstraint &c) { 223aba1acc8SRiver Riddle return c.constraint.isVariableLength(); 224aba1acc8SRiver Riddle }); 225c224a518SLei Zhang } 226c224a518SLei Zhang 22712d16de5SRahul Joshi unsigned Operator::getNumVariableLengthOperands() const { 228aba1acc8SRiver Riddle return llvm::count_if(operands, [](const NamedTypeConstraint &c) { 229aba1acc8SRiver Riddle return c.constraint.isVariableLength(); 230aba1acc8SRiver Riddle }); 2311df6ca50SLei Zhang } 2321df6ca50SLei Zhang 23312d16de5SRahul Joshi bool Operator::hasSingleVariadicArg() const { 23426d513d1SKazu Hirata return getNumArgs() == 1 && isa<NamedTypeConstraint *>(getArg(0)) && 23513d05787SRahul Joshi getOperand(0).isVariadic(); 23613d05787SRahul Joshi } 23713d05787SRahul Joshi 23812d16de5SRahul Joshi Operator::arg_iterator Operator::arg_begin() const { return arguments.begin(); } 239020f9eb6SLei Zhang 24012d16de5SRahul Joshi Operator::arg_iterator Operator::arg_end() const { return arguments.end(); } 241020f9eb6SLei Zhang 24212d16de5SRahul Joshi Operator::arg_range Operator::getArgs() const { 243020f9eb6SLei Zhang return {arg_begin(), arg_end()}; 244020f9eb6SLei Zhang } 245020f9eb6SLei Zhang 24612d16de5SRahul Joshi StringRef Operator::getArgName(int index) const { 247e768b076SRahul Joshi const DagInit *argumentValues = def.getValueAsDag("arguments"); 248c5a6712fSAlex Zinenko return argumentValues->getArgNameStr(index); 2492a463c36SJacques Pienaar } 2502a463c36SJacques Pienaar 25112d16de5SRahul Joshi auto Operator::getArgDecorators(int index) const -> var_decorator_range { 252d256b9e8SRahul Joshi const Record *arg = 25320dca522SRiver Riddle cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef(); 25420dca522SRiver Riddle if (!arg->isSubClassOf("OpVariable")) 25520dca522SRiver Riddle return var_decorator_range(nullptr, nullptr); 25620dca522SRiver Riddle return *arg->getValueAsListInit("decorators"); 25720dca522SRiver Riddle } 25820dca522SRiver Riddle 25994662ee0SRiver Riddle const Trait *Operator::getTrait(StringRef trait) const { 26013c6e419SLei Zhang for (const auto &t : traits) { 26194662ee0SRiver Riddle if (const auto *traitDef = dyn_cast<NativeTrait>(&t)) { 26294662ee0SRiver Riddle if (traitDef->getFullyQualifiedTraitName() == trait) 26394662ee0SRiver Riddle return traitDef; 26494662ee0SRiver Riddle } else if (const auto *traitDef = dyn_cast<InternalTrait>(&t)) { 26594662ee0SRiver Riddle if (traitDef->getFullyQualifiedTraitName() == trait) 26694662ee0SRiver Riddle return traitDef; 26794662ee0SRiver Riddle } else if (const auto *traitDef = dyn_cast<InterfaceTrait>(&t)) { 26894662ee0SRiver Riddle if (traitDef->getFullyQualifiedTraitName() == trait) 26994662ee0SRiver Riddle return traitDef; 270c489f50eSFeng Liu } 2711725b485SJacques Pienaar } 27213c6e419SLei Zhang return nullptr; 273eb3f8dcbSLei Zhang } 274eb3f8dcbSLei Zhang 27512d16de5SRahul Joshi auto Operator::region_begin() const -> const_region_iterator { 2760359b86dSRiver Riddle return regions.begin(); 2770359b86dSRiver Riddle } 27812d16de5SRahul Joshi auto Operator::region_end() const -> const_region_iterator { 2790359b86dSRiver Riddle return regions.end(); 2800359b86dSRiver Riddle } 28112d16de5SRahul Joshi auto Operator::getRegions() const 2820359b86dSRiver Riddle -> llvm::iterator_range<const_region_iterator> { 2830359b86dSRiver Riddle return {region_begin(), region_end()}; 2840359b86dSRiver Riddle } 2850359b86dSRiver Riddle 28612d16de5SRahul Joshi unsigned Operator::getNumRegions() const { return regions.size(); } 2873650df50SLei Zhang 28812d16de5SRahul Joshi const NamedRegion &Operator::getRegion(unsigned index) const { 2893650df50SLei Zhang return regions[index]; 2903650df50SLei Zhang } 291d4c8c8deSLei Zhang 29212d16de5SRahul Joshi unsigned Operator::getNumVariadicRegions() const { 2930359b86dSRiver Riddle return llvm::count_if(regions, 2940359b86dSRiver Riddle [](const NamedRegion &c) { return c.isVariadic(); }); 2950359b86dSRiver Riddle } 2960359b86dSRiver Riddle 29712d16de5SRahul Joshi auto Operator::successor_begin() const -> const_successor_iterator { 298b1de971bSRiver Riddle return successors.begin(); 299b1de971bSRiver Riddle } 30012d16de5SRahul Joshi auto Operator::successor_end() const -> const_successor_iterator { 301b1de971bSRiver Riddle return successors.end(); 302b1de971bSRiver Riddle } 30312d16de5SRahul Joshi auto Operator::getSuccessors() const 304b1de971bSRiver Riddle -> llvm::iterator_range<const_successor_iterator> { 305b1de971bSRiver Riddle return {successor_begin(), successor_end()}; 306b1de971bSRiver Riddle } 307b1de971bSRiver Riddle 30812d16de5SRahul Joshi unsigned Operator::getNumSuccessors() const { return successors.size(); } 309b1de971bSRiver Riddle 31012d16de5SRahul Joshi const NamedSuccessor &Operator::getSuccessor(unsigned index) const { 311b1de971bSRiver Riddle return successors[index]; 312b1de971bSRiver Riddle } 313b1de971bSRiver Riddle 31412d16de5SRahul Joshi unsigned Operator::getNumVariadicSuccessors() const { 315b1de971bSRiver Riddle return llvm::count_if(successors, 316b1de971bSRiver Riddle [](const NamedSuccessor &c) { return c.isVariadic(); }); 317b1de971bSRiver Riddle } 318b1de971bSRiver Riddle 31912d16de5SRahul Joshi auto Operator::trait_begin() const -> const_trait_iterator { 3201725b485SJacques Pienaar return traits.begin(); 3211725b485SJacques Pienaar } 32212d16de5SRahul Joshi auto Operator::trait_end() const -> const_trait_iterator { 3231725b485SJacques Pienaar return traits.end(); 3241725b485SJacques Pienaar } 32512d16de5SRahul Joshi auto Operator::getTraits() const -> llvm::iterator_range<const_trait_iterator> { 3261725b485SJacques Pienaar return {trait_begin(), trait_end()}; 3271725b485SJacques Pienaar } 3281725b485SJacques Pienaar 3295e118f93SMehdi Amini auto Operator::attribute_begin() const -> const_attribute_iterator { 3302a463c36SJacques Pienaar return attributes.begin(); 3312a463c36SJacques Pienaar } 3325e118f93SMehdi Amini auto Operator::attribute_end() const -> const_attribute_iterator { 3332a463c36SJacques Pienaar return attributes.end(); 3342a463c36SJacques Pienaar } 33512d16de5SRahul Joshi auto Operator::getAttributes() const 3365e118f93SMehdi Amini -> llvm::iterator_range<const_attribute_iterator> { 3375e118f93SMehdi Amini return {attribute_begin(), attribute_end()}; 3385e118f93SMehdi Amini } 3395e118f93SMehdi Amini auto Operator::attribute_begin() -> attribute_iterator { 3405e118f93SMehdi Amini return attributes.begin(); 3415e118f93SMehdi Amini } 3425e118f93SMehdi Amini auto Operator::attribute_end() -> attribute_iterator { 3435e118f93SMehdi Amini return attributes.end(); 3445e118f93SMehdi Amini } 3455e118f93SMehdi Amini auto Operator::getAttributes() -> llvm::iterator_range<attribute_iterator> { 3462a463c36SJacques Pienaar return {attribute_begin(), attribute_end()}; 3472a463c36SJacques Pienaar } 3482a463c36SJacques Pienaar 34978fdbdbfSMehdi Amini auto Operator::operand_begin() const -> const_value_iterator { 35078fdbdbfSMehdi Amini return operands.begin(); 35178fdbdbfSMehdi Amini } 35278fdbdbfSMehdi Amini auto Operator::operand_end() const -> const_value_iterator { 35378fdbdbfSMehdi Amini return operands.end(); 35478fdbdbfSMehdi Amini } 35578fdbdbfSMehdi Amini auto Operator::getOperands() const -> const_value_range { 3562a463c36SJacques Pienaar return {operand_begin(), operand_end()}; 3572a463c36SJacques Pienaar } 3582a463c36SJacques Pienaar 35912d16de5SRahul Joshi auto Operator::getArg(int index) const -> Argument { return arguments[index]; } 3602a463c36SJacques Pienaar 36112d16de5SRahul Joshi bool Operator::isVariadic() const { 36231f40f60SJacques Pienaar return any_of(llvm::concat<const NamedTypeConstraint>(operands, results), 36331f40f60SJacques Pienaar [](const NamedTypeConstraint &op) { return op.isVariadic(); }); 36431f40f60SJacques Pienaar } 36531f40f60SJacques Pienaar 36612d16de5SRahul Joshi void Operator::populateTypeInferenceInfo( 36731f40f60SJacques Pienaar const llvm::StringMap<int> &argumentsAndResultsIndex) { 36831f40f60SJacques Pienaar // If the type inference op interface is not registered, then do not attempt 36931f40f60SJacques Pienaar // to determine if the result types an be inferred. 37031f40f60SJacques Pienaar auto &recordKeeper = def.getRecords(); 37131f40f60SJacques Pienaar auto *inferTrait = recordKeeper.getDef(inferTypeOpInterface); 37231f40f60SJacques Pienaar allResultsHaveKnownTypes = false; 37331f40f60SJacques Pienaar if (!inferTrait) 37431f40f60SJacques Pienaar return; 37531f40f60SJacques Pienaar 37631f40f60SJacques Pienaar // If there are no results, the skip this else the build method generated 37731f40f60SJacques Pienaar // overlaps with another autogenerated builder. 37831f40f60SJacques Pienaar if (getNumResults() == 0) 37931f40f60SJacques Pienaar return; 38031f40f60SJacques Pienaar 3813ce2ee28SBenjamin Kramer // Skip ops with variadic or optional results. 3823ce2ee28SBenjamin Kramer if (getNumVariableLengthResults() > 0) 38331f40f60SJacques Pienaar return; 38431f40f60SJacques Pienaar 38531f40f60SJacques Pienaar // Skip cases currently being custom generated. 38631f40f60SJacques Pienaar // TODO: Remove special cases. 38792a836daSRiver Riddle if (getTrait("::mlir::OpTrait::SameOperandsAndResultType")) { 38892a836daSRiver Riddle // Check for a non-variable length operand to use as the type anchor. 38992a836daSRiver Riddle auto *operandI = llvm::find_if(arguments, [](const Argument &arg) { 39068f58812STres Popp NamedTypeConstraint *operand = llvm::dyn_cast_if_present<NamedTypeConstraint *>(arg); 39192a836daSRiver Riddle return operand && !operand->isVariableLength(); 39292a836daSRiver Riddle }); 39392a836daSRiver Riddle if (operandI == arguments.end()) 39431f40f60SJacques Pienaar return; 39531f40f60SJacques Pienaar 3961b60f0d7SJeff Niu // All result types are inferred from the operand type. 39792a836daSRiver Riddle int operandIdx = operandI - arguments.begin(); 39892a836daSRiver Riddle for (int i = 0; i < getNumResults(); ++i) 3991b60f0d7SJeff Niu resultTypeMapping.emplace_back(operandIdx, "$_self"); 40092a836daSRiver Riddle 40192a836daSRiver Riddle allResultsHaveKnownTypes = true; 40292a836daSRiver Riddle traits.push_back(Trait::create(inferTrait->getDefInit())); 40392a836daSRiver Riddle return; 40492a836daSRiver Riddle } 40592a836daSRiver Riddle 4061b60f0d7SJeff Niu /// This struct represents a node in this operation's result type inferenece 4071b60f0d7SJeff Niu /// graph. Each node has a list of incoming type inference edges `sources`. 4081b60f0d7SJeff Niu /// Each edge represents a "source" from which the result type can be 4091b60f0d7SJeff Niu /// inferred, either an operand (leaf) or another result (node). When a node 4101b60f0d7SJeff Niu /// is known to have a fully-inferred type, `inferred` is set to true. 4111b60f0d7SJeff Niu struct ResultTypeInference { 4121b60f0d7SJeff Niu /// The list of incoming type inference edges. 4131b60f0d7SJeff Niu SmallVector<InferredResultType> sources; 4141b60f0d7SJeff Niu /// This flag is set to true when the result type is known to be inferrable. 4151b60f0d7SJeff Niu bool inferred = false; 41631f40f60SJacques Pienaar }; 41731f40f60SJacques Pienaar 4181b60f0d7SJeff Niu // This vector represents the type inference graph, with one node for each 4191b60f0d7SJeff Niu // operation result. The nth element is the node for the nth result. 4201b60f0d7SJeff Niu SmallVector<ResultTypeInference> inference(getNumResults(), {}); 4211b60f0d7SJeff Niu 4221b60f0d7SJeff Niu // For all results whose types are buildable, initialize their type inference 4231b60f0d7SJeff Niu // nodes with an edge to themselves. Mark those nodes are fully-inferred. 4248c258fdaSJakub Kuderski for (auto [idx, infer] : llvm::enumerate(inference)) { 4251b60f0d7SJeff Niu if (getResult(idx).constraint.getBuilderCall()) { 4261b60f0d7SJeff Niu infer.sources.emplace_back(InferredResultType::mapResultIndex(idx), 4271b60f0d7SJeff Niu "$_self"); 4281b60f0d7SJeff Niu infer.inferred = true; 4291b60f0d7SJeff Niu } 4301b60f0d7SJeff Niu } 4311b60f0d7SJeff Niu 4321b60f0d7SJeff Niu // Use `AllTypesMatch` and `TypesMatchWith` operation traits to build the 4331b60f0d7SJeff Niu // result type inference graph. 43494662ee0SRiver Riddle for (const Trait &trait : traits) { 435659192b1SRahul Joshi const Record &def = trait.getDef(); 4361b60f0d7SJeff Niu 43731f40f60SJacques Pienaar // If the infer type op interface was manually added, then treat it as 43831f40f60SJacques Pienaar // intention that the op needs special handling. 43931f40f60SJacques Pienaar // TODO: Reconsider whether to always generate, this is more conservative 44031f40f60SJacques Pienaar // and keeps existing behavior so starting that way for now. 44131f40f60SJacques Pienaar if (def.isSubClassOf( 44231f40f60SJacques Pienaar llvm::formatv("{0}::Trait", inferTypeOpInterface).str())) 44331f40f60SJacques Pienaar return; 44494662ee0SRiver Riddle if (const auto *traitDef = dyn_cast<InterfaceTrait>(&trait)) 44594662ee0SRiver Riddle if (&traitDef->getDef() == inferTrait) 44631f40f60SJacques Pienaar return; 44731f40f60SJacques Pienaar 4481b60f0d7SJeff Niu // The `TypesMatchWith` trait represents a 1 -> 1 type inference edge with a 4491b60f0d7SJeff Niu // type transformer. 4501b60f0d7SJeff Niu if (def.isSubClassOf("TypesMatchWith")) { 4511b60f0d7SJeff Niu int target = argumentsAndResultsIndex.lookup(def.getValueAsString("rhs")); 4521b60f0d7SJeff Niu // Ignore operand type inference. 4531b60f0d7SJeff Niu if (InferredResultType::isArgIndex(target)) 4541b60f0d7SJeff Niu continue; 4551b60f0d7SJeff Niu int resultIndex = InferredResultType::unmapResultIndex(target); 4561b60f0d7SJeff Niu ResultTypeInference &infer = inference[resultIndex]; 4571b60f0d7SJeff Niu // If the type of the result has already been inferred, do nothing. 4581b60f0d7SJeff Niu if (infer.inferred) 4591b60f0d7SJeff Niu continue; 4601b60f0d7SJeff Niu int sourceIndex = 4611b60f0d7SJeff Niu argumentsAndResultsIndex.lookup(def.getValueAsString("lhs")); 4621b60f0d7SJeff Niu infer.sources.emplace_back(sourceIndex, 4631b60f0d7SJeff Niu def.getValueAsString("transformer").str()); 4641b60f0d7SJeff Niu // Locally propagate inferredness. 4651b60f0d7SJeff Niu infer.inferred = 4661b60f0d7SJeff Niu InferredResultType::isArgIndex(sourceIndex) || 4671b60f0d7SJeff Niu inference[InferredResultType::unmapResultIndex(sourceIndex)].inferred; 4681b60f0d7SJeff Niu continue; 4691b60f0d7SJeff Niu } 4701b60f0d7SJeff Niu 47131f40f60SJacques Pienaar if (!def.isSubClassOf("AllTypesMatch")) 47231f40f60SJacques Pienaar continue; 47331f40f60SJacques Pienaar 47431f40f60SJacques Pienaar auto values = def.getValueAsListOfStrings("values"); 4751b60f0d7SJeff Niu // The `AllTypesMatch` trait represents an N <-> N fanin and fanout. That 4761b60f0d7SJeff Niu // is, every result type has an edge from every other type. However, if any 4771b60f0d7SJeff Niu // one of the values refers to an operand or a result with a fully-inferred 4781b60f0d7SJeff Niu // type, we can infer all other types from that value. Try to find a 4791b60f0d7SJeff Niu // fully-inferred type in the list. 4801b60f0d7SJeff Niu std::optional<int> fullyInferredIndex; 4811b60f0d7SJeff Niu SmallVector<int> resultIndices; 4821b60f0d7SJeff Niu for (StringRef name : values) { 4831b60f0d7SJeff Niu int index = argumentsAndResultsIndex.lookup(name); 4841b60f0d7SJeff Niu if (InferredResultType::isResultIndex(index)) 4851b60f0d7SJeff Niu resultIndices.push_back(InferredResultType::unmapResultIndex(index)); 4861b60f0d7SJeff Niu if (InferredResultType::isArgIndex(index) || 4871b60f0d7SJeff Niu inference[InferredResultType::unmapResultIndex(index)].inferred) 4881b60f0d7SJeff Niu fullyInferredIndex = index; 4891b60f0d7SJeff Niu } 4901b60f0d7SJeff Niu if (fullyInferredIndex) { 4911b60f0d7SJeff Niu // Make the fully-inferred type the only source for all results that 4921b60f0d7SJeff Niu // aren't already inferred -- a 1 -> N fanout. 4931b60f0d7SJeff Niu for (int resultIndex : resultIndices) { 4941b60f0d7SJeff Niu ResultTypeInference &infer = inference[resultIndex]; 4951b60f0d7SJeff Niu if (!infer.inferred) { 4961b60f0d7SJeff Niu infer.sources.assign(1, {*fullyInferredIndex, "$_self"}); 4971b60f0d7SJeff Niu infer.inferred = true; 4981b60f0d7SJeff Niu } 4991b60f0d7SJeff Niu } 5001b60f0d7SJeff Niu } else { 5011b60f0d7SJeff Niu // Add an edge between every result and every other type; N <-> N. 5021b60f0d7SJeff Niu for (int resultIndex : resultIndices) { 5031b60f0d7SJeff Niu for (int otherResultIndex : resultIndices) { 5041b60f0d7SJeff Niu if (resultIndex == otherResultIndex) 5051b60f0d7SJeff Niu continue; 506*7aebacbeSPhilipp Schilk inference[resultIndex].sources.emplace_back( 507*7aebacbeSPhilipp Schilk InferredResultType::unmapResultIndex(otherResultIndex), "$_self"); 5081b60f0d7SJeff Niu } 5091b60f0d7SJeff Niu } 5101b60f0d7SJeff Niu } 51131f40f60SJacques Pienaar } 51231f40f60SJacques Pienaar 5131b60f0d7SJeff Niu // Propagate inferredness until a fixed point. 5141e60e7adSMarkus Böck std::vector<ResultTypeInference *> worklist; 5151b60f0d7SJeff Niu for (ResultTypeInference &infer : inference) 5161b60f0d7SJeff Niu if (!infer.inferred) 5171b60f0d7SJeff Niu worklist.push_back(&infer); 5181b60f0d7SJeff Niu bool changed; 5191b60f0d7SJeff Niu do { 5201b60f0d7SJeff Niu changed = false; 5211e60e7adSMarkus Böck for (auto cur = worklist.begin(); cur != worklist.end();) { 5221b60f0d7SJeff Niu ResultTypeInference &infer = **cur; 5231e60e7adSMarkus Böck 5241e60e7adSMarkus Böck InferredResultType *iter = 5251e60e7adSMarkus Böck llvm::find_if(infer.sources, [&](const InferredResultType &source) { 5261b60f0d7SJeff Niu assert(InferredResultType::isResultIndex(source.getIndex())); 5271e60e7adSMarkus Böck return inference[InferredResultType::unmapResultIndex( 5281e60e7adSMarkus Böck source.getIndex())] 5291e60e7adSMarkus Böck .inferred; 5301e60e7adSMarkus Böck }); 5311e60e7adSMarkus Böck if (iter == infer.sources.end()) { 5321e60e7adSMarkus Böck ++cur; 5331e60e7adSMarkus Böck continue; 5341e60e7adSMarkus Böck } 5351e60e7adSMarkus Böck 5361b60f0d7SJeff Niu changed = true; 5371b60f0d7SJeff Niu infer.inferred = true; 5381b60f0d7SJeff Niu // Make this the only source for the result. This breaks any cycles. 5391e60e7adSMarkus Böck infer.sources.assign(1, *iter); 5401e60e7adSMarkus Böck cur = worklist.erase(cur); 5411b60f0d7SJeff Niu } 5421b60f0d7SJeff Niu } while (changed); 5431b60f0d7SJeff Niu 5441b60f0d7SJeff Niu allResultsHaveKnownTypes = worklist.empty(); 54531f40f60SJacques Pienaar 54631f40f60SJacques Pienaar // If the types could be computed, then add type inference trait. 5471b60f0d7SJeff Niu if (allResultsHaveKnownTypes) { 54894662ee0SRiver Riddle traits.push_back(Trait::create(inferTrait->getDefInit())); 5491b60f0d7SJeff Niu for (const ResultTypeInference &infer : inference) 5501b60f0d7SJeff Niu resultTypeMapping.push_back(infer.sources.front()); 5511b60f0d7SJeff Niu } 55231f40f60SJacques Pienaar } 55331f40f60SJacques Pienaar 55412d16de5SRahul Joshi void Operator::populateOpStructure() { 5552a463c36SJacques Pienaar auto &recordKeeper = def.getRecords(); 55631f40f60SJacques Pienaar auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint"); 55731f40f60SJacques Pienaar auto *attrClass = recordKeeper.getClass("Attr"); 5585e118f93SMehdi Amini auto *propertyClass = recordKeeper.getClass("Property"); 55931f40f60SJacques Pienaar auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr"); 56031f40f60SJacques Pienaar auto *opVarClass = recordKeeper.getClass("OpVariable"); 56195949a0dSAlex Zinenko numNativeAttributes = 0; 5622a463c36SJacques Pienaar 563e768b076SRahul Joshi const DagInit *argumentValues = def.getValueAsDag("arguments"); 564796ca609SLei Zhang unsigned numArgs = argumentValues->getNumArgs(); 565796ca609SLei Zhang 56631f40f60SJacques Pienaar // Mapping from name of to argument or result index. Arguments are indexed 56731f40f60SJacques Pienaar // to match getArg index, while the results are negatively indexed. 56831f40f60SJacques Pienaar llvm::StringMap<int> argumentsAndResultsIndex; 56931f40f60SJacques Pienaar 57095949a0dSAlex Zinenko // Handle operands and native attributes. 571796ca609SLei Zhang for (unsigned i = 0; i != numArgs; ++i) { 57231f40f60SJacques Pienaar auto *arg = argumentValues->getArg(i); 57366647a31SLei Zhang auto givenName = argumentValues->getArgNameStr(i); 57431f40f60SJacques Pienaar auto *argDefInit = dyn_cast<DefInit>(arg); 5752a463c36SJacques Pienaar if (!argDefInit) 5762a463c36SJacques Pienaar PrintFatalError(def.getLoc(), 577e0fc5038SLei Zhang Twine("undefined type for argument #") + Twine(i)); 578d256b9e8SRahul Joshi const Record *argDef = argDefInit->getDef(); 57920dca522SRiver Riddle if (argDef->isSubClassOf(opVarClass)) 58020dca522SRiver Riddle argDef = argDef->getValueAsDef("constraint"); 58195949a0dSAlex Zinenko 58295949a0dSAlex Zinenko if (argDef->isSubClassOf(typeConstraintClass)) { 583509cd739SJacques Pienaar operands.push_back( 58420dca522SRiver Riddle NamedTypeConstraint{givenName, TypeConstraint(argDef)}); 58595949a0dSAlex Zinenko } else if (argDef->isSubClassOf(attrClass)) { 58666647a31SLei Zhang if (givenName.empty()) 5872a463c36SJacques Pienaar PrintFatalError(argDef->getLoc(), "attributes must be named"); 58895949a0dSAlex Zinenko if (argDef->isSubClassOf(derivedAttrClass)) 58995949a0dSAlex Zinenko PrintFatalError(argDef->getLoc(), 590dde5bf23SJacques Pienaar "derived attributes not allowed in argument list"); 5919b034f0bSLei Zhang attributes.push_back({givenName, Attribute(argDef)}); 59295949a0dSAlex Zinenko ++numNativeAttributes; 5935e118f93SMehdi Amini } else if (argDef->isSubClassOf(propertyClass)) { 5945e118f93SMehdi Amini if (givenName.empty()) 5955e118f93SMehdi Amini PrintFatalError(argDef->getLoc(), "properties must be named"); 5965e118f93SMehdi Amini properties.push_back({givenName, Property(argDef)}); 59795949a0dSAlex Zinenko } else { 5985e118f93SMehdi Amini PrintFatalError(def.getLoc(), 5995e118f93SMehdi Amini "unexpected def type; only defs deriving " 6005e118f93SMehdi Amini "from TypeConstraint or Attr or Property are allowed"); 60195949a0dSAlex Zinenko } 60231f40f60SJacques Pienaar if (!givenName.empty()) 60331f40f60SJacques Pienaar argumentsAndResultsIndex[givenName] = i; 604dde5bf23SJacques Pienaar } 605dde5bf23SJacques Pienaar 606f8bbe5deSLei Zhang // Handle derived attributes. 607dde5bf23SJacques Pienaar for (const auto &val : def.getValues()) { 608dde5bf23SJacques Pienaar if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) { 609dde5bf23SJacques Pienaar if (!record->isSubClassOf(attrClass)) 610dde5bf23SJacques Pienaar continue; 611dde5bf23SJacques Pienaar if (!record->isSubClassOf(derivedAttrClass)) 612dde5bf23SJacques Pienaar PrintFatalError(def.getLoc(), 613dde5bf23SJacques Pienaar "unexpected Attr where only DerivedAttr is allowed"); 614dde5bf23SJacques Pienaar 615dde5bf23SJacques Pienaar if (record->getClasses().size() != 1) { 6162a463c36SJacques Pienaar PrintFatalError( 6172a463c36SJacques Pienaar def.getLoc(), 618dde5bf23SJacques Pienaar "unsupported attribute modelling, only single class expected"); 6192a463c36SJacques Pienaar } 620659192b1SRahul Joshi attributes.push_back({cast<StringInit>(val.getNameInit())->getValue(), 6219b034f0bSLei Zhang Attribute(cast<DefInit>(val.getValue()))}); 622dde5bf23SJacques Pienaar } 6232a463c36SJacques Pienaar } 6241df6ca50SLei Zhang 625796ca609SLei Zhang // Populate `arguments`. This must happen after we've finalized `operands` and 626796ca609SLei Zhang // `attributes` because we will put their elements' pointers in `arguments`. 627796ca609SLei Zhang // SmallVector may perform re-allocation under the hood when adding new 628796ca609SLei Zhang // elements. 6295e118f93SMehdi Amini int operandIndex = 0, attrIndex = 0, propIndex = 0; 630796ca609SLei Zhang for (unsigned i = 0; i != numArgs; ++i) { 631d256b9e8SRahul Joshi const Record *argDef = 632d256b9e8SRahul Joshi dyn_cast<DefInit>(argumentValues->getArg(i))->getDef(); 63320dca522SRiver Riddle if (argDef->isSubClassOf(opVarClass)) 63420dca522SRiver Riddle argDef = argDef->getValueAsDef("constraint"); 635796ca609SLei Zhang 636796ca609SLei Zhang if (argDef->isSubClassOf(typeConstraintClass)) { 63771b9d89dSJacques Pienaar attrOrOperandMapping.push_back( 63871b9d89dSJacques Pienaar {OperandOrAttribute::Kind::Operand, operandIndex}); 639796ca609SLei Zhang arguments.emplace_back(&operands[operandIndex++]); 6405e118f93SMehdi Amini } else if (argDef->isSubClassOf(attrClass)) { 64171b9d89dSJacques Pienaar attrOrOperandMapping.push_back( 64271b9d89dSJacques Pienaar {OperandOrAttribute::Kind::Attribute, attrIndex}); 643796ca609SLei Zhang arguments.emplace_back(&attributes[attrIndex++]); 6445e118f93SMehdi Amini } else { 6455e118f93SMehdi Amini assert(argDef->isSubClassOf(propertyClass)); 6465e118f93SMehdi Amini arguments.emplace_back(&properties[propIndex++]); 647796ca609SLei Zhang } 648796ca609SLei Zhang } 649796ca609SLei Zhang 650e0fc5038SLei Zhang auto *resultsDag = def.getValueAsDag("results"); 651e0fc5038SLei Zhang auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator()); 652e0fc5038SLei Zhang if (!outsOp || outsOp->getDef()->getName() != "outs") { 653e0fc5038SLei Zhang PrintFatalError(def.getLoc(), "'results' must have 'outs' directive"); 654e0fc5038SLei Zhang } 655e0fc5038SLei Zhang 656e0fc5038SLei Zhang // Handle results. 657e0fc5038SLei Zhang for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) { 658e0fc5038SLei Zhang auto name = resultsDag->getArgNameStr(i); 65920dca522SRiver Riddle auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i)); 66020dca522SRiver Riddle if (!resultInit) { 661e0fc5038SLei Zhang PrintFatalError(def.getLoc(), 662e0fc5038SLei Zhang Twine("undefined type for result #") + Twine(i)); 663e0fc5038SLei Zhang } 66420dca522SRiver Riddle auto *resultDef = resultInit->getDef(); 66520dca522SRiver Riddle if (resultDef->isSubClassOf(opVarClass)) 66620dca522SRiver Riddle resultDef = resultDef->getValueAsDef("constraint"); 6678f5fa566SLei Zhang results.push_back({name, TypeConstraint(resultDef)}); 66831f40f60SJacques Pienaar if (!name.empty()) 6691b60f0d7SJeff Niu argumentsAndResultsIndex[name] = InferredResultType::mapResultIndex(i); 6704e103a12SRiver Riddle 6714e103a12SRiver Riddle // We currently only support VariadicOfVariadic operands. 6724e103a12SRiver Riddle if (results.back().constraint.isVariadicOfVariadic()) { 6734e103a12SRiver Riddle PrintFatalError( 6744e103a12SRiver Riddle def.getLoc(), 6754e103a12SRiver Riddle "'VariadicOfVariadic' results are currently not supported"); 6764e103a12SRiver Riddle } 677e0fc5038SLei Zhang } 678e0fc5038SLei Zhang 679b1de971bSRiver Riddle // Handle successors 680b1de971bSRiver Riddle auto *successorsDag = def.getValueAsDag("successors"); 681b1de971bSRiver Riddle auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator()); 682b1de971bSRiver Riddle if (!successorsOp || successorsOp->getDef()->getName() != "successor") { 683b1de971bSRiver Riddle PrintFatalError(def.getLoc(), 684b1de971bSRiver Riddle "'successors' must have 'successor' directive"); 685b1de971bSRiver Riddle } 686b1de971bSRiver Riddle 687b1de971bSRiver Riddle for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) { 688b1de971bSRiver Riddle auto name = successorsDag->getArgNameStr(i); 689b1de971bSRiver Riddle auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i)); 690b1de971bSRiver Riddle if (!successorInit) { 691b1de971bSRiver Riddle PrintFatalError(def.getLoc(), 692b1de971bSRiver Riddle Twine("undefined kind for successor #") + Twine(i)); 693b1de971bSRiver Riddle } 694b1de971bSRiver Riddle Successor successor(successorInit->getDef()); 695b1de971bSRiver Riddle 696b1de971bSRiver Riddle // Only support variadic successors if it is the last one for now. 697b1de971bSRiver Riddle if (i != e - 1 && successor.isVariadic()) 698b1de971bSRiver Riddle PrintFatalError(def.getLoc(), "only the last successor can be variadic"); 699b1de971bSRiver Riddle successors.push_back({name, successor}); 700b1de971bSRiver Riddle } 701b1de971bSRiver Riddle 702b6d54a1bSJacques Pienaar // Create list of traits, skipping over duplicates: appending to lists in 703b6d54a1bSJacques Pienaar // tablegen is easy, making them unique less so, so dedupe here. 70431f40f60SJacques Pienaar if (auto *traitList = def.getValueAsListInit("traits")) { 705b6d54a1bSJacques Pienaar // This is uniquing based on pointers of the trait. 706659192b1SRahul Joshi SmallPtrSet<const Init *, 32> traitSet; 707b6d54a1bSJacques Pienaar traits.reserve(traitSet.size()); 7084b897de5SJacques Pienaar 70991e8a63cSChia-hung Duan // The declaration order of traits imply the verification order of traits. 71091e8a63cSChia-hung Duan // Some traits may require other traits to be verified first then they can 71191e8a63cSChia-hung Duan // do further verification based on those verified facts. If you see this 71291e8a63cSChia-hung Duan // error, fix the traits declaration order by checking the `dependentTraits` 71391e8a63cSChia-hung Duan // field. 714d256b9e8SRahul Joshi auto verifyTraitValidity = [&](const Record *trait) { 71591e8a63cSChia-hung Duan auto *dependentTraits = trait->getValueAsListInit("dependentTraits"); 71691e8a63cSChia-hung Duan for (auto *traitInit : *dependentTraits) 717ce14f7b1SKazu Hirata if (!traitSet.contains(traitInit)) 71891e8a63cSChia-hung Duan PrintFatalError( 71991e8a63cSChia-hung Duan def.getLoc(), 72091e8a63cSChia-hung Duan trait->getValueAsString("trait") + " requires " + 72191e8a63cSChia-hung Duan cast<DefInit>(traitInit)->getDef()->getValueAsString( 72291e8a63cSChia-hung Duan "trait") + 72391e8a63cSChia-hung Duan " to precede it in traits list"); 72491e8a63cSChia-hung Duan }; 72591e8a63cSChia-hung Duan 726659192b1SRahul Joshi std::function<void(const ListInit *)> insert; 727659192b1SRahul Joshi insert = [&](const ListInit *traitList) { 72831f40f60SJacques Pienaar for (auto *traitInit : *traitList) { 7294b897de5SJacques Pienaar auto *def = cast<DefInit>(traitInit)->getDef(); 730697a5036SSanjoy Das if (def->isSubClassOf("TraitList")) { 7314b897de5SJacques Pienaar insert(def->getValueAsListInit("traits")); 7324b897de5SJacques Pienaar continue; 7334b897de5SJacques Pienaar } 73491e8a63cSChia-hung Duan 73583a635c0SRiver Riddle // Ignore duplicates. 73683a635c0SRiver Riddle if (!traitSet.insert(traitInit).second) 73783a635c0SRiver Riddle continue; 73883a635c0SRiver Riddle 73983a635c0SRiver Riddle // If this is an interface with base classes, add the bases to the 74083a635c0SRiver Riddle // trait list. 74183a635c0SRiver Riddle if (def->isSubClassOf("Interface")) 74283a635c0SRiver Riddle insert(def->getValueAsListInit("baseInterfaces")); 74383a635c0SRiver Riddle 74491e8a63cSChia-hung Duan // Verify if the trait has all the dependent traits declared before 74591e8a63cSChia-hung Duan // itself. 74691e8a63cSChia-hung Duan verifyTraitValidity(def); 74794662ee0SRiver Riddle traits.push_back(Trait::create(traitInit)); 748b6d54a1bSJacques Pienaar } 7494b897de5SJacques Pienaar }; 7504b897de5SJacques Pienaar insert(traitList); 751b6d54a1bSJacques Pienaar } 752d4c8c8deSLei Zhang 75331f40f60SJacques Pienaar populateTypeInferenceInfo(argumentsAndResultsIndex); 75431f40f60SJacques Pienaar 755d4c8c8deSLei Zhang // Handle regions 7563650df50SLei Zhang auto *regionsDag = def.getValueAsDag("regions"); 7573650df50SLei Zhang auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator()); 7583650df50SLei Zhang if (!regionsOp || regionsOp->getDef()->getName() != "region") { 7593650df50SLei Zhang PrintFatalError(def.getLoc(), "'regions' must have 'region' directive"); 7603650df50SLei Zhang } 7613650df50SLei Zhang 7623650df50SLei Zhang for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) { 7633650df50SLei Zhang auto name = regionsDag->getArgNameStr(i); 7643650df50SLei Zhang auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i)); 7653650df50SLei Zhang if (!regionInit) { 7663650df50SLei Zhang PrintFatalError(def.getLoc(), 7673650df50SLei Zhang Twine("undefined kind for region #") + Twine(i)); 7683650df50SLei Zhang } 7690359b86dSRiver Riddle Region region(regionInit->getDef()); 7700359b86dSRiver Riddle if (region.isVariadic()) { 7710359b86dSRiver Riddle // Only support variadic regions if it is the last one for now. 7720359b86dSRiver Riddle if (i != e - 1) 7730359b86dSRiver Riddle PrintFatalError(def.getLoc(), "only the last region can be variadic"); 7740359b86dSRiver Riddle if (name.empty()) 7750359b86dSRiver Riddle PrintFatalError(def.getLoc(), "variadic regions must be named"); 7760359b86dSRiver Riddle } 7770359b86dSRiver Riddle 7780359b86dSRiver Riddle regions.push_back({name, region}); 7793650df50SLei Zhang } 780796ca609SLei Zhang 78120741773SRiver Riddle // Populate the builders. 782659192b1SRahul Joshi auto *builderList = dyn_cast_or_null<ListInit>(def.getValueInit("builders")); 78320741773SRiver Riddle if (builderList && !builderList->empty()) { 784659192b1SRahul Joshi for (const Init *init : builderList->getValues()) 785659192b1SRahul Joshi builders.emplace_back(cast<DefInit>(init)->getDef(), def.getLoc()); 78620741773SRiver Riddle } else if (skipDefaultBuilders()) { 78720741773SRiver Riddle PrintFatalError( 78820741773SRiver Riddle def.getLoc(), 78920741773SRiver Riddle "default builders are skipped and no custom builders provided"); 79020741773SRiver Riddle } 79120741773SRiver Riddle 792796ca609SLei Zhang LLVM_DEBUG(print(llvm::dbgs())); 7932a463c36SJacques Pienaar } 7948f249438SJacques Pienaar 7951b60f0d7SJeff Niu const InferredResultType &Operator::getInferredResultType(int index) const { 79631f40f60SJacques Pienaar assert(allResultTypesKnown()); 79731f40f60SJacques Pienaar return resultTypeMapping[index]; 79831f40f60SJacques Pienaar } 79931f40f60SJacques Pienaar 8006842ec42SRiver Riddle ArrayRef<SMLoc> Operator::getLoc() const { return def.getLoc(); } 8012927297aSSmit Hinsu 80212d16de5SRahul Joshi bool Operator::hasDescription() const { 803e4906862SAlex Rice return !getDescription().trim().empty(); 804a280e399SJacques Pienaar } 805a280e399SJacques Pienaar 80612d16de5SRahul Joshi StringRef Operator::getDescription() const { 807a280e399SJacques Pienaar return def.getValueAsString("description"); 808a280e399SJacques Pienaar } 809a280e399SJacques Pienaar 810e4906862SAlex Rice bool Operator::hasSummary() const { return !getSummary().trim().empty(); } 811a280e399SJacques Pienaar 81212d16de5SRahul Joshi StringRef Operator::getSummary() const { 813a280e399SJacques Pienaar return def.getValueAsString("summary"); 814a280e399SJacques Pienaar } 815796ca609SLei Zhang 81612d16de5SRahul Joshi bool Operator::hasAssemblyFormat() const { 8171a083f02SRiver Riddle auto *valueInit = def.getValueInit("assemblyFormat"); 818659192b1SRahul Joshi return isa<StringInit>(valueInit); 8191a083f02SRiver Riddle } 8201a083f02SRiver Riddle 82112d16de5SRahul Joshi StringRef Operator::getAssemblyFormat() const { 822659192b1SRahul Joshi return TypeSwitch<const Init *, StringRef>(def.getValueInit("assemblyFormat")) 823659192b1SRahul Joshi .Case<StringInit>([&](auto *init) { return init->getValue(); }); 8241a083f02SRiver Riddle } 8251a083f02SRiver Riddle 82612d16de5SRahul Joshi void Operator::print(llvm::raw_ostream &os) const { 827796ca609SLei Zhang os << "op '" << getOperationName() << "'\n"; 828796ca609SLei Zhang for (Argument arg : arguments) { 82968f58812STres Popp if (auto *attr = llvm::dyn_cast_if_present<NamedAttribute *>(arg)) 830796ca609SLei Zhang os << "[attribute] " << attr->name << '\n'; 831796ca609SLei Zhang else 83226d513d1SKazu Hirata os << "[operand] " << cast<NamedTypeConstraint *>(arg)->name << '\n'; 833796ca609SLei Zhang } 834796ca609SLei Zhang } 83520dca522SRiver Riddle 836659192b1SRahul Joshi auto Operator::VariableDecoratorIterator::unwrap(const Init *init) 83720dca522SRiver Riddle -> VariableDecorator { 838659192b1SRahul Joshi return VariableDecorator(cast<DefInit>(init)->getDef()); 83920dca522SRiver Riddle } 84071b9d89dSJacques Pienaar 84112d16de5SRahul Joshi auto Operator::getArgToOperandOrAttribute(int index) const 84271b9d89dSJacques Pienaar -> OperandOrAttribute { 84371b9d89dSJacques Pienaar return attrOrOperandMapping[index]; 84471b9d89dSJacques Pienaar } 8456a994233SJacques Pienaar 846b74192b7SRiver Riddle std::string Operator::getGetterName(StringRef name) const { 847b74192b7SRiver Riddle return "get" + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true); 8486a994233SJacques Pienaar } 8496a994233SJacques Pienaar 850b74192b7SRiver Riddle std::string Operator::getSetterName(StringRef name) const { 851b74192b7SRiver Riddle return "set" + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true); 8526a994233SJacques Pienaar } 85315511c2eSJeff Niu 85415511c2eSJeff Niu std::string Operator::getRemoverName(StringRef name) const { 85515511c2eSJeff Niu return "remove" + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true); 85615511c2eSJeff Niu } 857bbfa7ef1SMarkus Böck 858bbfa7ef1SMarkus Böck bool Operator::hasFolder() const { return def.getValueAsBit("hasFolder"); } 859cf0e8dcaSMatteo Franciolini 860cf0e8dcaSMatteo Franciolini bool Operator::useCustomPropertiesEncoding() const { 861cf0e8dcaSMatteo Franciolini return def.getValueAsBit("useCustomPropertiesEncoding"); 862cf0e8dcaSMatteo Franciolini } 863