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 
290ea6154bSJacques Pienaar using llvm::formatv;
30eb753f4aSLei Zhang 
31ac68637bSLei Zhang //===----------------------------------------------------------------------===//
32ac68637bSLei Zhang // DagLeaf
33ac68637bSLei Zhang //===----------------------------------------------------------------------===//
34ac68637bSLei Zhang 
isUnspecified() const3512d16de5SRahul Joshi bool DagLeaf::isUnspecified() const {
36*ae002f8bSKazu Hirata   return isa_and_nonnull<llvm::UnsetInit>(def);
37e0774c00SLei Zhang }
38e0774c00SLei Zhang 
isOperandMatcher() const3912d16de5SRahul Joshi bool DagLeaf::isOperandMatcher() const {
40e0774c00SLei Zhang   // Operand matchers specify a type constraint.
41b9e38a79SLei Zhang   return isSubClassOf("TypeConstraint");
42e0774c00SLei Zhang }
43e0774c00SLei Zhang 
isAttrMatcher() const4412d16de5SRahul Joshi bool DagLeaf::isAttrMatcher() const {
45c52a8127SFeng Liu   // Attribute matchers specify an attribute constraint.
46b9e38a79SLei Zhang   return isSubClassOf("AttrConstraint");
47e0774c00SLei Zhang }
48e0774c00SLei Zhang 
isNativeCodeCall() const4912d16de5SRahul Joshi bool DagLeaf::isNativeCodeCall() const {
50d0e2019dSLei Zhang   return isSubClassOf("NativeCodeCall");
51e0774c00SLei Zhang }
52e0774c00SLei Zhang 
isConstantAttr() const5312d16de5SRahul Joshi bool DagLeaf::isConstantAttr() const { return isSubClassOf("ConstantAttr"); }
54b9e38a79SLei Zhang 
isEnumAttrCase() const5512d16de5SRahul Joshi bool DagLeaf::isEnumAttrCase() const {
569dd182e0SLei Zhang   return isSubClassOf("EnumAttrCaseInfo");
57e0774c00SLei Zhang }
58e0774c00SLei Zhang 
isStringAttr() const59cb8c30d3SMogball bool DagLeaf::isStringAttr() const { return isa<llvm::StringInit>(def); }
60d6b32e39SJacques Pienaar 
getAsConstraint() const6112d16de5SRahul Joshi Constraint DagLeaf::getAsConstraint() const {
628f5fa566SLei Zhang   assert((isOperandMatcher() || isAttrMatcher()) &&
638f5fa566SLei Zhang          "the DAG leaf must be operand or attribute");
648f5fa566SLei Zhang   return Constraint(cast<llvm::DefInit>(def)->getDef());
65e0774c00SLei Zhang }
66e0774c00SLei Zhang 
getAsConstantAttr() const6712d16de5SRahul Joshi ConstantAttr DagLeaf::getAsConstantAttr() const {
68e0774c00SLei Zhang   assert(isConstantAttr() && "the DAG leaf must be constant attribute");
69e0774c00SLei Zhang   return ConstantAttr(cast<llvm::DefInit>(def));
70e0774c00SLei Zhang }
71e0774c00SLei Zhang 
getAsEnumAttrCase() const7212d16de5SRahul Joshi EnumAttrCase DagLeaf::getAsEnumAttrCase() const {
73b9e38a79SLei Zhang   assert(isEnumAttrCase() && "the DAG leaf must be an enum attribute case");
74b9e38a79SLei Zhang   return EnumAttrCase(cast<llvm::DefInit>(def));
75b9e38a79SLei Zhang }
76b9e38a79SLei Zhang 
getConditionTemplate() const7712d16de5SRahul Joshi std::string DagLeaf::getConditionTemplate() const {
788f5fa566SLei Zhang   return getAsConstraint().getConditionTemplate();
79e0774c00SLei Zhang }
80e0774c00SLei Zhang 
getNativeCodeTemplate() const8112d16de5SRahul Joshi llvm::StringRef DagLeaf::getNativeCodeTemplate() const {
82d0e2019dSLei Zhang   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
83d0e2019dSLei Zhang   return cast<llvm::DefInit>(def)->getDef()->getValueAsString("expression");
84eb753f4aSLei Zhang }
85eb753f4aSLei Zhang 
getNumReturnsOfNativeCode() const86d7314b3cSChia-hung Duan int DagLeaf::getNumReturnsOfNativeCode() const {
87d7314b3cSChia-hung Duan   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
88d7314b3cSChia-hung Duan   return cast<llvm::DefInit>(def)->getDef()->getValueAsInt("numReturns");
89d7314b3cSChia-hung Duan }
90d7314b3cSChia-hung Duan 
getStringAttr() const9112d16de5SRahul Joshi std::string DagLeaf::getStringAttr() const {
92d6b32e39SJacques Pienaar   assert(isStringAttr() && "the DAG leaf must be string attribute");
93d6b32e39SJacques Pienaar   return def->getAsUnquotedString();
94d6b32e39SJacques Pienaar }
isSubClassOf(StringRef superclass) const9512d16de5SRahul Joshi bool DagLeaf::isSubClassOf(StringRef superclass) const {
96b9e38a79SLei Zhang   if (auto *defInit = dyn_cast_or_null<llvm::DefInit>(def))
97b9e38a79SLei Zhang     return defInit->getDef()->isSubClassOf(superclass);
98b9e38a79SLei Zhang   return false;
99b9e38a79SLei Zhang }
100b9e38a79SLei Zhang 
print(raw_ostream & os) const10112d16de5SRahul Joshi void DagLeaf::print(raw_ostream &os) const {
1021358df19SLei Zhang   if (def)
1031358df19SLei Zhang     def->print(os);
1041358df19SLei Zhang }
1051358df19SLei Zhang 
106ac68637bSLei Zhang //===----------------------------------------------------------------------===//
107ac68637bSLei Zhang // DagNode
108ac68637bSLei Zhang //===----------------------------------------------------------------------===//
109ac68637bSLei Zhang 
isNativeCodeCall() const11012d16de5SRahul Joshi bool DagNode::isNativeCodeCall() const {
111d0e2019dSLei Zhang   if (auto *defInit = dyn_cast_or_null<llvm::DefInit>(node->getOperator()))
112d0e2019dSLei Zhang     return defInit->getDef()->isSubClassOf("NativeCodeCall");
113c52a8127SFeng Liu   return false;
114c52a8127SFeng Liu }
115c52a8127SFeng Liu 
isOperation() const11612d16de5SRahul Joshi bool DagNode::isOperation() const {
117cb8c30d3SMogball   return !isNativeCodeCall() && !isReplaceWithValue() &&
1182d99c815SChia-hung Duan          !isLocationDirective() && !isReturnTypeDirective() && !isEither();
119647f8cabSRiver Riddle }
120647f8cabSRiver Riddle 
getNativeCodeTemplate() const12112d16de5SRahul Joshi llvm::StringRef DagNode::getNativeCodeTemplate() const {
122d0e2019dSLei Zhang   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
123c52a8127SFeng Liu   return cast<llvm::DefInit>(node->getOperator())
124c52a8127SFeng Liu       ->getDef()
125d0e2019dSLei Zhang       ->getValueAsString("expression");
126c52a8127SFeng Liu }
127c52a8127SFeng Liu 
getNumReturnsOfNativeCode() const128d7314b3cSChia-hung Duan int DagNode::getNumReturnsOfNativeCode() const {
129d7314b3cSChia-hung Duan   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
130d7314b3cSChia-hung Duan   return cast<llvm::DefInit>(node->getOperator())
131d7314b3cSChia-hung Duan       ->getDef()
132d7314b3cSChia-hung Duan       ->getValueAsInt("numReturns");
133d7314b3cSChia-hung Duan }
134d7314b3cSChia-hung Duan 
getSymbol() const13512d16de5SRahul Joshi llvm::StringRef DagNode::getSymbol() const { return node->getNameStr(); }
136388fb375SJacques Pienaar 
getDialectOp(RecordOperatorMap * mapper) const13712d16de5SRahul Joshi Operator &DagNode::getDialectOp(RecordOperatorMap *mapper) const {
138eb753f4aSLei Zhang   llvm::Record *opDef = cast<llvm::DefInit>(node->getOperator())->getDef();
1392dc6d205SLei Zhang   auto it = mapper->find(opDef);
1402dc6d205SLei Zhang   if (it != mapper->end())
1412dc6d205SLei Zhang     return *it->second;
14279f53b0cSJacques Pienaar   return *mapper->try_emplace(opDef, std::make_unique<Operator>(opDef))
1432dc6d205SLei Zhang               .first->second;
144eb753f4aSLei Zhang }
145eb753f4aSLei Zhang 
getNumOps() const14612d16de5SRahul Joshi int DagNode::getNumOps() const {
1472d99c815SChia-hung Duan   // We want to get number of operations recursively involved in the DAG tree.
1482d99c815SChia-hung Duan   // All other directives should be excluded.
1492d99c815SChia-hung Duan   int count = isOperation() ? 1 : 0;
1502fe8ae4fSJacques Pienaar   for (int i = 0, e = getNumArgs(); i != e; ++i) {
151eb753f4aSLei Zhang     if (auto child = getArgAsNestedDag(i))
152eb753f4aSLei Zhang       count += child.getNumOps();
153eb753f4aSLei Zhang   }
154eb753f4aSLei Zhang   return count;
155eb753f4aSLei Zhang }
156eb753f4aSLei Zhang 
getNumArgs() const15712d16de5SRahul Joshi int DagNode::getNumArgs() const { return node->getNumArgs(); }
158eb753f4aSLei Zhang 
isNestedDagArg(unsigned index) const15912d16de5SRahul Joshi bool DagNode::isNestedDagArg(unsigned index) const {
160eb753f4aSLei Zhang   return isa<llvm::DagInit>(node->getArg(index));
161eb753f4aSLei Zhang }
162eb753f4aSLei Zhang 
getArgAsNestedDag(unsigned index) const16312d16de5SRahul Joshi DagNode DagNode::getArgAsNestedDag(unsigned index) const {
164eb753f4aSLei Zhang   return DagNode(dyn_cast_or_null<llvm::DagInit>(node->getArg(index)));
165eb753f4aSLei Zhang }
166eb753f4aSLei Zhang 
getArgAsLeaf(unsigned index) const16712d16de5SRahul Joshi DagLeaf DagNode::getArgAsLeaf(unsigned index) const {
168e0774c00SLei Zhang   assert(!isNestedDagArg(index));
169e0774c00SLei Zhang   return DagLeaf(node->getArg(index));
170eb753f4aSLei Zhang }
171eb753f4aSLei Zhang 
getArgName(unsigned index) const17212d16de5SRahul Joshi StringRef DagNode::getArgName(unsigned index) const {
173eb753f4aSLei Zhang   return node->getArgNameStr(index);
174eb753f4aSLei Zhang }
175eb753f4aSLei Zhang 
isReplaceWithValue() const17612d16de5SRahul Joshi bool DagNode::isReplaceWithValue() const {
177eb753f4aSLei Zhang   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
178eb753f4aSLei Zhang   return dagOpDef->getName() == "replaceWithValue";
179eb753f4aSLei Zhang }
180eb753f4aSLei Zhang 
isLocationDirective() const18112d16de5SRahul Joshi bool DagNode::isLocationDirective() const {
1823f7439b2SJacques Pienaar   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
1833f7439b2SJacques Pienaar   return dagOpDef->getName() == "location";
1843f7439b2SJacques Pienaar }
1853f7439b2SJacques Pienaar 
isReturnTypeDirective() const186cb8c30d3SMogball bool DagNode::isReturnTypeDirective() const {
187cb8c30d3SMogball   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
188cb8c30d3SMogball   return dagOpDef->getName() == "returnType";
189cb8c30d3SMogball }
190cb8c30d3SMogball 
isEither() const1912d99c815SChia-hung Duan bool DagNode::isEither() const {
1922d99c815SChia-hung Duan   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
1932d99c815SChia-hung Duan   return dagOpDef->getName() == "either";
1942d99c815SChia-hung Duan }
1952d99c815SChia-hung Duan 
print(raw_ostream & os) const19612d16de5SRahul Joshi void DagNode::print(raw_ostream &os) const {
1971358df19SLei Zhang   if (node)
1981358df19SLei Zhang     node->print(os);
1991358df19SLei Zhang }
2001358df19SLei Zhang 
201ac68637bSLei Zhang //===----------------------------------------------------------------------===//
202ac68637bSLei Zhang // SymbolInfoMap
203ac68637bSLei Zhang //===----------------------------------------------------------------------===//
204ac68637bSLei Zhang 
getValuePackName(StringRef symbol,int * index)20512d16de5SRahul Joshi StringRef SymbolInfoMap::getValuePackName(StringRef symbol, int *index) {
206ac68637bSLei Zhang   StringRef name, indexStr;
207ac68637bSLei Zhang   int idx = -1;
208ac68637bSLei Zhang   std::tie(name, indexStr) = symbol.rsplit("__");
209ac68637bSLei Zhang 
210ac68637bSLei Zhang   if (indexStr.consumeInteger(10, idx)) {
211ac68637bSLei Zhang     // The second part is not an index; we return the whole symbol as-is.
212ac68637bSLei Zhang     return symbol;
213eb753f4aSLei Zhang   }
214ac68637bSLei Zhang   if (index) {
215ac68637bSLei Zhang     *index = idx;
216ac68637bSLei Zhang   }
217ac68637bSLei Zhang   return name;
218ac68637bSLei Zhang }
219ac68637bSLei Zhang 
SymbolInfo(const Operator * op,SymbolInfo::Kind kind,Optional<DagAndConstant> dagAndConstant)22012d16de5SRahul Joshi SymbolInfoMap::SymbolInfo::SymbolInfo(const Operator *op, SymbolInfo::Kind kind,
221d7314b3cSChia-hung Duan                                       Optional<DagAndConstant> dagAndConstant)
2221fc096afSMehdi Amini     : op(op), kind(kind), dagAndConstant(std::move(dagAndConstant)) {}
223ac68637bSLei Zhang 
getStaticValueCount() const22412d16de5SRahul Joshi int SymbolInfoMap::SymbolInfo::getStaticValueCount() const {
225ac68637bSLei Zhang   switch (kind) {
226ac68637bSLei Zhang   case Kind::Attr:
227ac68637bSLei Zhang   case Kind::Operand:
228ac68637bSLei Zhang   case Kind::Value:
229ac68637bSLei Zhang     return 1;
230ac68637bSLei Zhang   case Kind::Result:
231ac68637bSLei Zhang     return op->getNumResults();
232d7314b3cSChia-hung Duan   case Kind::MultipleValues:
233d7314b3cSChia-hung Duan     return getSize();
234ac68637bSLei Zhang   }
23512ff145eSjpienaar   llvm_unreachable("unknown kind");
236ac68637bSLei Zhang }
237ac68637bSLei Zhang 
getVarName(StringRef name) const238008c0ea6Srdzhabarov std::string SymbolInfoMap::SymbolInfo::getVarName(StringRef name) const {
239064a08cdSKazu Hirata   return alternativeName ? *alternativeName : name.str();
240008c0ea6Srdzhabarov }
241008c0ea6Srdzhabarov 
getVarTypeStr(StringRef name) const242bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getVarTypeStr(StringRef name) const {
243bb250606SChia-hung Duan   LLVM_DEBUG(llvm::dbgs() << "getVarTypeStr for '" << name << "': ");
244ac68637bSLei Zhang   switch (kind) {
245ac68637bSLei Zhang   case Kind::Attr: {
246bb250606SChia-hung Duan     if (op)
247bb250606SChia-hung Duan       return op->getArg(getArgIndex())
248b4001ae8SChia-hung Duan           .get<NamedAttribute *>()
249bb250606SChia-hung Duan           ->attr.getStorageType()
250bb250606SChia-hung Duan           .str();
2512bf423b0SRob Suderman     // TODO(suderman): Use a more exact type when available.
2528652fc84SMarkus Böck     return "::mlir::Attribute";
2532bf423b0SRob Suderman   }
25431cfee60SLei Zhang   case Kind::Operand: {
25531cfee60SLei Zhang     // Use operand range for captured operands (to support potential variadic
25631cfee60SLei Zhang     // operands).
257bb250606SChia-hung Duan     return "::mlir::Operation::operand_range";
25831cfee60SLei Zhang   }
259ac68637bSLei Zhang   case Kind::Value: {
260bb250606SChia-hung Duan     return "::mlir::Value";
261ac68637bSLei Zhang   }
262d7314b3cSChia-hung Duan   case Kind::MultipleValues: {
263bb250606SChia-hung Duan     return "::mlir::ValueRange";
264d7314b3cSChia-hung Duan   }
265ac68637bSLei Zhang   case Kind::Result: {
26631cfee60SLei Zhang     // Use the op itself for captured results.
267bb250606SChia-hung Duan     return op->getQualCppClassName();
268ac68637bSLei Zhang   }
269ac68637bSLei Zhang   }
27012ff145eSjpienaar   llvm_unreachable("unknown kind");
271ac68637bSLei Zhang }
272ac68637bSLei Zhang 
getVarDecl(StringRef name) const273bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getVarDecl(StringRef name) const {
274bb250606SChia-hung Duan   LLVM_DEBUG(llvm::dbgs() << "getVarDecl for '" << name << "': ");
275bb250606SChia-hung Duan   std::string varInit = kind == Kind::Operand ? "(op0->getOperands())" : "";
276bb250606SChia-hung Duan   return std::string(
277bb250606SChia-hung Duan       formatv("{0} {1}{2};\n", getVarTypeStr(name), getVarName(name), varInit));
278bb250606SChia-hung Duan }
279bb250606SChia-hung Duan 
getArgDecl(StringRef name) const280bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getArgDecl(StringRef name) const {
281bb250606SChia-hung Duan   LLVM_DEBUG(llvm::dbgs() << "getArgDecl for '" << name << "': ");
282bb250606SChia-hung Duan   return std::string(
283bb250606SChia-hung Duan       formatv("{0} &{1}", getVarTypeStr(name), getVarName(name)));
284bb250606SChia-hung Duan }
285bb250606SChia-hung Duan 
getValueAndRangeUse(StringRef name,int index,const char * fmt,const char * separator) const28612d16de5SRahul Joshi std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
28731cfee60SLei Zhang     StringRef name, int index, const char *fmt, const char *separator) const {
2881358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "getValueAndRangeUse for '" << name << "': ");
28931cfee60SLei Zhang   switch (kind) {
29031cfee60SLei Zhang   case Kind::Attr: {
29131cfee60SLei Zhang     assert(index < 0);
2921358df19SLei Zhang     auto repl = formatv(fmt, name);
2931358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Attr)\n");
294adcd0268SBenjamin Kramer     return std::string(repl);
29531cfee60SLei Zhang   }
29631cfee60SLei Zhang   case Kind::Operand: {
29731cfee60SLei Zhang     assert(index < 0);
298d7314b3cSChia-hung Duan     auto *operand = op->getArg(getArgIndex()).get<NamedTypeConstraint *>();
29931cfee60SLei Zhang     // If this operand is variadic, then return a range. Otherwise, return the
30031cfee60SLei Zhang     // value itself.
301aba1acc8SRiver Riddle     if (operand->isVariableLength()) {
3021358df19SLei Zhang       auto repl = formatv(fmt, name);
3031358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicOperand)\n");
304adcd0268SBenjamin Kramer       return std::string(repl);
30531cfee60SLei Zhang     }
3061358df19SLei Zhang     auto repl = formatv(fmt, formatv("(*{0}.begin())", name));
3071358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (SingleOperand)\n");
308adcd0268SBenjamin Kramer     return std::string(repl);
30931cfee60SLei Zhang   }
31031cfee60SLei Zhang   case Kind::Result: {
31131cfee60SLei Zhang     // If `index` is greater than zero, then we are referencing a specific
31231cfee60SLei Zhang     // result of a multi-result op. The result can still be variadic.
31331cfee60SLei Zhang     if (index >= 0) {
314adcd0268SBenjamin Kramer       std::string v =
315adcd0268SBenjamin Kramer           std::string(formatv("{0}.getODSResults({1})", name, index));
31631cfee60SLei Zhang       if (!op->getResult(index).isVariadic())
317adcd0268SBenjamin Kramer         v = std::string(formatv("(*{0}.begin())", v));
3181358df19SLei Zhang       auto repl = formatv(fmt, v);
3191358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
320adcd0268SBenjamin Kramer       return std::string(repl);
32131cfee60SLei Zhang     }
32231cfee60SLei Zhang 
32323d21af6SLei Zhang     // If this op has no result at all but still we bind a symbol to it, it
32423d21af6SLei Zhang     // means we want to capture the op itself.
32523d21af6SLei Zhang     if (op->getNumResults() == 0) {
32623d21af6SLei Zhang       LLVM_DEBUG(llvm::dbgs() << name << " (Op)\n");
3277b196f1bSMarkus Böck       return formatv(fmt, name);
32823d21af6SLei Zhang     }
32923d21af6SLei Zhang 
33031cfee60SLei Zhang     // We are referencing all results of the multi-result op. A specific result
33131cfee60SLei Zhang     // can either be a value or a range. Then join them with `separator`.
33231cfee60SLei Zhang     SmallVector<std::string, 4> values;
33331cfee60SLei Zhang     values.reserve(op->getNumResults());
33431cfee60SLei Zhang 
33531cfee60SLei Zhang     for (int i = 0, e = op->getNumResults(); i < e; ++i) {
336adcd0268SBenjamin Kramer       std::string v = std::string(formatv("{0}.getODSResults({1})", name, i));
33731cfee60SLei Zhang       if (!op->getResult(i).isVariadic()) {
338adcd0268SBenjamin Kramer         v = std::string(formatv("(*{0}.begin())", v));
33931cfee60SLei Zhang       }
340adcd0268SBenjamin Kramer       values.push_back(std::string(formatv(fmt, v)));
34131cfee60SLei Zhang     }
3421358df19SLei Zhang     auto repl = llvm::join(values, separator);
3431358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
3441358df19SLei Zhang     return repl;
34531cfee60SLei Zhang   }
34631cfee60SLei Zhang   case Kind::Value: {
34731cfee60SLei Zhang     assert(index < 0);
34831cfee60SLei Zhang     assert(op == nullptr);
3491358df19SLei Zhang     auto repl = formatv(fmt, name);
3501358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
351adcd0268SBenjamin Kramer     return std::string(repl);
35231cfee60SLei Zhang   }
353d7314b3cSChia-hung Duan   case Kind::MultipleValues: {
354d7314b3cSChia-hung Duan     assert(op == nullptr);
355d7314b3cSChia-hung Duan     assert(index < getSize());
356d7314b3cSChia-hung Duan     if (index >= 0) {
357d7314b3cSChia-hung Duan       std::string repl =
358d7314b3cSChia-hung Duan           formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));
359d7314b3cSChia-hung Duan       LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
360d7314b3cSChia-hung Duan       return repl;
361d7314b3cSChia-hung Duan     }
362d7314b3cSChia-hung Duan     // If it doesn't specify certain element, unpack them all.
363d7314b3cSChia-hung Duan     auto repl =
364d7314b3cSChia-hung Duan         formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
365d7314b3cSChia-hung Duan     LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
366d7314b3cSChia-hung Duan     return std::string(repl);
367d7314b3cSChia-hung Duan   }
36831cfee60SLei Zhang   }
36994298ceaSLei Zhang   llvm_unreachable("unknown kind");
37031cfee60SLei Zhang }
37131cfee60SLei Zhang 
getAllRangeUse(StringRef name,int index,const char * fmt,const char * separator) const37212d16de5SRahul Joshi std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(
37331cfee60SLei Zhang     StringRef name, int index, const char *fmt, const char *separator) const {
3741358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "getAllRangeUse for '" << name << "': ");
375ac68637bSLei Zhang   switch (kind) {
376ac68637bSLei Zhang   case Kind::Attr:
377ac68637bSLei Zhang   case Kind::Operand: {
378ac68637bSLei Zhang     assert(index < 0 && "only allowed for symbol bound to result");
3791358df19SLei Zhang     auto repl = formatv(fmt, name);
3801358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Operand/Attr)\n");
381adcd0268SBenjamin Kramer     return std::string(repl);
382ac68637bSLei Zhang   }
383ac68637bSLei Zhang   case Kind::Result: {
384ac68637bSLei Zhang     if (index >= 0) {
3851358df19SLei Zhang       auto repl = formatv(fmt, formatv("{0}.getODSResults({1})", name, index));
3861358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
387adcd0268SBenjamin Kramer       return std::string(repl);
388ac68637bSLei Zhang     }
389ac68637bSLei Zhang 
39031cfee60SLei Zhang     // We are referencing all results of the multi-result op. Each result should
39131cfee60SLei Zhang     // have a value range, and then join them with `separator`.
392ac68637bSLei Zhang     SmallVector<std::string, 4> values;
39331cfee60SLei Zhang     values.reserve(op->getNumResults());
39431cfee60SLei Zhang 
395ac68637bSLei Zhang     for (int i = 0, e = op->getNumResults(); i < e; ++i) {
396adcd0268SBenjamin Kramer       values.push_back(std::string(
397adcd0268SBenjamin Kramer           formatv(fmt, formatv("{0}.getODSResults({1})", name, i))));
398ac68637bSLei Zhang     }
3991358df19SLei Zhang     auto repl = llvm::join(values, separator);
4001358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
4011358df19SLei Zhang     return repl;
402ac68637bSLei Zhang   }
403ac68637bSLei Zhang   case Kind::Value: {
404ac68637bSLei Zhang     assert(index < 0 && "only allowed for symbol bound to result");
405ac68637bSLei Zhang     assert(op == nullptr);
40660f1d263SLei Zhang     auto repl = formatv(fmt, formatv("{{{0}}", name));
4071358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
408adcd0268SBenjamin Kramer     return std::string(repl);
409ac68637bSLei Zhang   }
410d7314b3cSChia-hung Duan   case Kind::MultipleValues: {
411d7314b3cSChia-hung Duan     assert(op == nullptr);
412d7314b3cSChia-hung Duan     assert(index < getSize());
413d7314b3cSChia-hung Duan     if (index >= 0) {
414d7314b3cSChia-hung Duan       std::string repl =
415d7314b3cSChia-hung Duan           formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));
416d7314b3cSChia-hung Duan       LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
417d7314b3cSChia-hung Duan       return repl;
418d7314b3cSChia-hung Duan     }
419d7314b3cSChia-hung Duan     auto repl =
420d7314b3cSChia-hung Duan         formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
421d7314b3cSChia-hung Duan     LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
422d7314b3cSChia-hung Duan     return std::string(repl);
423d7314b3cSChia-hung Duan   }
424ac68637bSLei Zhang   }
42512ff145eSjpienaar   llvm_unreachable("unknown kind");
426ac68637bSLei Zhang }
427ac68637bSLei Zhang 
bindOpArgument(DagNode node,StringRef symbol,const Operator & op,int argIndex)428b4001ae8SChia-hung Duan bool SymbolInfoMap::bindOpArgument(DagNode node, StringRef symbol,
429b4001ae8SChia-hung Duan                                    const Operator &op, int argIndex) {
430ac68637bSLei Zhang   StringRef name = getValuePackName(symbol);
431ac68637bSLei Zhang   if (name != symbol) {
432ac68637bSLei Zhang     auto error = formatv(
433ac68637bSLei Zhang         "symbol '{0}' with trailing index cannot bind to op argument", symbol);
434ac68637bSLei Zhang     PrintFatalError(loc, error);
435ac68637bSLei Zhang   }
436ac68637bSLei Zhang 
437ac68637bSLei Zhang   auto symInfo = op.getArg(argIndex).is<NamedAttribute *>()
438ac68637bSLei Zhang                      ? SymbolInfo::getAttr(&op, argIndex)
439b4001ae8SChia-hung Duan                      : SymbolInfo::getOperand(node, &op, argIndex);
440ac68637bSLei Zhang 
441008c0ea6Srdzhabarov   std::string key = symbol.str();
442008c0ea6Srdzhabarov   if (symbolInfoMap.count(key)) {
443008c0ea6Srdzhabarov     // Only non unique name for the operand is supported.
444008c0ea6Srdzhabarov     if (symInfo.kind != SymbolInfo::Kind::Operand) {
445008c0ea6Srdzhabarov       return false;
446008c0ea6Srdzhabarov     }
447008c0ea6Srdzhabarov 
448008c0ea6Srdzhabarov     // Cannot add new operand if there is already non operand with the same
449008c0ea6Srdzhabarov     // name.
450008c0ea6Srdzhabarov     if (symbolInfoMap.find(key)->second.kind != SymbolInfo::Kind::Operand) {
451008c0ea6Srdzhabarov       return false;
452008c0ea6Srdzhabarov     }
453008c0ea6Srdzhabarov   }
454008c0ea6Srdzhabarov 
455008c0ea6Srdzhabarov   symbolInfoMap.emplace(key, symInfo);
456008c0ea6Srdzhabarov   return true;
457ac68637bSLei Zhang }
458ac68637bSLei Zhang 
bindOpResult(StringRef symbol,const Operator & op)45912d16de5SRahul Joshi bool SymbolInfoMap::bindOpResult(StringRef symbol, const Operator &op) {
460008c0ea6Srdzhabarov   std::string name = getValuePackName(symbol).str();
461008c0ea6Srdzhabarov   auto inserted = symbolInfoMap.emplace(name, SymbolInfo::getResult(&op));
462008c0ea6Srdzhabarov 
463008c0ea6Srdzhabarov   return symbolInfoMap.count(inserted->first) == 1;
464ac68637bSLei Zhang }
465ac68637bSLei Zhang 
bindValues(StringRef symbol,int numValues)466d7314b3cSChia-hung Duan bool SymbolInfoMap::bindValues(StringRef symbol, int numValues) {
467d7314b3cSChia-hung Duan   std::string name = getValuePackName(symbol).str();
468d7314b3cSChia-hung Duan   if (numValues > 1)
469d7314b3cSChia-hung Duan     return bindMultipleValues(name, numValues);
470d7314b3cSChia-hung Duan   return bindValue(name);
471d7314b3cSChia-hung Duan }
472d7314b3cSChia-hung Duan 
bindValue(StringRef symbol)47312d16de5SRahul Joshi bool SymbolInfoMap::bindValue(StringRef symbol) {
474008c0ea6Srdzhabarov   auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getValue());
475008c0ea6Srdzhabarov   return symbolInfoMap.count(inserted->first) == 1;
476ac68637bSLei Zhang }
477ac68637bSLei Zhang 
bindMultipleValues(StringRef symbol,int numValues)478d7314b3cSChia-hung Duan bool SymbolInfoMap::bindMultipleValues(StringRef symbol, int numValues) {
479d7314b3cSChia-hung Duan   std::string name = getValuePackName(symbol).str();
480d7314b3cSChia-hung Duan   auto inserted =
481d7314b3cSChia-hung Duan       symbolInfoMap.emplace(name, SymbolInfo::getMultipleValues(numValues));
482d7314b3cSChia-hung Duan   return symbolInfoMap.count(inserted->first) == 1;
483d7314b3cSChia-hung Duan }
484d7314b3cSChia-hung Duan 
bindAttr(StringRef symbol)4852bf423b0SRob Suderman bool SymbolInfoMap::bindAttr(StringRef symbol) {
486ad1fe396SRob Suderman   auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getAttr());
4872bf423b0SRob Suderman   return symbolInfoMap.count(inserted->first) == 1;
4882bf423b0SRob Suderman }
4892bf423b0SRob Suderman 
contains(StringRef symbol) const49012d16de5SRahul Joshi bool SymbolInfoMap::contains(StringRef symbol) const {
491ac68637bSLei Zhang   return find(symbol) != symbolInfoMap.end();
492ac68637bSLei Zhang }
493ac68637bSLei Zhang 
find(StringRef key) const49412d16de5SRahul Joshi SymbolInfoMap::const_iterator SymbolInfoMap::find(StringRef key) const {
495008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
496008c0ea6Srdzhabarov 
497ac68637bSLei Zhang   return symbolInfoMap.find(name);
498ac68637bSLei Zhang }
499ac68637bSLei Zhang 
500008c0ea6Srdzhabarov SymbolInfoMap::const_iterator
findBoundSymbol(StringRef key,DagNode node,const Operator & op,int argIndex) const501b4001ae8SChia-hung Duan SymbolInfoMap::findBoundSymbol(StringRef key, DagNode node, const Operator &op,
502008c0ea6Srdzhabarov                                int argIndex) const {
503bb250606SChia-hung Duan   return findBoundSymbol(key, SymbolInfo::getOperand(node, &op, argIndex));
504bb250606SChia-hung Duan }
505bb250606SChia-hung Duan 
506bb250606SChia-hung Duan SymbolInfoMap::const_iterator
findBoundSymbol(StringRef key,const SymbolInfo & symbolInfo) const5071fc096afSMehdi Amini SymbolInfoMap::findBoundSymbol(StringRef key,
5081fc096afSMehdi Amini                                const SymbolInfo &symbolInfo) const {
509008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
510008c0ea6Srdzhabarov   auto range = symbolInfoMap.equal_range(name);
511008c0ea6Srdzhabarov 
512d7314b3cSChia-hung Duan   for (auto it = range.first; it != range.second; ++it)
513d7314b3cSChia-hung Duan     if (it->second.dagAndConstant == symbolInfo.dagAndConstant)
514008c0ea6Srdzhabarov       return it;
515008c0ea6Srdzhabarov 
516008c0ea6Srdzhabarov   return symbolInfoMap.end();
517008c0ea6Srdzhabarov }
518008c0ea6Srdzhabarov 
519008c0ea6Srdzhabarov std::pair<SymbolInfoMap::iterator, SymbolInfoMap::iterator>
getRangeOfEqualElements(StringRef key)520008c0ea6Srdzhabarov SymbolInfoMap::getRangeOfEqualElements(StringRef key) {
521008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
522008c0ea6Srdzhabarov 
523008c0ea6Srdzhabarov   return symbolInfoMap.equal_range(name);
524008c0ea6Srdzhabarov }
525008c0ea6Srdzhabarov 
count(StringRef key) const526008c0ea6Srdzhabarov int SymbolInfoMap::count(StringRef key) const {
527008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
528008c0ea6Srdzhabarov   return symbolInfoMap.count(name);
529008c0ea6Srdzhabarov }
530008c0ea6Srdzhabarov 
getStaticValueCount(StringRef symbol) const53112d16de5SRahul Joshi int SymbolInfoMap::getStaticValueCount(StringRef symbol) const {
532ac68637bSLei Zhang   StringRef name = getValuePackName(symbol);
533ac68637bSLei Zhang   if (name != symbol) {
534ac68637bSLei Zhang     // If there is a trailing index inside symbol, it references just one
535ac68637bSLei Zhang     // static value.
536ac68637bSLei Zhang     return 1;
537ac68637bSLei Zhang   }
538ac68637bSLei Zhang   // Otherwise, find how many it represents by querying the symbol's info.
539008c0ea6Srdzhabarov   return find(name)->second.getStaticValueCount();
540ac68637bSLei Zhang }
541ac68637bSLei Zhang 
getValueAndRangeUse(StringRef symbol,const char * fmt,const char * separator) const54212d16de5SRahul Joshi std::string SymbolInfoMap::getValueAndRangeUse(StringRef symbol,
54312d16de5SRahul Joshi                                                const char *fmt,
54431cfee60SLei Zhang                                                const char *separator) const {
545ac68637bSLei Zhang   int index = -1;
546ac68637bSLei Zhang   StringRef name = getValuePackName(symbol, &index);
547ac68637bSLei Zhang 
548008c0ea6Srdzhabarov   auto it = symbolInfoMap.find(name.str());
549ac68637bSLei Zhang   if (it == symbolInfoMap.end()) {
550ac68637bSLei Zhang     auto error = formatv("referencing unbound symbol '{0}'", symbol);
551ac68637bSLei Zhang     PrintFatalError(loc, error);
552ac68637bSLei Zhang   }
553ac68637bSLei Zhang 
554008c0ea6Srdzhabarov   return it->second.getValueAndRangeUse(name, index, fmt, separator);
55531cfee60SLei Zhang }
55631cfee60SLei Zhang 
getAllRangeUse(StringRef symbol,const char * fmt,const char * separator) const55712d16de5SRahul Joshi std::string SymbolInfoMap::getAllRangeUse(StringRef symbol, const char *fmt,
55831cfee60SLei Zhang                                           const char *separator) const {
55931cfee60SLei Zhang   int index = -1;
56031cfee60SLei Zhang   StringRef name = getValuePackName(symbol, &index);
56131cfee60SLei Zhang 
562008c0ea6Srdzhabarov   auto it = symbolInfoMap.find(name.str());
56331cfee60SLei Zhang   if (it == symbolInfoMap.end()) {
56431cfee60SLei Zhang     auto error = formatv("referencing unbound symbol '{0}'", symbol);
56531cfee60SLei Zhang     PrintFatalError(loc, error);
56631cfee60SLei Zhang   }
56731cfee60SLei Zhang 
568008c0ea6Srdzhabarov   return it->second.getAllRangeUse(name, index, fmt, separator);
569008c0ea6Srdzhabarov }
570008c0ea6Srdzhabarov 
assignUniqueAlternativeNames()571008c0ea6Srdzhabarov void SymbolInfoMap::assignUniqueAlternativeNames() {
572008c0ea6Srdzhabarov   llvm::StringSet<> usedNames;
573008c0ea6Srdzhabarov 
574008c0ea6Srdzhabarov   for (auto symbolInfoIt = symbolInfoMap.begin();
575008c0ea6Srdzhabarov        symbolInfoIt != symbolInfoMap.end();) {
576008c0ea6Srdzhabarov     auto range = symbolInfoMap.equal_range(symbolInfoIt->first);
577008c0ea6Srdzhabarov     auto startRange = range.first;
578008c0ea6Srdzhabarov     auto endRange = range.second;
579008c0ea6Srdzhabarov 
580008c0ea6Srdzhabarov     auto operandName = symbolInfoIt->first;
581008c0ea6Srdzhabarov     int startSearchIndex = 0;
582008c0ea6Srdzhabarov     for (++startRange; startRange != endRange; ++startRange) {
583008c0ea6Srdzhabarov       // Current operand name is not unique, find a unique one
584008c0ea6Srdzhabarov       // and set the alternative name.
585008c0ea6Srdzhabarov       for (int i = startSearchIndex;; ++i) {
586008c0ea6Srdzhabarov         std::string alternativeName = operandName + std::to_string(i);
587008c0ea6Srdzhabarov         if (!usedNames.contains(alternativeName) &&
588008c0ea6Srdzhabarov             symbolInfoMap.count(alternativeName) == 0) {
589008c0ea6Srdzhabarov           usedNames.insert(alternativeName);
590008c0ea6Srdzhabarov           startRange->second.alternativeName = alternativeName;
591008c0ea6Srdzhabarov           startSearchIndex = i + 1;
592008c0ea6Srdzhabarov 
593008c0ea6Srdzhabarov           break;
594008c0ea6Srdzhabarov         }
595008c0ea6Srdzhabarov       }
596008c0ea6Srdzhabarov     }
597008c0ea6Srdzhabarov 
598008c0ea6Srdzhabarov     symbolInfoIt = endRange;
599008c0ea6Srdzhabarov   }
600ac68637bSLei Zhang }
601ac68637bSLei Zhang 
602ac68637bSLei Zhang //===----------------------------------------------------------------------===//
603ac68637bSLei Zhang // Pattern
604ac68637bSLei Zhang //==----------------------------------------------------------------------===//
605ac68637bSLei Zhang 
Pattern(const llvm::Record * def,RecordOperatorMap * mapper)60612d16de5SRahul Joshi Pattern::Pattern(const llvm::Record *def, RecordOperatorMap *mapper)
607ac68637bSLei Zhang     : def(*def), recordOpMap(mapper) {}
608eb753f4aSLei Zhang 
getSourcePattern() const60912d16de5SRahul Joshi DagNode Pattern::getSourcePattern() const {
61012d16de5SRahul Joshi   return DagNode(def.getValueAsDag("sourcePattern"));
611eb753f4aSLei Zhang }
612eb753f4aSLei Zhang 
getNumResultPatterns() const61312d16de5SRahul Joshi int Pattern::getNumResultPatterns() const {
6148f5fa566SLei Zhang   auto *results = def.getValueAsListInit("resultPatterns");
615eb753f4aSLei Zhang   return results->size();
616eb753f4aSLei Zhang }
617eb753f4aSLei Zhang 
getResultPattern(unsigned index) const61812d16de5SRahul Joshi DagNode Pattern::getResultPattern(unsigned index) const {
6198f5fa566SLei Zhang   auto *results = def.getValueAsListInit("resultPatterns");
62012d16de5SRahul Joshi   return DagNode(cast<llvm::DagInit>(results->getElement(index)));
621eb753f4aSLei Zhang }
622eb753f4aSLei Zhang 
collectSourcePatternBoundSymbols(SymbolInfoMap & infoMap)62312d16de5SRahul Joshi void Pattern::collectSourcePatternBoundSymbols(SymbolInfoMap &infoMap) {
6241358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "start collecting source pattern bound symbols\n");
625ac68637bSLei Zhang   collectBoundSymbols(getSourcePattern(), infoMap, /*isSrcPattern=*/true);
6261358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "done collecting source pattern bound symbols\n");
627008c0ea6Srdzhabarov 
628008c0ea6Srdzhabarov   LLVM_DEBUG(llvm::dbgs() << "start assigning alternative names for symbols\n");
629008c0ea6Srdzhabarov   infoMap.assignUniqueAlternativeNames();
630008c0ea6Srdzhabarov   LLVM_DEBUG(llvm::dbgs() << "done assigning alternative names for symbols\n");
631eb753f4aSLei Zhang }
632eb753f4aSLei Zhang 
collectResultPatternBoundSymbols(SymbolInfoMap & infoMap)63312d16de5SRahul Joshi void Pattern::collectResultPatternBoundSymbols(SymbolInfoMap &infoMap) {
6341358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "start collecting result pattern bound symbols\n");
635ac68637bSLei Zhang   for (int i = 0, e = getNumResultPatterns(); i < e; ++i) {
636ac68637bSLei Zhang     auto pattern = getResultPattern(i);
637ac68637bSLei Zhang     collectBoundSymbols(pattern, infoMap, /*isSrcPattern=*/false);
638eb753f4aSLei Zhang   }
6391358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "done collecting result pattern bound symbols\n");
640388fb375SJacques Pienaar }
641388fb375SJacques Pienaar 
getSourceRootOp()64212d16de5SRahul Joshi const Operator &Pattern::getSourceRootOp() {
643eb753f4aSLei Zhang   return getSourcePattern().getDialectOp(recordOpMap);
644eb753f4aSLei Zhang }
645eb753f4aSLei Zhang 
getDialectOp(DagNode node)64612d16de5SRahul Joshi Operator &Pattern::getDialectOp(DagNode node) {
647eb753f4aSLei Zhang   return node.getDialectOp(recordOpMap);
648eb753f4aSLei Zhang }
649388fb375SJacques Pienaar 
getConstraints() const65012d16de5SRahul Joshi std::vector<AppliedConstraint> Pattern::getConstraints() const {
651388fb375SJacques Pienaar   auto *listInit = def.getValueAsListInit("constraints");
65212d16de5SRahul Joshi   std::vector<AppliedConstraint> ret;
653388fb375SJacques Pienaar   ret.reserve(listInit->size());
6548f5fa566SLei Zhang 
65502b6fb21SMehdi Amini   for (auto *it : *listInit) {
6568f5fa566SLei Zhang     auto *dagInit = dyn_cast<llvm::DagInit>(it);
6578f5fa566SLei Zhang     if (!dagInit)
6582bf423b0SRob Suderman       PrintFatalError(&def, "all elements in Pattern multi-entity "
6598f5fa566SLei Zhang                             "constraints should be DAG nodes");
6608f5fa566SLei Zhang 
6618f5fa566SLei Zhang     std::vector<std::string> entities;
6628f5fa566SLei Zhang     entities.reserve(dagInit->arg_size());
663cb40e36dSLei Zhang     for (auto *argName : dagInit->getArgNames()) {
664cb40e36dSLei Zhang       if (!argName) {
665cb40e36dSLei Zhang         PrintFatalError(
6662bf423b0SRob Suderman             &def,
667cb40e36dSLei Zhang             "operands to additional constraints can only be symbol references");
668cb40e36dSLei Zhang       }
669e5639b3fSMehdi Amini       entities.emplace_back(argName->getValue());
670cb40e36dSLei Zhang     }
6718f5fa566SLei Zhang 
6728f5fa566SLei Zhang     ret.emplace_back(cast<llvm::DefInit>(dagInit->getOperator())->getDef(),
673c72d849eSLei Zhang                      dagInit->getNameStr(), std::move(entities));
674388fb375SJacques Pienaar   }
675388fb375SJacques Pienaar   return ret;
676388fb375SJacques Pienaar }
67753035874SFeng Liu 
getBenefit() const67812d16de5SRahul Joshi int Pattern::getBenefit() const {
679a0606ca7SFeng Liu   // The initial benefit value is a heuristic with number of ops in the source
68053035874SFeng Liu   // pattern.
681a0606ca7SFeng Liu   int initBenefit = getSourcePattern().getNumOps();
68253035874SFeng Liu   llvm::DagInit *delta = def.getValueAsDag("benefitDelta");
683a0606ca7SFeng Liu   if (delta->getNumArgs() != 1 || !isa<llvm::IntInit>(delta->getArg(0))) {
6842bf423b0SRob Suderman     PrintFatalError(&def,
685a0606ca7SFeng Liu                     "The 'addBenefit' takes and only takes one integer value");
686a0606ca7SFeng Liu   }
687a0606ca7SFeng Liu   return initBenefit + dyn_cast<llvm::IntInit>(delta->getArg(0))->getValue();
68853035874SFeng Liu }
68904b6d2f3SLei Zhang 
getLocation() const69012d16de5SRahul Joshi std::vector<Pattern::IdentifierLine> Pattern::getLocation() const {
6914165885aSJacques Pienaar   std::vector<std::pair<StringRef, unsigned>> result;
6924165885aSJacques Pienaar   result.reserve(def.getLoc().size());
6934165885aSJacques Pienaar   for (auto loc : def.getLoc()) {
6944165885aSJacques Pienaar     unsigned buf = llvm::SrcMgr.FindBufferContainingLoc(loc);
6954165885aSJacques Pienaar     assert(buf && "invalid source location");
6964165885aSJacques Pienaar     result.emplace_back(
6974165885aSJacques Pienaar         llvm::SrcMgr.getBufferInfo(buf).Buffer->getBufferIdentifier(),
6984165885aSJacques Pienaar         llvm::SrcMgr.getLineAndColumn(loc, buf).first);
6994165885aSJacques Pienaar   }
7004165885aSJacques Pienaar   return result;
7014165885aSJacques Pienaar }
7024165885aSJacques Pienaar 
verifyBind(bool result,StringRef symbolName)7032bf423b0SRob Suderman void Pattern::verifyBind(bool result, StringRef symbolName) {
7042bf423b0SRob Suderman   if (!result) {
7052bf423b0SRob Suderman     auto err = formatv("symbol '{0}' bound more than once", symbolName);
7062bf423b0SRob Suderman     PrintFatalError(&def, err);
7072bf423b0SRob Suderman   }
7082bf423b0SRob Suderman }
7092bf423b0SRob Suderman 
collectBoundSymbols(DagNode tree,SymbolInfoMap & infoMap,bool isSrcPattern)71012d16de5SRahul Joshi void Pattern::collectBoundSymbols(DagNode tree, SymbolInfoMap &infoMap,
711e032d0dcSLei Zhang                                   bool isSrcPattern) {
712e032d0dcSLei Zhang   auto treeName = tree.getSymbol();
7132bf423b0SRob Suderman   auto numTreeArgs = tree.getNumArgs();
7142bf423b0SRob Suderman 
7152bf423b0SRob Suderman   if (tree.isNativeCodeCall()) {
716e032d0dcSLei Zhang     if (!treeName.empty()) {
71734b5482bSChia-hung Duan       if (!isSrcPattern) {
71834b5482bSChia-hung Duan         LLVM_DEBUG(llvm::dbgs() << "found symbol bound to NativeCodeCall: "
71934b5482bSChia-hung Duan                                 << treeName << '\n');
720d7314b3cSChia-hung Duan         verifyBind(
721d7314b3cSChia-hung Duan             infoMap.bindValues(treeName, tree.getNumReturnsOfNativeCode()),
722d7314b3cSChia-hung Duan             treeName);
72334b5482bSChia-hung Duan       } else {
72434b5482bSChia-hung Duan         PrintFatalError(&def,
72534b5482bSChia-hung Duan                         formatv("binding symbol '{0}' to NativecodeCall in "
72634b5482bSChia-hung Duan                                 "MatchPattern is not supported",
727e032d0dcSLei Zhang                                 treeName));
728e032d0dcSLei Zhang       }
72934b5482bSChia-hung Duan     }
7302bf423b0SRob Suderman 
7312bf423b0SRob Suderman     for (int i = 0; i != numTreeArgs; ++i) {
7322bf423b0SRob Suderman       if (auto treeArg = tree.getArgAsNestedDag(i)) {
7332bf423b0SRob Suderman         // This DAG node argument is a DAG node itself. Go inside recursively.
7342bf423b0SRob Suderman         collectBoundSymbols(treeArg, infoMap, isSrcPattern);
7352bf423b0SRob Suderman         continue;
7362bf423b0SRob Suderman       }
7372bf423b0SRob Suderman 
7382bf423b0SRob Suderman       if (!isSrcPattern)
7392bf423b0SRob Suderman         continue;
7402bf423b0SRob Suderman 
7412bf423b0SRob Suderman       // We can only bind symbols to arguments in source pattern. Those
7422bf423b0SRob Suderman       // symbols are referenced in result patterns.
7432bf423b0SRob Suderman       auto treeArgName = tree.getArgName(i);
7442bf423b0SRob Suderman 
7452bf423b0SRob Suderman       // `$_` is a special symbol meaning ignore the current argument.
7462bf423b0SRob Suderman       if (!treeArgName.empty() && treeArgName != "_") {
7472bf423b0SRob Suderman         DagLeaf leaf = tree.getArgAsLeaf(i);
74834b5482bSChia-hung Duan 
74934b5482bSChia-hung Duan         // In (NativeCodeCall<"Foo($_self, $0, $1, $2)"> I8Attr:$a, I8:$b, $c),
75034b5482bSChia-hung Duan         if (leaf.isUnspecified()) {
75134b5482bSChia-hung Duan           // This is case of $c, a Value without any constraints.
75234b5482bSChia-hung Duan           verifyBind(infoMap.bindValue(treeArgName), treeArgName);
75334b5482bSChia-hung Duan         } else {
7542bf423b0SRob Suderman           auto constraint = leaf.getAsConstraint();
7552bf423b0SRob Suderman           bool isAttr = leaf.isAttrMatcher() || leaf.isEnumAttrCase() ||
7562bf423b0SRob Suderman                         leaf.isConstantAttr() ||
7572bf423b0SRob Suderman                         constraint.getKind() == Constraint::Kind::CK_Attr;
7582bf423b0SRob Suderman 
7592bf423b0SRob Suderman           if (isAttr) {
76034b5482bSChia-hung Duan             // This is case of $a, a binding to a certain attribute.
7612bf423b0SRob Suderman             verifyBind(infoMap.bindAttr(treeArgName), treeArgName);
7622bf423b0SRob Suderman             continue;
7632bf423b0SRob Suderman           }
7642bf423b0SRob Suderman 
76534b5482bSChia-hung Duan           // This is case of $b, a binding to a certain type.
7662bf423b0SRob Suderman           verifyBind(infoMap.bindValue(treeArgName), treeArgName);
7672bf423b0SRob Suderman         }
7682bf423b0SRob Suderman       }
76934b5482bSChia-hung Duan     }
7702bf423b0SRob Suderman 
771e032d0dcSLei Zhang     return;
772e032d0dcSLei Zhang   }
773e032d0dcSLei Zhang 
7742bf423b0SRob Suderman   if (tree.isOperation()) {
77504b6d2f3SLei Zhang     auto &op = getDialectOp(tree);
77604b6d2f3SLei Zhang     auto numOpArgs = op.getNumArgs();
7772d99c815SChia-hung Duan     int numEither = 0;
77804b6d2f3SLei Zhang 
7792d99c815SChia-hung Duan     // We need to exclude the trailing directives and `either` directive groups
7802d99c815SChia-hung Duan     // two operands of the operation.
781cb8c30d3SMogball     int numDirectives = 0;
782cb8c30d3SMogball     for (int i = numTreeArgs - 1; i >= 0; --i) {
783cb8c30d3SMogball       if (auto dagArg = tree.getArgAsNestedDag(i)) {
784cb8c30d3SMogball         if (dagArg.isLocationDirective() || dagArg.isReturnTypeDirective())
785cb8c30d3SMogball           ++numDirectives;
7862d99c815SChia-hung Duan         else if (dagArg.isEither())
7872d99c815SChia-hung Duan           ++numEither;
788cb8c30d3SMogball       }
7893f7439b2SJacques Pienaar     }
7903f7439b2SJacques Pienaar 
7912d99c815SChia-hung Duan     if (numOpArgs != numTreeArgs - numDirectives + numEither) {
7922d99c815SChia-hung Duan       auto err =
7932d99c815SChia-hung Duan           formatv("op '{0}' argument number mismatch: "
79404b6d2f3SLei Zhang                   "{1} in pattern vs. {2} in definition",
7952d99c815SChia-hung Duan                   op.getOperationName(), numTreeArgs + numEither, numOpArgs);
7962bf423b0SRob Suderman       PrintFatalError(&def, err);
79704b6d2f3SLei Zhang     }
79804b6d2f3SLei Zhang 
79904b6d2f3SLei Zhang     // The name attached to the DAG node's operator is for representing the
80004b6d2f3SLei Zhang     // results generated from this op. It should be remembered as bound results.
801ac68637bSLei Zhang     if (!treeName.empty()) {
8021358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs()
8031358df19SLei Zhang                  << "found symbol bound to op result: " << treeName << '\n');
8042bf423b0SRob Suderman       verifyBind(infoMap.bindOpResult(treeName, op), treeName);
805ac68637bSLei Zhang     }
80604b6d2f3SLei Zhang 
8072d99c815SChia-hung Duan     // The operand in `either` DAG should be bound to the operation in the
8082d99c815SChia-hung Duan     // parent DagNode.
8092d99c815SChia-hung Duan     auto collectSymbolInEither = [&](DagNode parent, DagNode tree,
8102d99c815SChia-hung Duan                                      int &opArgIdx) {
8112d99c815SChia-hung Duan       for (int i = 0; i < tree.getNumArgs(); ++i, ++opArgIdx) {
8122d99c815SChia-hung Duan         if (DagNode subTree = tree.getArgAsNestedDag(i)) {
8132d99c815SChia-hung Duan           collectBoundSymbols(subTree, infoMap, isSrcPattern);
8142d99c815SChia-hung Duan         } else {
8152d99c815SChia-hung Duan           auto argName = tree.getArgName(i);
8162d99c815SChia-hung Duan           if (!argName.empty() && argName != "_")
8172d99c815SChia-hung Duan             verifyBind(infoMap.bindOpArgument(parent, argName, op, opArgIdx),
8182d99c815SChia-hung Duan                        argName);
8192d99c815SChia-hung Duan         }
8202d99c815SChia-hung Duan       }
8212d99c815SChia-hung Duan     };
8222d99c815SChia-hung Duan 
8232d99c815SChia-hung Duan     for (int i = 0, opArgIdx = 0; i != numTreeArgs; ++i, ++opArgIdx) {
82404b6d2f3SLei Zhang       if (auto treeArg = tree.getArgAsNestedDag(i)) {
8252d99c815SChia-hung Duan         if (treeArg.isEither()) {
8262d99c815SChia-hung Duan           collectSymbolInEither(tree, treeArg, opArgIdx);
8272d99c815SChia-hung Duan         } else {
82804b6d2f3SLei Zhang           // This DAG node argument is a DAG node itself. Go inside recursively.
829ac68637bSLei Zhang           collectBoundSymbols(treeArg, infoMap, isSrcPattern);
8302d99c815SChia-hung Duan         }
8312bf423b0SRob Suderman         continue;
8322bf423b0SRob Suderman       }
8332bf423b0SRob Suderman 
8342bf423b0SRob Suderman       if (isSrcPattern) {
835e032d0dcSLei Zhang         // We can only bind symbols to op arguments in source pattern. Those
836e032d0dcSLei Zhang         // symbols are referenced in result patterns.
83704b6d2f3SLei Zhang         auto treeArgName = tree.getArgName(i);
8384982eaf8SLei Zhang         // `$_` is a special symbol meaning ignore the current argument.
8394982eaf8SLei Zhang         if (!treeArgName.empty() && treeArgName != "_") {
8401358df19SLei Zhang           LLVM_DEBUG(llvm::dbgs() << "found symbol bound to op argument: "
8411358df19SLei Zhang                                   << treeArgName << '\n');
8422d99c815SChia-hung Duan           verifyBind(infoMap.bindOpArgument(tree, treeArgName, op, opArgIdx),
843b4001ae8SChia-hung Duan                      treeArgName);
844ac68637bSLei Zhang         }
845ac68637bSLei Zhang       }
84604b6d2f3SLei Zhang     }
8472bf423b0SRob Suderman     return;
84804b6d2f3SLei Zhang   }
8492bf423b0SRob Suderman 
8502bf423b0SRob Suderman   if (!treeName.empty()) {
8512bf423b0SRob Suderman     PrintFatalError(
8522bf423b0SRob Suderman         &def, formatv("binding symbol '{0}' to non-operation/native code call "
8532bf423b0SRob Suderman                       "unsupported right now",
8542bf423b0SRob Suderman                       treeName));
8552bf423b0SRob Suderman   }
85604b6d2f3SLei Zhang }
857