1cde4d5a6SJacques Pienaar //===- Pattern.cpp - Pattern wrapper class --------------------------------===// 2eb753f4aSLei Zhang // 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 6eb753f4aSLei Zhang // 756222a06SMehdi Amini //===----------------------------------------------------------------------===// 8eb753f4aSLei Zhang // 9eb753f4aSLei Zhang // Pattern wrapper class to simplify using TableGen Record defining a MLIR 10eb753f4aSLei Zhang // Pattern. 11eb753f4aSLei Zhang // 12eb753f4aSLei Zhang //===----------------------------------------------------------------------===// 13eb753f4aSLei Zhang 141fc096afSMehdi Amini #include <utility> 151fc096afSMehdi Amini 16eb753f4aSLei Zhang #include "mlir/TableGen/Pattern.h" 17b12a7c88SMehdi Amini #include "llvm/ADT/StringExtras.h" 18eb753f4aSLei Zhang #include "llvm/ADT/Twine.h" 191358df19SLei Zhang #include "llvm/Support/Debug.h" 2004b6d2f3SLei Zhang #include "llvm/Support/FormatVariadic.h" 218f5fa566SLei Zhang #include "llvm/TableGen/Error.h" 22eb753f4aSLei Zhang #include "llvm/TableGen/Record.h" 23eb753f4aSLei Zhang 241358df19SLei Zhang #define DEBUG_TYPE "mlir-tblgen-pattern" 251358df19SLei Zhang 26eb753f4aSLei Zhang using namespace mlir; 2712d16de5SRahul Joshi using namespace tblgen; 28eb753f4aSLei Zhang 29659192b1SRahul Joshi using llvm::DagInit; 30659192b1SRahul Joshi using llvm::dbgs; 31659192b1SRahul Joshi using llvm::DefInit; 320ea6154bSJacques Pienaar using llvm::formatv; 33659192b1SRahul Joshi using llvm::IntInit; 34659192b1SRahul Joshi using llvm::Record; 35eb753f4aSLei Zhang 36ac68637bSLei Zhang //===----------------------------------------------------------------------===// 37ac68637bSLei Zhang // DagLeaf 38ac68637bSLei Zhang //===----------------------------------------------------------------------===// 39ac68637bSLei Zhang 4012d16de5SRahul Joshi bool DagLeaf::isUnspecified() const { 41ae002f8bSKazu Hirata return isa_and_nonnull<llvm::UnsetInit>(def); 42e0774c00SLei Zhang } 43e0774c00SLei Zhang 4412d16de5SRahul Joshi bool DagLeaf::isOperandMatcher() const { 45e0774c00SLei Zhang // Operand matchers specify a type constraint. 46b9e38a79SLei Zhang return isSubClassOf("TypeConstraint"); 47e0774c00SLei Zhang } 48e0774c00SLei Zhang 4912d16de5SRahul Joshi bool DagLeaf::isAttrMatcher() const { 50c52a8127SFeng Liu // Attribute matchers specify an attribute constraint. 51b9e38a79SLei Zhang return isSubClassOf("AttrConstraint"); 52e0774c00SLei Zhang } 53e0774c00SLei Zhang 5412d16de5SRahul Joshi bool DagLeaf::isNativeCodeCall() const { 55d0e2019dSLei Zhang return isSubClassOf("NativeCodeCall"); 56e0774c00SLei Zhang } 57e0774c00SLei Zhang 5812d16de5SRahul Joshi bool DagLeaf::isConstantAttr() const { return isSubClassOf("ConstantAttr"); } 59b9e38a79SLei Zhang 6012d16de5SRahul Joshi bool DagLeaf::isEnumAttrCase() const { 619dd182e0SLei Zhang return isSubClassOf("EnumAttrCaseInfo"); 62e0774c00SLei Zhang } 63e0774c00SLei Zhang 64cb8c30d3SMogball bool DagLeaf::isStringAttr() const { return isa<llvm::StringInit>(def); } 65d6b32e39SJacques Pienaar 6612d16de5SRahul Joshi Constraint DagLeaf::getAsConstraint() const { 678f5fa566SLei Zhang assert((isOperandMatcher() || isAttrMatcher()) && 688f5fa566SLei Zhang "the DAG leaf must be operand or attribute"); 69659192b1SRahul Joshi return Constraint(cast<DefInit>(def)->getDef()); 70e0774c00SLei Zhang } 71e0774c00SLei Zhang 7212d16de5SRahul Joshi ConstantAttr DagLeaf::getAsConstantAttr() const { 73e0774c00SLei Zhang assert(isConstantAttr() && "the DAG leaf must be constant attribute"); 74659192b1SRahul Joshi return ConstantAttr(cast<DefInit>(def)); 75e0774c00SLei Zhang } 76e0774c00SLei Zhang 7712d16de5SRahul Joshi EnumAttrCase DagLeaf::getAsEnumAttrCase() const { 78b9e38a79SLei Zhang assert(isEnumAttrCase() && "the DAG leaf must be an enum attribute case"); 79659192b1SRahul Joshi return EnumAttrCase(cast<DefInit>(def)); 80b9e38a79SLei Zhang } 81b9e38a79SLei Zhang 8212d16de5SRahul Joshi std::string DagLeaf::getConditionTemplate() const { 838f5fa566SLei Zhang return getAsConstraint().getConditionTemplate(); 84e0774c00SLei Zhang } 85e0774c00SLei Zhang 86659192b1SRahul Joshi StringRef DagLeaf::getNativeCodeTemplate() const { 87d0e2019dSLei Zhang assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall"); 88659192b1SRahul Joshi return cast<DefInit>(def)->getDef()->getValueAsString("expression"); 89eb753f4aSLei Zhang } 90eb753f4aSLei Zhang 91d7314b3cSChia-hung Duan int DagLeaf::getNumReturnsOfNativeCode() const { 92d7314b3cSChia-hung Duan assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall"); 93659192b1SRahul Joshi return cast<DefInit>(def)->getDef()->getValueAsInt("numReturns"); 94d7314b3cSChia-hung Duan } 95d7314b3cSChia-hung Duan 9612d16de5SRahul Joshi std::string DagLeaf::getStringAttr() const { 97d6b32e39SJacques Pienaar assert(isStringAttr() && "the DAG leaf must be string attribute"); 98d6b32e39SJacques Pienaar return def->getAsUnquotedString(); 99d6b32e39SJacques Pienaar } 10012d16de5SRahul Joshi bool DagLeaf::isSubClassOf(StringRef superclass) const { 101659192b1SRahul Joshi if (auto *defInit = dyn_cast_or_null<DefInit>(def)) 102b9e38a79SLei Zhang return defInit->getDef()->isSubClassOf(superclass); 103b9e38a79SLei Zhang return false; 104b9e38a79SLei Zhang } 105b9e38a79SLei Zhang 10612d16de5SRahul Joshi void DagLeaf::print(raw_ostream &os) const { 1071358df19SLei Zhang if (def) 1081358df19SLei Zhang def->print(os); 1091358df19SLei Zhang } 1101358df19SLei Zhang 111ac68637bSLei Zhang //===----------------------------------------------------------------------===// 112ac68637bSLei Zhang // DagNode 113ac68637bSLei Zhang //===----------------------------------------------------------------------===// 114ac68637bSLei Zhang 11512d16de5SRahul Joshi bool DagNode::isNativeCodeCall() const { 116659192b1SRahul Joshi if (auto *defInit = dyn_cast_or_null<DefInit>(node->getOperator())) 117d0e2019dSLei Zhang return defInit->getDef()->isSubClassOf("NativeCodeCall"); 118c52a8127SFeng Liu return false; 119c52a8127SFeng Liu } 120c52a8127SFeng Liu 12112d16de5SRahul Joshi bool DagNode::isOperation() const { 122cb8c30d3SMogball return !isNativeCodeCall() && !isReplaceWithValue() && 12308d7377bSLogan Chien !isLocationDirective() && !isReturnTypeDirective() && !isEither() && 12408d7377bSLogan Chien !isVariadic(); 125647f8cabSRiver Riddle } 126647f8cabSRiver Riddle 127659192b1SRahul Joshi StringRef DagNode::getNativeCodeTemplate() const { 128d0e2019dSLei Zhang assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall"); 129659192b1SRahul Joshi return cast<DefInit>(node->getOperator()) 130c52a8127SFeng Liu ->getDef() 131d0e2019dSLei Zhang ->getValueAsString("expression"); 132c52a8127SFeng Liu } 133c52a8127SFeng Liu 134d7314b3cSChia-hung Duan int DagNode::getNumReturnsOfNativeCode() const { 135d7314b3cSChia-hung Duan assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall"); 136659192b1SRahul Joshi return cast<DefInit>(node->getOperator()) 137d7314b3cSChia-hung Duan ->getDef() 138d7314b3cSChia-hung Duan ->getValueAsInt("numReturns"); 139d7314b3cSChia-hung Duan } 140d7314b3cSChia-hung Duan 141659192b1SRahul Joshi StringRef DagNode::getSymbol() const { return node->getNameStr(); } 142388fb375SJacques Pienaar 14312d16de5SRahul Joshi Operator &DagNode::getDialectOp(RecordOperatorMap *mapper) const { 144659192b1SRahul Joshi const Record *opDef = cast<DefInit>(node->getOperator())->getDef(); 1455e1e6a68SKazu Hirata auto [it, inserted] = mapper->try_emplace(opDef); 1465e1e6a68SKazu Hirata if (inserted) 1475e1e6a68SKazu Hirata it->second = std::make_unique<Operator>(opDef); 1482dc6d205SLei Zhang return *it->second; 149eb753f4aSLei Zhang } 150eb753f4aSLei Zhang 15112d16de5SRahul Joshi int DagNode::getNumOps() const { 1522d99c815SChia-hung Duan // We want to get number of operations recursively involved in the DAG tree. 1532d99c815SChia-hung Duan // All other directives should be excluded. 1542d99c815SChia-hung Duan int count = isOperation() ? 1 : 0; 1552fe8ae4fSJacques Pienaar for (int i = 0, e = getNumArgs(); i != e; ++i) { 156eb753f4aSLei Zhang if (auto child = getArgAsNestedDag(i)) 157eb753f4aSLei Zhang count += child.getNumOps(); 158eb753f4aSLei Zhang } 159eb753f4aSLei Zhang return count; 160eb753f4aSLei Zhang } 161eb753f4aSLei Zhang 16212d16de5SRahul Joshi int DagNode::getNumArgs() const { return node->getNumArgs(); } 163eb753f4aSLei Zhang 16412d16de5SRahul Joshi bool DagNode::isNestedDagArg(unsigned index) const { 165659192b1SRahul Joshi return isa<DagInit>(node->getArg(index)); 166eb753f4aSLei Zhang } 167eb753f4aSLei Zhang 16812d16de5SRahul Joshi DagNode DagNode::getArgAsNestedDag(unsigned index) const { 169659192b1SRahul Joshi return DagNode(dyn_cast_or_null<DagInit>(node->getArg(index))); 170eb753f4aSLei Zhang } 171eb753f4aSLei Zhang 17212d16de5SRahul Joshi DagLeaf DagNode::getArgAsLeaf(unsigned index) const { 173e0774c00SLei Zhang assert(!isNestedDagArg(index)); 174e0774c00SLei Zhang return DagLeaf(node->getArg(index)); 175eb753f4aSLei Zhang } 176eb753f4aSLei Zhang 17712d16de5SRahul Joshi StringRef DagNode::getArgName(unsigned index) const { 178eb753f4aSLei Zhang return node->getArgNameStr(index); 179eb753f4aSLei Zhang } 180eb753f4aSLei Zhang 18112d16de5SRahul Joshi bool DagNode::isReplaceWithValue() const { 182659192b1SRahul Joshi auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef(); 183eb753f4aSLei Zhang return dagOpDef->getName() == "replaceWithValue"; 184eb753f4aSLei Zhang } 185eb753f4aSLei Zhang 18612d16de5SRahul Joshi bool DagNode::isLocationDirective() const { 187659192b1SRahul Joshi auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef(); 1883f7439b2SJacques Pienaar return dagOpDef->getName() == "location"; 1893f7439b2SJacques Pienaar } 1903f7439b2SJacques Pienaar 191cb8c30d3SMogball bool DagNode::isReturnTypeDirective() const { 192659192b1SRahul Joshi auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef(); 193cb8c30d3SMogball return dagOpDef->getName() == "returnType"; 194cb8c30d3SMogball } 195cb8c30d3SMogball 1962d99c815SChia-hung Duan bool DagNode::isEither() const { 197659192b1SRahul Joshi auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef(); 1982d99c815SChia-hung Duan return dagOpDef->getName() == "either"; 1992d99c815SChia-hung Duan } 2002d99c815SChia-hung Duan 20108d7377bSLogan Chien bool DagNode::isVariadic() const { 202659192b1SRahul Joshi auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef(); 20308d7377bSLogan Chien return dagOpDef->getName() == "variadic"; 20408d7377bSLogan Chien } 20508d7377bSLogan Chien 20612d16de5SRahul Joshi void DagNode::print(raw_ostream &os) const { 2071358df19SLei Zhang if (node) 2081358df19SLei Zhang node->print(os); 2091358df19SLei Zhang } 2101358df19SLei Zhang 211ac68637bSLei Zhang //===----------------------------------------------------------------------===// 212ac68637bSLei Zhang // SymbolInfoMap 213ac68637bSLei Zhang //===----------------------------------------------------------------------===// 214ac68637bSLei Zhang 21512d16de5SRahul Joshi StringRef SymbolInfoMap::getValuePackName(StringRef symbol, int *index) { 216ac68637bSLei Zhang int idx = -1; 2179fa59e76SBenjamin Kramer auto [name, indexStr] = symbol.rsplit("__"); 218ac68637bSLei Zhang 219ac68637bSLei Zhang if (indexStr.consumeInteger(10, idx)) { 220ac68637bSLei Zhang // The second part is not an index; we return the whole symbol as-is. 221ac68637bSLei Zhang return symbol; 222eb753f4aSLei Zhang } 223ac68637bSLei Zhang if (index) { 224ac68637bSLei Zhang *index = idx; 225ac68637bSLei Zhang } 226ac68637bSLei Zhang return name; 227ac68637bSLei Zhang } 228ac68637bSLei Zhang 2293cfe412eSFangrui Song SymbolInfoMap::SymbolInfo::SymbolInfo( 2303cfe412eSFangrui Song const Operator *op, SymbolInfo::Kind kind, 2313cfe412eSFangrui Song std::optional<DagAndConstant> dagAndConstant) 2321f97219aSMehdi Amini : op(op), kind(kind), dagAndConstant(dagAndConstant) {} 233ac68637bSLei Zhang 23412d16de5SRahul Joshi int SymbolInfoMap::SymbolInfo::getStaticValueCount() const { 235ac68637bSLei Zhang switch (kind) { 236ac68637bSLei Zhang case Kind::Attr: 237ac68637bSLei Zhang case Kind::Operand: 238ac68637bSLei Zhang case Kind::Value: 239ac68637bSLei Zhang return 1; 240ac68637bSLei Zhang case Kind::Result: 241ac68637bSLei Zhang return op->getNumResults(); 242d7314b3cSChia-hung Duan case Kind::MultipleValues: 243d7314b3cSChia-hung Duan return getSize(); 244ac68637bSLei Zhang } 24512ff145eSjpienaar llvm_unreachable("unknown kind"); 246ac68637bSLei Zhang } 247ac68637bSLei Zhang 248008c0ea6Srdzhabarov std::string SymbolInfoMap::SymbolInfo::getVarName(StringRef name) const { 249064a08cdSKazu Hirata return alternativeName ? *alternativeName : name.str(); 250008c0ea6Srdzhabarov } 251008c0ea6Srdzhabarov 252bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getVarTypeStr(StringRef name) const { 253659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "getVarTypeStr for '" << name << "': "); 254ac68637bSLei Zhang switch (kind) { 255ac68637bSLei Zhang case Kind::Attr: { 256bb250606SChia-hung Duan if (op) 257*26d513d1SKazu Hirata return cast<NamedAttribute *>(op->getArg(getArgIndex())) 258bb250606SChia-hung Duan ->attr.getStorageType() 259bb250606SChia-hung Duan .str(); 2602bf423b0SRob Suderman // TODO(suderman): Use a more exact type when available. 2618652fc84SMarkus Böck return "::mlir::Attribute"; 2622bf423b0SRob Suderman } 26331cfee60SLei Zhang case Kind::Operand: { 26431cfee60SLei Zhang // Use operand range for captured operands (to support potential variadic 26531cfee60SLei Zhang // operands). 266bb250606SChia-hung Duan return "::mlir::Operation::operand_range"; 26731cfee60SLei Zhang } 268ac68637bSLei Zhang case Kind::Value: { 269bb250606SChia-hung Duan return "::mlir::Value"; 270ac68637bSLei Zhang } 271d7314b3cSChia-hung Duan case Kind::MultipleValues: { 272bb250606SChia-hung Duan return "::mlir::ValueRange"; 273d7314b3cSChia-hung Duan } 274ac68637bSLei Zhang case Kind::Result: { 27531cfee60SLei Zhang // Use the op itself for captured results. 276bb250606SChia-hung Duan return op->getQualCppClassName(); 277ac68637bSLei Zhang } 278ac68637bSLei Zhang } 27912ff145eSjpienaar llvm_unreachable("unknown kind"); 280ac68637bSLei Zhang } 281ac68637bSLei Zhang 282bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getVarDecl(StringRef name) const { 283659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "getVarDecl for '" << name << "': "); 284bb250606SChia-hung Duan std::string varInit = kind == Kind::Operand ? "(op0->getOperands())" : ""; 285bb250606SChia-hung Duan return std::string( 286bb250606SChia-hung Duan formatv("{0} {1}{2};\n", getVarTypeStr(name), getVarName(name), varInit)); 287bb250606SChia-hung Duan } 288bb250606SChia-hung Duan 289bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getArgDecl(StringRef name) const { 290659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "getArgDecl for '" << name << "': "); 291bb250606SChia-hung Duan return std::string( 292bb250606SChia-hung Duan formatv("{0} &{1}", getVarTypeStr(name), getVarName(name))); 293bb250606SChia-hung Duan } 294bb250606SChia-hung Duan 29512d16de5SRahul Joshi std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse( 29631cfee60SLei Zhang StringRef name, int index, const char *fmt, const char *separator) const { 297659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "getValueAndRangeUse for '" << name << "': "); 29831cfee60SLei Zhang switch (kind) { 29931cfee60SLei Zhang case Kind::Attr: { 30031cfee60SLei Zhang assert(index < 0); 3011358df19SLei Zhang auto repl = formatv(fmt, name); 302659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (Attr)\n"); 303adcd0268SBenjamin Kramer return std::string(repl); 30431cfee60SLei Zhang } 30531cfee60SLei Zhang case Kind::Operand: { 30631cfee60SLei Zhang assert(index < 0); 307*26d513d1SKazu Hirata auto *operand = cast<NamedTypeConstraint *>(op->getArg(getArgIndex())); 30808d7377bSLogan Chien // If this operand is variadic and this SymbolInfo doesn't have a range 30908d7377bSLogan Chien // index, then return the full variadic operand_range. Otherwise, return 31008d7377bSLogan Chien // the value itself. 31108d7377bSLogan Chien if (operand->isVariableLength() && !getVariadicSubIndex().has_value()) { 3121358df19SLei Zhang auto repl = formatv(fmt, name); 313659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (VariadicOperand)\n"); 314adcd0268SBenjamin Kramer return std::string(repl); 31531cfee60SLei Zhang } 3161358df19SLei Zhang auto repl = formatv(fmt, formatv("(*{0}.begin())", name)); 317659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (SingleOperand)\n"); 318adcd0268SBenjamin Kramer return std::string(repl); 31931cfee60SLei Zhang } 32031cfee60SLei Zhang case Kind::Result: { 32131cfee60SLei Zhang // If `index` is greater than zero, then we are referencing a specific 32231cfee60SLei Zhang // result of a multi-result op. The result can still be variadic. 32331cfee60SLei Zhang if (index >= 0) { 324adcd0268SBenjamin Kramer std::string v = 325adcd0268SBenjamin Kramer std::string(formatv("{0}.getODSResults({1})", name, index)); 32631cfee60SLei Zhang if (!op->getResult(index).isVariadic()) 327adcd0268SBenjamin Kramer v = std::string(formatv("(*{0}.begin())", v)); 3281358df19SLei Zhang auto repl = formatv(fmt, v); 329659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (SingleResult)\n"); 330adcd0268SBenjamin Kramer return std::string(repl); 33131cfee60SLei Zhang } 33231cfee60SLei Zhang 33323d21af6SLei Zhang // If this op has no result at all but still we bind a symbol to it, it 33423d21af6SLei Zhang // means we want to capture the op itself. 33523d21af6SLei Zhang if (op->getNumResults() == 0) { 336659192b1SRahul Joshi LLVM_DEBUG(dbgs() << name << " (Op)\n"); 3377b196f1bSMarkus Böck return formatv(fmt, name); 33823d21af6SLei Zhang } 33923d21af6SLei Zhang 34031cfee60SLei Zhang // We are referencing all results of the multi-result op. A specific result 34131cfee60SLei Zhang // can either be a value or a range. Then join them with `separator`. 34231cfee60SLei Zhang SmallVector<std::string, 4> values; 34331cfee60SLei Zhang values.reserve(op->getNumResults()); 34431cfee60SLei Zhang 34531cfee60SLei Zhang for (int i = 0, e = op->getNumResults(); i < e; ++i) { 346adcd0268SBenjamin Kramer std::string v = std::string(formatv("{0}.getODSResults({1})", name, i)); 34731cfee60SLei Zhang if (!op->getResult(i).isVariadic()) { 348adcd0268SBenjamin Kramer v = std::string(formatv("(*{0}.begin())", v)); 34931cfee60SLei Zhang } 350adcd0268SBenjamin Kramer values.push_back(std::string(formatv(fmt, v))); 35131cfee60SLei Zhang } 3521358df19SLei Zhang auto repl = llvm::join(values, separator); 353659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (VariadicResult)\n"); 3541358df19SLei Zhang return repl; 35531cfee60SLei Zhang } 35631cfee60SLei Zhang case Kind::Value: { 35731cfee60SLei Zhang assert(index < 0); 35831cfee60SLei Zhang assert(op == nullptr); 3591358df19SLei Zhang auto repl = formatv(fmt, name); 360659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (Value)\n"); 361adcd0268SBenjamin Kramer return std::string(repl); 36231cfee60SLei Zhang } 363d7314b3cSChia-hung Duan case Kind::MultipleValues: { 364d7314b3cSChia-hung Duan assert(op == nullptr); 365d7314b3cSChia-hung Duan assert(index < getSize()); 366d7314b3cSChia-hung Duan if (index >= 0) { 367d7314b3cSChia-hung Duan std::string repl = 368d7314b3cSChia-hung Duan formatv(fmt, std::string(formatv("{0}[{1}]", name, index))); 369659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n"); 370d7314b3cSChia-hung Duan return repl; 371d7314b3cSChia-hung Duan } 372d7314b3cSChia-hung Duan // If it doesn't specify certain element, unpack them all. 373d7314b3cSChia-hung Duan auto repl = 374d7314b3cSChia-hung Duan formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name))); 375659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n"); 376d7314b3cSChia-hung Duan return std::string(repl); 377d7314b3cSChia-hung Duan } 37831cfee60SLei Zhang } 37994298ceaSLei Zhang llvm_unreachable("unknown kind"); 38031cfee60SLei Zhang } 38131cfee60SLei Zhang 38212d16de5SRahul Joshi std::string SymbolInfoMap::SymbolInfo::getAllRangeUse( 38331cfee60SLei Zhang StringRef name, int index, const char *fmt, const char *separator) const { 384659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "getAllRangeUse for '" << name << "': "); 385ac68637bSLei Zhang switch (kind) { 386ac68637bSLei Zhang case Kind::Attr: 387ac68637bSLei Zhang case Kind::Operand: { 388ac68637bSLei Zhang assert(index < 0 && "only allowed for symbol bound to result"); 3891358df19SLei Zhang auto repl = formatv(fmt, name); 390659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (Operand/Attr)\n"); 391adcd0268SBenjamin Kramer return std::string(repl); 392ac68637bSLei Zhang } 393ac68637bSLei Zhang case Kind::Result: { 394ac68637bSLei Zhang if (index >= 0) { 3951358df19SLei Zhang auto repl = formatv(fmt, formatv("{0}.getODSResults({1})", name, index)); 396659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (SingleResult)\n"); 397adcd0268SBenjamin Kramer return std::string(repl); 398ac68637bSLei Zhang } 399ac68637bSLei Zhang 40031cfee60SLei Zhang // We are referencing all results of the multi-result op. Each result should 40131cfee60SLei Zhang // have a value range, and then join them with `separator`. 402ac68637bSLei Zhang SmallVector<std::string, 4> values; 40331cfee60SLei Zhang values.reserve(op->getNumResults()); 40431cfee60SLei Zhang 405ac68637bSLei Zhang for (int i = 0, e = op->getNumResults(); i < e; ++i) { 406adcd0268SBenjamin Kramer values.push_back(std::string( 407adcd0268SBenjamin Kramer formatv(fmt, formatv("{0}.getODSResults({1})", name, i)))); 408ac68637bSLei Zhang } 4091358df19SLei Zhang auto repl = llvm::join(values, separator); 410659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (VariadicResult)\n"); 4111358df19SLei Zhang return repl; 412ac68637bSLei Zhang } 413ac68637bSLei Zhang case Kind::Value: { 414ac68637bSLei Zhang assert(index < 0 && "only allowed for symbol bound to result"); 415ac68637bSLei Zhang assert(op == nullptr); 41660f1d263SLei Zhang auto repl = formatv(fmt, formatv("{{{0}}", name)); 417659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (Value)\n"); 418adcd0268SBenjamin Kramer return std::string(repl); 419ac68637bSLei Zhang } 420d7314b3cSChia-hung Duan case Kind::MultipleValues: { 421d7314b3cSChia-hung Duan assert(op == nullptr); 422d7314b3cSChia-hung Duan assert(index < getSize()); 423d7314b3cSChia-hung Duan if (index >= 0) { 424d7314b3cSChia-hung Duan std::string repl = 425d7314b3cSChia-hung Duan formatv(fmt, std::string(formatv("{0}[{1}]", name, index))); 426659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n"); 427d7314b3cSChia-hung Duan return repl; 428d7314b3cSChia-hung Duan } 429d7314b3cSChia-hung Duan auto repl = 430d7314b3cSChia-hung Duan formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name))); 431659192b1SRahul Joshi LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n"); 432d7314b3cSChia-hung Duan return std::string(repl); 433d7314b3cSChia-hung Duan } 434ac68637bSLei Zhang } 43512ff145eSjpienaar llvm_unreachable("unknown kind"); 436ac68637bSLei Zhang } 437ac68637bSLei Zhang 438b4001ae8SChia-hung Duan bool SymbolInfoMap::bindOpArgument(DagNode node, StringRef symbol, 43908d7377bSLogan Chien const Operator &op, int argIndex, 44008d7377bSLogan Chien std::optional<int> variadicSubIndex) { 441ac68637bSLei Zhang StringRef name = getValuePackName(symbol); 442ac68637bSLei Zhang if (name != symbol) { 443ac68637bSLei Zhang auto error = formatv( 444ac68637bSLei Zhang "symbol '{0}' with trailing index cannot bind to op argument", symbol); 445ac68637bSLei Zhang PrintFatalError(loc, error); 446ac68637bSLei Zhang } 447ac68637bSLei Zhang 44808d7377bSLogan Chien auto symInfo = 449*26d513d1SKazu Hirata isa<NamedAttribute *>(op.getArg(argIndex)) 450ac68637bSLei Zhang ? SymbolInfo::getAttr(&op, argIndex) 45108d7377bSLogan Chien : SymbolInfo::getOperand(node, &op, argIndex, variadicSubIndex); 452ac68637bSLei Zhang 453008c0ea6Srdzhabarov std::string key = symbol.str(); 454008c0ea6Srdzhabarov if (symbolInfoMap.count(key)) { 455008c0ea6Srdzhabarov // Only non unique name for the operand is supported. 456008c0ea6Srdzhabarov if (symInfo.kind != SymbolInfo::Kind::Operand) { 457008c0ea6Srdzhabarov return false; 458008c0ea6Srdzhabarov } 459008c0ea6Srdzhabarov 460008c0ea6Srdzhabarov // Cannot add new operand if there is already non operand with the same 461008c0ea6Srdzhabarov // name. 462008c0ea6Srdzhabarov if (symbolInfoMap.find(key)->second.kind != SymbolInfo::Kind::Operand) { 463008c0ea6Srdzhabarov return false; 464008c0ea6Srdzhabarov } 465008c0ea6Srdzhabarov } 466008c0ea6Srdzhabarov 467008c0ea6Srdzhabarov symbolInfoMap.emplace(key, symInfo); 468008c0ea6Srdzhabarov return true; 469ac68637bSLei Zhang } 470ac68637bSLei Zhang 47112d16de5SRahul Joshi bool SymbolInfoMap::bindOpResult(StringRef symbol, const Operator &op) { 472008c0ea6Srdzhabarov std::string name = getValuePackName(symbol).str(); 473008c0ea6Srdzhabarov auto inserted = symbolInfoMap.emplace(name, SymbolInfo::getResult(&op)); 474008c0ea6Srdzhabarov 475008c0ea6Srdzhabarov return symbolInfoMap.count(inserted->first) == 1; 476ac68637bSLei Zhang } 477ac68637bSLei Zhang 478d7314b3cSChia-hung Duan bool SymbolInfoMap::bindValues(StringRef symbol, int numValues) { 479d7314b3cSChia-hung Duan std::string name = getValuePackName(symbol).str(); 480d7314b3cSChia-hung Duan if (numValues > 1) 481d7314b3cSChia-hung Duan return bindMultipleValues(name, numValues); 482d7314b3cSChia-hung Duan return bindValue(name); 483d7314b3cSChia-hung Duan } 484d7314b3cSChia-hung Duan 48512d16de5SRahul Joshi bool SymbolInfoMap::bindValue(StringRef symbol) { 486008c0ea6Srdzhabarov auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getValue()); 487008c0ea6Srdzhabarov return symbolInfoMap.count(inserted->first) == 1; 488ac68637bSLei Zhang } 489ac68637bSLei Zhang 490d7314b3cSChia-hung Duan bool SymbolInfoMap::bindMultipleValues(StringRef symbol, int numValues) { 491d7314b3cSChia-hung Duan std::string name = getValuePackName(symbol).str(); 492d7314b3cSChia-hung Duan auto inserted = 493d7314b3cSChia-hung Duan symbolInfoMap.emplace(name, SymbolInfo::getMultipleValues(numValues)); 494d7314b3cSChia-hung Duan return symbolInfoMap.count(inserted->first) == 1; 495d7314b3cSChia-hung Duan } 496d7314b3cSChia-hung Duan 4972bf423b0SRob Suderman bool SymbolInfoMap::bindAttr(StringRef symbol) { 498ad1fe396SRob Suderman auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getAttr()); 4992bf423b0SRob Suderman return symbolInfoMap.count(inserted->first) == 1; 5002bf423b0SRob Suderman } 5012bf423b0SRob Suderman 50212d16de5SRahul Joshi bool SymbolInfoMap::contains(StringRef symbol) const { 503ac68637bSLei Zhang return find(symbol) != symbolInfoMap.end(); 504ac68637bSLei Zhang } 505ac68637bSLei Zhang 50612d16de5SRahul Joshi SymbolInfoMap::const_iterator SymbolInfoMap::find(StringRef key) const { 507008c0ea6Srdzhabarov std::string name = getValuePackName(key).str(); 508008c0ea6Srdzhabarov 509ac68637bSLei Zhang return symbolInfoMap.find(name); 510ac68637bSLei Zhang } 511ac68637bSLei Zhang 512008c0ea6Srdzhabarov SymbolInfoMap::const_iterator 513b4001ae8SChia-hung Duan SymbolInfoMap::findBoundSymbol(StringRef key, DagNode node, const Operator &op, 51408d7377bSLogan Chien int argIndex, 51508d7377bSLogan Chien std::optional<int> variadicSubIndex) const { 51608d7377bSLogan Chien return findBoundSymbol( 51708d7377bSLogan Chien key, SymbolInfo::getOperand(node, &op, argIndex, variadicSubIndex)); 518bb250606SChia-hung Duan } 519bb250606SChia-hung Duan 520bb250606SChia-hung Duan SymbolInfoMap::const_iterator 5211fc096afSMehdi Amini SymbolInfoMap::findBoundSymbol(StringRef key, 5221fc096afSMehdi Amini const SymbolInfo &symbolInfo) const { 523008c0ea6Srdzhabarov std::string name = getValuePackName(key).str(); 524008c0ea6Srdzhabarov auto range = symbolInfoMap.equal_range(name); 525008c0ea6Srdzhabarov 526d7314b3cSChia-hung Duan for (auto it = range.first; it != range.second; ++it) 527d7314b3cSChia-hung Duan if (it->second.dagAndConstant == symbolInfo.dagAndConstant) 528008c0ea6Srdzhabarov return it; 529008c0ea6Srdzhabarov 530008c0ea6Srdzhabarov return symbolInfoMap.end(); 531008c0ea6Srdzhabarov } 532008c0ea6Srdzhabarov 533008c0ea6Srdzhabarov std::pair<SymbolInfoMap::iterator, SymbolInfoMap::iterator> 534008c0ea6Srdzhabarov SymbolInfoMap::getRangeOfEqualElements(StringRef key) { 535008c0ea6Srdzhabarov std::string name = getValuePackName(key).str(); 536008c0ea6Srdzhabarov 537008c0ea6Srdzhabarov return symbolInfoMap.equal_range(name); 538008c0ea6Srdzhabarov } 539008c0ea6Srdzhabarov 540008c0ea6Srdzhabarov int SymbolInfoMap::count(StringRef key) const { 541008c0ea6Srdzhabarov std::string name = getValuePackName(key).str(); 542008c0ea6Srdzhabarov return symbolInfoMap.count(name); 543008c0ea6Srdzhabarov } 544008c0ea6Srdzhabarov 54512d16de5SRahul Joshi int SymbolInfoMap::getStaticValueCount(StringRef symbol) const { 546ac68637bSLei Zhang StringRef name = getValuePackName(symbol); 547ac68637bSLei Zhang if (name != symbol) { 548ac68637bSLei Zhang // If there is a trailing index inside symbol, it references just one 549ac68637bSLei Zhang // static value. 550ac68637bSLei Zhang return 1; 551ac68637bSLei Zhang } 552ac68637bSLei Zhang // Otherwise, find how many it represents by querying the symbol's info. 553008c0ea6Srdzhabarov return find(name)->second.getStaticValueCount(); 554ac68637bSLei Zhang } 555ac68637bSLei Zhang 55612d16de5SRahul Joshi std::string SymbolInfoMap::getValueAndRangeUse(StringRef symbol, 55712d16de5SRahul Joshi const char *fmt, 55831cfee60SLei Zhang const char *separator) const { 559ac68637bSLei Zhang int index = -1; 560ac68637bSLei Zhang StringRef name = getValuePackName(symbol, &index); 561ac68637bSLei Zhang 562008c0ea6Srdzhabarov auto it = symbolInfoMap.find(name.str()); 563ac68637bSLei Zhang if (it == symbolInfoMap.end()) { 564ac68637bSLei Zhang auto error = formatv("referencing unbound symbol '{0}'", symbol); 565ac68637bSLei Zhang PrintFatalError(loc, error); 566ac68637bSLei Zhang } 567ac68637bSLei Zhang 568008c0ea6Srdzhabarov return it->second.getValueAndRangeUse(name, index, fmt, separator); 56931cfee60SLei Zhang } 57031cfee60SLei Zhang 57112d16de5SRahul Joshi std::string SymbolInfoMap::getAllRangeUse(StringRef symbol, const char *fmt, 57231cfee60SLei Zhang const char *separator) const { 57331cfee60SLei Zhang int index = -1; 57431cfee60SLei Zhang StringRef name = getValuePackName(symbol, &index); 57531cfee60SLei Zhang 576008c0ea6Srdzhabarov auto it = symbolInfoMap.find(name.str()); 57731cfee60SLei Zhang if (it == symbolInfoMap.end()) { 57831cfee60SLei Zhang auto error = formatv("referencing unbound symbol '{0}'", symbol); 57931cfee60SLei Zhang PrintFatalError(loc, error); 58031cfee60SLei Zhang } 58131cfee60SLei Zhang 582008c0ea6Srdzhabarov return it->second.getAllRangeUse(name, index, fmt, separator); 583008c0ea6Srdzhabarov } 584008c0ea6Srdzhabarov 585008c0ea6Srdzhabarov void SymbolInfoMap::assignUniqueAlternativeNames() { 586008c0ea6Srdzhabarov llvm::StringSet<> usedNames; 587008c0ea6Srdzhabarov 588008c0ea6Srdzhabarov for (auto symbolInfoIt = symbolInfoMap.begin(); 589008c0ea6Srdzhabarov symbolInfoIt != symbolInfoMap.end();) { 590008c0ea6Srdzhabarov auto range = symbolInfoMap.equal_range(symbolInfoIt->first); 591008c0ea6Srdzhabarov auto startRange = range.first; 592008c0ea6Srdzhabarov auto endRange = range.second; 593008c0ea6Srdzhabarov 594008c0ea6Srdzhabarov auto operandName = symbolInfoIt->first; 595008c0ea6Srdzhabarov int startSearchIndex = 0; 596008c0ea6Srdzhabarov for (++startRange; startRange != endRange; ++startRange) { 597008c0ea6Srdzhabarov // Current operand name is not unique, find a unique one 598008c0ea6Srdzhabarov // and set the alternative name. 599008c0ea6Srdzhabarov for (int i = startSearchIndex;; ++i) { 600008c0ea6Srdzhabarov std::string alternativeName = operandName + std::to_string(i); 601008c0ea6Srdzhabarov if (!usedNames.contains(alternativeName) && 602008c0ea6Srdzhabarov symbolInfoMap.count(alternativeName) == 0) { 603008c0ea6Srdzhabarov usedNames.insert(alternativeName); 604008c0ea6Srdzhabarov startRange->second.alternativeName = alternativeName; 605008c0ea6Srdzhabarov startSearchIndex = i + 1; 606008c0ea6Srdzhabarov 607008c0ea6Srdzhabarov break; 608008c0ea6Srdzhabarov } 609008c0ea6Srdzhabarov } 610008c0ea6Srdzhabarov } 611008c0ea6Srdzhabarov 612008c0ea6Srdzhabarov symbolInfoIt = endRange; 613008c0ea6Srdzhabarov } 614ac68637bSLei Zhang } 615ac68637bSLei Zhang 616ac68637bSLei Zhang //===----------------------------------------------------------------------===// 617ac68637bSLei Zhang // Pattern 618ac68637bSLei Zhang //==----------------------------------------------------------------------===// 619ac68637bSLei Zhang 620659192b1SRahul Joshi Pattern::Pattern(const Record *def, RecordOperatorMap *mapper) 621ac68637bSLei Zhang : def(*def), recordOpMap(mapper) {} 622eb753f4aSLei Zhang 62312d16de5SRahul Joshi DagNode Pattern::getSourcePattern() const { 62412d16de5SRahul Joshi return DagNode(def.getValueAsDag("sourcePattern")); 625eb753f4aSLei Zhang } 626eb753f4aSLei Zhang 62712d16de5SRahul Joshi int Pattern::getNumResultPatterns() const { 6288f5fa566SLei Zhang auto *results = def.getValueAsListInit("resultPatterns"); 629eb753f4aSLei Zhang return results->size(); 630eb753f4aSLei Zhang } 631eb753f4aSLei Zhang 63212d16de5SRahul Joshi DagNode Pattern::getResultPattern(unsigned index) const { 6338f5fa566SLei Zhang auto *results = def.getValueAsListInit("resultPatterns"); 634659192b1SRahul Joshi return DagNode(cast<DagInit>(results->getElement(index))); 635eb753f4aSLei Zhang } 636eb753f4aSLei Zhang 63712d16de5SRahul Joshi void Pattern::collectSourcePatternBoundSymbols(SymbolInfoMap &infoMap) { 638659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "start collecting source pattern bound symbols\n"); 639ac68637bSLei Zhang collectBoundSymbols(getSourcePattern(), infoMap, /*isSrcPattern=*/true); 640659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "done collecting source pattern bound symbols\n"); 641008c0ea6Srdzhabarov 642659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "start assigning alternative names for symbols\n"); 643008c0ea6Srdzhabarov infoMap.assignUniqueAlternativeNames(); 644659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "done assigning alternative names for symbols\n"); 645eb753f4aSLei Zhang } 646eb753f4aSLei Zhang 64712d16de5SRahul Joshi void Pattern::collectResultPatternBoundSymbols(SymbolInfoMap &infoMap) { 648659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "start collecting result pattern bound symbols\n"); 649ac68637bSLei Zhang for (int i = 0, e = getNumResultPatterns(); i < e; ++i) { 650ac68637bSLei Zhang auto pattern = getResultPattern(i); 651ac68637bSLei Zhang collectBoundSymbols(pattern, infoMap, /*isSrcPattern=*/false); 652eb753f4aSLei Zhang } 653659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "done collecting result pattern bound symbols\n"); 654388fb375SJacques Pienaar } 655388fb375SJacques Pienaar 65612d16de5SRahul Joshi const Operator &Pattern::getSourceRootOp() { 657eb753f4aSLei Zhang return getSourcePattern().getDialectOp(recordOpMap); 658eb753f4aSLei Zhang } 659eb753f4aSLei Zhang 66012d16de5SRahul Joshi Operator &Pattern::getDialectOp(DagNode node) { 661eb753f4aSLei Zhang return node.getDialectOp(recordOpMap); 662eb753f4aSLei Zhang } 663388fb375SJacques Pienaar 66412d16de5SRahul Joshi std::vector<AppliedConstraint> Pattern::getConstraints() const { 665388fb375SJacques Pienaar auto *listInit = def.getValueAsListInit("constraints"); 66612d16de5SRahul Joshi std::vector<AppliedConstraint> ret; 667388fb375SJacques Pienaar ret.reserve(listInit->size()); 6688f5fa566SLei Zhang 66902b6fb21SMehdi Amini for (auto *it : *listInit) { 670659192b1SRahul Joshi auto *dagInit = dyn_cast<DagInit>(it); 6718f5fa566SLei Zhang if (!dagInit) 6722bf423b0SRob Suderman PrintFatalError(&def, "all elements in Pattern multi-entity " 6738f5fa566SLei Zhang "constraints should be DAG nodes"); 6748f5fa566SLei Zhang 6758f5fa566SLei Zhang std::vector<std::string> entities; 6768f5fa566SLei Zhang entities.reserve(dagInit->arg_size()); 677cb40e36dSLei Zhang for (auto *argName : dagInit->getArgNames()) { 678cb40e36dSLei Zhang if (!argName) { 679cb40e36dSLei Zhang PrintFatalError( 6802bf423b0SRob Suderman &def, 681cb40e36dSLei Zhang "operands to additional constraints can only be symbol references"); 682cb40e36dSLei Zhang } 683e5639b3fSMehdi Amini entities.emplace_back(argName->getValue()); 684cb40e36dSLei Zhang } 6858f5fa566SLei Zhang 686659192b1SRahul Joshi ret.emplace_back(cast<DefInit>(dagInit->getOperator())->getDef(), 687c72d849eSLei Zhang dagInit->getNameStr(), std::move(entities)); 688388fb375SJacques Pienaar } 689388fb375SJacques Pienaar return ret; 690388fb375SJacques Pienaar } 69153035874SFeng Liu 692d22965f0SJian Cai int Pattern::getNumSupplementalPatterns() const { 693d22965f0SJian Cai auto *results = def.getValueAsListInit("supplementalPatterns"); 694d22965f0SJian Cai return results->size(); 695d22965f0SJian Cai } 696d22965f0SJian Cai 697d22965f0SJian Cai DagNode Pattern::getSupplementalPattern(unsigned index) const { 698d22965f0SJian Cai auto *results = def.getValueAsListInit("supplementalPatterns"); 699659192b1SRahul Joshi return DagNode(cast<DagInit>(results->getElement(index))); 700d22965f0SJian Cai } 701d22965f0SJian Cai 70212d16de5SRahul Joshi int Pattern::getBenefit() const { 703a0606ca7SFeng Liu // The initial benefit value is a heuristic with number of ops in the source 70453035874SFeng Liu // pattern. 705a0606ca7SFeng Liu int initBenefit = getSourcePattern().getNumOps(); 706659192b1SRahul Joshi const DagInit *delta = def.getValueAsDag("benefitDelta"); 707659192b1SRahul Joshi if (delta->getNumArgs() != 1 || !isa<IntInit>(delta->getArg(0))) { 7082bf423b0SRob Suderman PrintFatalError(&def, 709a0606ca7SFeng Liu "The 'addBenefit' takes and only takes one integer value"); 710a0606ca7SFeng Liu } 711659192b1SRahul Joshi return initBenefit + dyn_cast<IntInit>(delta->getArg(0))->getValue(); 71253035874SFeng Liu } 71304b6d2f3SLei Zhang 71412d16de5SRahul Joshi std::vector<Pattern::IdentifierLine> Pattern::getLocation() const { 7154165885aSJacques Pienaar std::vector<std::pair<StringRef, unsigned>> result; 7164165885aSJacques Pienaar result.reserve(def.getLoc().size()); 7174165885aSJacques Pienaar for (auto loc : def.getLoc()) { 7184165885aSJacques Pienaar unsigned buf = llvm::SrcMgr.FindBufferContainingLoc(loc); 7194165885aSJacques Pienaar assert(buf && "invalid source location"); 7204165885aSJacques Pienaar result.emplace_back( 7214165885aSJacques Pienaar llvm::SrcMgr.getBufferInfo(buf).Buffer->getBufferIdentifier(), 7224165885aSJacques Pienaar llvm::SrcMgr.getLineAndColumn(loc, buf).first); 7234165885aSJacques Pienaar } 7244165885aSJacques Pienaar return result; 7254165885aSJacques Pienaar } 7264165885aSJacques Pienaar 7272bf423b0SRob Suderman void Pattern::verifyBind(bool result, StringRef symbolName) { 7282bf423b0SRob Suderman if (!result) { 7292bf423b0SRob Suderman auto err = formatv("symbol '{0}' bound more than once", symbolName); 7302bf423b0SRob Suderman PrintFatalError(&def, err); 7312bf423b0SRob Suderman } 7322bf423b0SRob Suderman } 7332bf423b0SRob Suderman 73412d16de5SRahul Joshi void Pattern::collectBoundSymbols(DagNode tree, SymbolInfoMap &infoMap, 735e032d0dcSLei Zhang bool isSrcPattern) { 736e032d0dcSLei Zhang auto treeName = tree.getSymbol(); 7372bf423b0SRob Suderman auto numTreeArgs = tree.getNumArgs(); 7382bf423b0SRob Suderman 7392bf423b0SRob Suderman if (tree.isNativeCodeCall()) { 740e032d0dcSLei Zhang if (!treeName.empty()) { 74134b5482bSChia-hung Duan if (!isSrcPattern) { 742659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "found symbol bound to NativeCodeCall: " 74334b5482bSChia-hung Duan << treeName << '\n'); 744d7314b3cSChia-hung Duan verifyBind( 745d7314b3cSChia-hung Duan infoMap.bindValues(treeName, tree.getNumReturnsOfNativeCode()), 746d7314b3cSChia-hung Duan treeName); 74734b5482bSChia-hung Duan } else { 74834b5482bSChia-hung Duan PrintFatalError(&def, 74934b5482bSChia-hung Duan formatv("binding symbol '{0}' to NativecodeCall in " 75034b5482bSChia-hung Duan "MatchPattern is not supported", 751e032d0dcSLei Zhang treeName)); 752e032d0dcSLei Zhang } 75334b5482bSChia-hung Duan } 7542bf423b0SRob Suderman 7552bf423b0SRob Suderman for (int i = 0; i != numTreeArgs; ++i) { 7562bf423b0SRob Suderman if (auto treeArg = tree.getArgAsNestedDag(i)) { 7572bf423b0SRob Suderman // This DAG node argument is a DAG node itself. Go inside recursively. 7582bf423b0SRob Suderman collectBoundSymbols(treeArg, infoMap, isSrcPattern); 7592bf423b0SRob Suderman continue; 7602bf423b0SRob Suderman } 7612bf423b0SRob Suderman 7622bf423b0SRob Suderman if (!isSrcPattern) 7632bf423b0SRob Suderman continue; 7642bf423b0SRob Suderman 7652bf423b0SRob Suderman // We can only bind symbols to arguments in source pattern. Those 7662bf423b0SRob Suderman // symbols are referenced in result patterns. 7672bf423b0SRob Suderman auto treeArgName = tree.getArgName(i); 7682bf423b0SRob Suderman 7692bf423b0SRob Suderman // `$_` is a special symbol meaning ignore the current argument. 7702bf423b0SRob Suderman if (!treeArgName.empty() && treeArgName != "_") { 7712bf423b0SRob Suderman DagLeaf leaf = tree.getArgAsLeaf(i); 77234b5482bSChia-hung Duan 77334b5482bSChia-hung Duan // In (NativeCodeCall<"Foo($_self, $0, $1, $2)"> I8Attr:$a, I8:$b, $c), 77434b5482bSChia-hung Duan if (leaf.isUnspecified()) { 77534b5482bSChia-hung Duan // This is case of $c, a Value without any constraints. 77634b5482bSChia-hung Duan verifyBind(infoMap.bindValue(treeArgName), treeArgName); 77734b5482bSChia-hung Duan } else { 7782bf423b0SRob Suderman auto constraint = leaf.getAsConstraint(); 7792bf423b0SRob Suderman bool isAttr = leaf.isAttrMatcher() || leaf.isEnumAttrCase() || 7802bf423b0SRob Suderman leaf.isConstantAttr() || 7812bf423b0SRob Suderman constraint.getKind() == Constraint::Kind::CK_Attr; 7822bf423b0SRob Suderman 7832bf423b0SRob Suderman if (isAttr) { 78434b5482bSChia-hung Duan // This is case of $a, a binding to a certain attribute. 7852bf423b0SRob Suderman verifyBind(infoMap.bindAttr(treeArgName), treeArgName); 7862bf423b0SRob Suderman continue; 7872bf423b0SRob Suderman } 7882bf423b0SRob Suderman 78934b5482bSChia-hung Duan // This is case of $b, a binding to a certain type. 7902bf423b0SRob Suderman verifyBind(infoMap.bindValue(treeArgName), treeArgName); 7912bf423b0SRob Suderman } 7922bf423b0SRob Suderman } 79334b5482bSChia-hung Duan } 7942bf423b0SRob Suderman 795e032d0dcSLei Zhang return; 796e032d0dcSLei Zhang } 797e032d0dcSLei Zhang 7982bf423b0SRob Suderman if (tree.isOperation()) { 79904b6d2f3SLei Zhang auto &op = getDialectOp(tree); 80004b6d2f3SLei Zhang auto numOpArgs = op.getNumArgs(); 8012d99c815SChia-hung Duan int numEither = 0; 80204b6d2f3SLei Zhang 8032d99c815SChia-hung Duan // We need to exclude the trailing directives and `either` directive groups 8042d99c815SChia-hung Duan // two operands of the operation. 805cb8c30d3SMogball int numDirectives = 0; 806cb8c30d3SMogball for (int i = numTreeArgs - 1; i >= 0; --i) { 807cb8c30d3SMogball if (auto dagArg = tree.getArgAsNestedDag(i)) { 808cb8c30d3SMogball if (dagArg.isLocationDirective() || dagArg.isReturnTypeDirective()) 809cb8c30d3SMogball ++numDirectives; 8102d99c815SChia-hung Duan else if (dagArg.isEither()) 8112d99c815SChia-hung Duan ++numEither; 812cb8c30d3SMogball } 8133f7439b2SJacques Pienaar } 8143f7439b2SJacques Pienaar 8152d99c815SChia-hung Duan if (numOpArgs != numTreeArgs - numDirectives + numEither) { 8162d99c815SChia-hung Duan auto err = 8172d99c815SChia-hung Duan formatv("op '{0}' argument number mismatch: " 81804b6d2f3SLei Zhang "{1} in pattern vs. {2} in definition", 8192d99c815SChia-hung Duan op.getOperationName(), numTreeArgs + numEither, numOpArgs); 8202bf423b0SRob Suderman PrintFatalError(&def, err); 82104b6d2f3SLei Zhang } 82204b6d2f3SLei Zhang 82304b6d2f3SLei Zhang // The name attached to the DAG node's operator is for representing the 82404b6d2f3SLei Zhang // results generated from this op. It should be remembered as bound results. 825ac68637bSLei Zhang if (!treeName.empty()) { 826659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "found symbol bound to op result: " << treeName 827659192b1SRahul Joshi << '\n'); 8282bf423b0SRob Suderman verifyBind(infoMap.bindOpResult(treeName, op), treeName); 829ac68637bSLei Zhang } 83004b6d2f3SLei Zhang 8312d99c815SChia-hung Duan // The operand in `either` DAG should be bound to the operation in the 8322d99c815SChia-hung Duan // parent DagNode. 8332d99c815SChia-hung Duan auto collectSymbolInEither = [&](DagNode parent, DagNode tree, 83432032cbfSChia-hung Duan int opArgIdx) { 8352d99c815SChia-hung Duan for (int i = 0; i < tree.getNumArgs(); ++i, ++opArgIdx) { 8362d99c815SChia-hung Duan if (DagNode subTree = tree.getArgAsNestedDag(i)) { 8372d99c815SChia-hung Duan collectBoundSymbols(subTree, infoMap, isSrcPattern); 8382d99c815SChia-hung Duan } else { 8392d99c815SChia-hung Duan auto argName = tree.getArgName(i); 84032032cbfSChia-hung Duan if (!argName.empty() && argName != "_") { 8412d99c815SChia-hung Duan verifyBind(infoMap.bindOpArgument(parent, argName, op, opArgIdx), 8422d99c815SChia-hung Duan argName); 8432d99c815SChia-hung Duan } 8442d99c815SChia-hung Duan } 84532032cbfSChia-hung Duan } 8462d99c815SChia-hung Duan }; 8472d99c815SChia-hung Duan 84808d7377bSLogan Chien // The operand in `variadic` DAG should be bound to the operation in the 84908d7377bSLogan Chien // parent DagNode. The range index must be included as well to distinguish 85008d7377bSLogan Chien // (potentially) repeating argName within the `variadic` DAG. 85108d7377bSLogan Chien auto collectSymbolInVariadic = [&](DagNode parent, DagNode tree, 85208d7377bSLogan Chien int opArgIdx) { 85308d7377bSLogan Chien auto treeName = tree.getSymbol(); 85408d7377bSLogan Chien if (!treeName.empty()) { 85508d7377bSLogan Chien // If treeName is specified, bind to the full variadic operand_range. 85608d7377bSLogan Chien verifyBind(infoMap.bindOpArgument(parent, treeName, op, opArgIdx, 85708d7377bSLogan Chien std::nullopt), 85808d7377bSLogan Chien treeName); 85908d7377bSLogan Chien } 86008d7377bSLogan Chien 86108d7377bSLogan Chien for (int i = 0; i < tree.getNumArgs(); ++i) { 86208d7377bSLogan Chien if (DagNode subTree = tree.getArgAsNestedDag(i)) { 86308d7377bSLogan Chien collectBoundSymbols(subTree, infoMap, isSrcPattern); 86408d7377bSLogan Chien } else { 86508d7377bSLogan Chien auto argName = tree.getArgName(i); 86608d7377bSLogan Chien if (!argName.empty() && argName != "_") { 86708d7377bSLogan Chien verifyBind(infoMap.bindOpArgument(parent, argName, op, opArgIdx, 86808d7377bSLogan Chien /*variadicSubIndex=*/i), 86908d7377bSLogan Chien argName); 87008d7377bSLogan Chien } 87108d7377bSLogan Chien } 87208d7377bSLogan Chien } 87308d7377bSLogan Chien }; 87408d7377bSLogan Chien 8752d99c815SChia-hung Duan for (int i = 0, opArgIdx = 0; i != numTreeArgs; ++i, ++opArgIdx) { 87604b6d2f3SLei Zhang if (auto treeArg = tree.getArgAsNestedDag(i)) { 8772d99c815SChia-hung Duan if (treeArg.isEither()) { 8782d99c815SChia-hung Duan collectSymbolInEither(tree, treeArg, opArgIdx); 87932032cbfSChia-hung Duan // `either` DAG is *flattened*. For example, 88032032cbfSChia-hung Duan // 88132032cbfSChia-hung Duan // (FooOp (either arg0, arg1), arg2) 88232032cbfSChia-hung Duan // 88332032cbfSChia-hung Duan // can be viewed as: 88432032cbfSChia-hung Duan // 88532032cbfSChia-hung Duan // (FooOp arg0, arg1, arg2) 88632032cbfSChia-hung Duan ++opArgIdx; 88708d7377bSLogan Chien } else if (treeArg.isVariadic()) { 88808d7377bSLogan Chien collectSymbolInVariadic(tree, treeArg, opArgIdx); 8892d99c815SChia-hung Duan } else { 89004b6d2f3SLei Zhang // This DAG node argument is a DAG node itself. Go inside recursively. 891ac68637bSLei Zhang collectBoundSymbols(treeArg, infoMap, isSrcPattern); 8922d99c815SChia-hung Duan } 8932bf423b0SRob Suderman continue; 8942bf423b0SRob Suderman } 8952bf423b0SRob Suderman 8962bf423b0SRob Suderman if (isSrcPattern) { 897e032d0dcSLei Zhang // We can only bind symbols to op arguments in source pattern. Those 898e032d0dcSLei Zhang // symbols are referenced in result patterns. 89904b6d2f3SLei Zhang auto treeArgName = tree.getArgName(i); 9004982eaf8SLei Zhang // `$_` is a special symbol meaning ignore the current argument. 9014982eaf8SLei Zhang if (!treeArgName.empty() && treeArgName != "_") { 902659192b1SRahul Joshi LLVM_DEBUG(dbgs() << "found symbol bound to op argument: " 9031358df19SLei Zhang << treeArgName << '\n'); 9042d99c815SChia-hung Duan verifyBind(infoMap.bindOpArgument(tree, treeArgName, op, opArgIdx), 905b4001ae8SChia-hung Duan treeArgName); 906ac68637bSLei Zhang } 907ac68637bSLei Zhang } 90804b6d2f3SLei Zhang } 9092bf423b0SRob Suderman return; 91004b6d2f3SLei Zhang } 9112bf423b0SRob Suderman 9122bf423b0SRob Suderman if (!treeName.empty()) { 9132bf423b0SRob Suderman PrintFatalError( 9142bf423b0SRob Suderman &def, formatv("binding symbol '{0}' to non-operation/native code call " 9152bf423b0SRob Suderman "unsupported right now", 9162bf423b0SRob Suderman treeName)); 9172bf423b0SRob Suderman } 91804b6d2f3SLei Zhang } 919