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 
14eb753f4aSLei Zhang #include "mlir/TableGen/Pattern.h"
15b12a7c88SMehdi Amini #include "llvm/ADT/StringExtras.h"
16eb753f4aSLei Zhang #include "llvm/ADT/Twine.h"
171358df19SLei Zhang #include "llvm/Support/Debug.h"
1804b6d2f3SLei Zhang #include "llvm/Support/FormatVariadic.h"
198f5fa566SLei Zhang #include "llvm/TableGen/Error.h"
20eb753f4aSLei Zhang #include "llvm/TableGen/Record.h"
21eb753f4aSLei Zhang 
221358df19SLei Zhang #define DEBUG_TYPE "mlir-tblgen-pattern"
231358df19SLei Zhang 
24eb753f4aSLei Zhang using namespace mlir;
2512d16de5SRahul Joshi using namespace tblgen;
26eb753f4aSLei Zhang 
270ea6154bSJacques Pienaar using llvm::formatv;
28eb753f4aSLei Zhang 
29ac68637bSLei Zhang //===----------------------------------------------------------------------===//
30ac68637bSLei Zhang // DagLeaf
31ac68637bSLei Zhang //===----------------------------------------------------------------------===//
32ac68637bSLei Zhang 
3312d16de5SRahul Joshi bool DagLeaf::isUnspecified() const {
34b9e38a79SLei Zhang   return dyn_cast_or_null<llvm::UnsetInit>(def);
35e0774c00SLei Zhang }
36e0774c00SLei Zhang 
3712d16de5SRahul Joshi bool DagLeaf::isOperandMatcher() const {
38e0774c00SLei Zhang   // Operand matchers specify a type constraint.
39b9e38a79SLei Zhang   return isSubClassOf("TypeConstraint");
40e0774c00SLei Zhang }
41e0774c00SLei Zhang 
4212d16de5SRahul Joshi bool DagLeaf::isAttrMatcher() const {
43c52a8127SFeng Liu   // Attribute matchers specify an attribute constraint.
44b9e38a79SLei Zhang   return isSubClassOf("AttrConstraint");
45e0774c00SLei Zhang }
46e0774c00SLei Zhang 
4712d16de5SRahul Joshi bool DagLeaf::isNativeCodeCall() const {
48d0e2019dSLei Zhang   return isSubClassOf("NativeCodeCall");
49e0774c00SLei Zhang }
50e0774c00SLei Zhang 
5112d16de5SRahul Joshi bool DagLeaf::isConstantAttr() const { return isSubClassOf("ConstantAttr"); }
52b9e38a79SLei Zhang 
5312d16de5SRahul Joshi bool DagLeaf::isEnumAttrCase() const {
549dd182e0SLei Zhang   return isSubClassOf("EnumAttrCaseInfo");
55e0774c00SLei Zhang }
56e0774c00SLei Zhang 
57cb8c30d3SMogball bool DagLeaf::isStringAttr() const { return isa<llvm::StringInit>(def); }
58d6b32e39SJacques Pienaar 
5912d16de5SRahul Joshi Constraint DagLeaf::getAsConstraint() const {
608f5fa566SLei Zhang   assert((isOperandMatcher() || isAttrMatcher()) &&
618f5fa566SLei Zhang          "the DAG leaf must be operand or attribute");
628f5fa566SLei Zhang   return Constraint(cast<llvm::DefInit>(def)->getDef());
63e0774c00SLei Zhang }
64e0774c00SLei Zhang 
6512d16de5SRahul Joshi ConstantAttr DagLeaf::getAsConstantAttr() const {
66e0774c00SLei Zhang   assert(isConstantAttr() && "the DAG leaf must be constant attribute");
67e0774c00SLei Zhang   return ConstantAttr(cast<llvm::DefInit>(def));
68e0774c00SLei Zhang }
69e0774c00SLei Zhang 
7012d16de5SRahul Joshi EnumAttrCase DagLeaf::getAsEnumAttrCase() const {
71b9e38a79SLei Zhang   assert(isEnumAttrCase() && "the DAG leaf must be an enum attribute case");
72b9e38a79SLei Zhang   return EnumAttrCase(cast<llvm::DefInit>(def));
73b9e38a79SLei Zhang }
74b9e38a79SLei Zhang 
7512d16de5SRahul Joshi std::string DagLeaf::getConditionTemplate() const {
768f5fa566SLei Zhang   return getAsConstraint().getConditionTemplate();
77e0774c00SLei Zhang }
78e0774c00SLei Zhang 
7912d16de5SRahul Joshi llvm::StringRef DagLeaf::getNativeCodeTemplate() const {
80d0e2019dSLei Zhang   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
81d0e2019dSLei Zhang   return cast<llvm::DefInit>(def)->getDef()->getValueAsString("expression");
82eb753f4aSLei Zhang }
83eb753f4aSLei Zhang 
84d7314b3cSChia-hung Duan int DagLeaf::getNumReturnsOfNativeCode() const {
85d7314b3cSChia-hung Duan   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
86d7314b3cSChia-hung Duan   return cast<llvm::DefInit>(def)->getDef()->getValueAsInt("numReturns");
87d7314b3cSChia-hung Duan }
88d7314b3cSChia-hung Duan 
8912d16de5SRahul Joshi std::string DagLeaf::getStringAttr() const {
90d6b32e39SJacques Pienaar   assert(isStringAttr() && "the DAG leaf must be string attribute");
91d6b32e39SJacques Pienaar   return def->getAsUnquotedString();
92d6b32e39SJacques Pienaar }
9312d16de5SRahul Joshi bool DagLeaf::isSubClassOf(StringRef superclass) const {
94b9e38a79SLei Zhang   if (auto *defInit = dyn_cast_or_null<llvm::DefInit>(def))
95b9e38a79SLei Zhang     return defInit->getDef()->isSubClassOf(superclass);
96b9e38a79SLei Zhang   return false;
97b9e38a79SLei Zhang }
98b9e38a79SLei Zhang 
9912d16de5SRahul Joshi void DagLeaf::print(raw_ostream &os) const {
1001358df19SLei Zhang   if (def)
1011358df19SLei Zhang     def->print(os);
1021358df19SLei Zhang }
1031358df19SLei Zhang 
104ac68637bSLei Zhang //===----------------------------------------------------------------------===//
105ac68637bSLei Zhang // DagNode
106ac68637bSLei Zhang //===----------------------------------------------------------------------===//
107ac68637bSLei Zhang 
10812d16de5SRahul Joshi bool DagNode::isNativeCodeCall() const {
109d0e2019dSLei Zhang   if (auto *defInit = dyn_cast_or_null<llvm::DefInit>(node->getOperator()))
110d0e2019dSLei Zhang     return defInit->getDef()->isSubClassOf("NativeCodeCall");
111c52a8127SFeng Liu   return false;
112c52a8127SFeng Liu }
113c52a8127SFeng Liu 
11412d16de5SRahul Joshi bool DagNode::isOperation() const {
115cb8c30d3SMogball   return !isNativeCodeCall() && !isReplaceWithValue() &&
116cb8c30d3SMogball          !isLocationDirective() && !isReturnTypeDirective();
117647f8cabSRiver Riddle }
118647f8cabSRiver Riddle 
11912d16de5SRahul Joshi llvm::StringRef DagNode::getNativeCodeTemplate() const {
120d0e2019dSLei Zhang   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
121c52a8127SFeng Liu   return cast<llvm::DefInit>(node->getOperator())
122c52a8127SFeng Liu       ->getDef()
123d0e2019dSLei Zhang       ->getValueAsString("expression");
124c52a8127SFeng Liu }
125c52a8127SFeng Liu 
126d7314b3cSChia-hung Duan int DagNode::getNumReturnsOfNativeCode() const {
127d7314b3cSChia-hung Duan   assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
128d7314b3cSChia-hung Duan   return cast<llvm::DefInit>(node->getOperator())
129d7314b3cSChia-hung Duan       ->getDef()
130d7314b3cSChia-hung Duan       ->getValueAsInt("numReturns");
131d7314b3cSChia-hung Duan }
132d7314b3cSChia-hung Duan 
13312d16de5SRahul Joshi llvm::StringRef DagNode::getSymbol() const { return node->getNameStr(); }
134388fb375SJacques Pienaar 
13512d16de5SRahul Joshi Operator &DagNode::getDialectOp(RecordOperatorMap *mapper) const {
136eb753f4aSLei Zhang   llvm::Record *opDef = cast<llvm::DefInit>(node->getOperator())->getDef();
1372dc6d205SLei Zhang   auto it = mapper->find(opDef);
1382dc6d205SLei Zhang   if (it != mapper->end())
1392dc6d205SLei Zhang     return *it->second;
14079f53b0cSJacques Pienaar   return *mapper->try_emplace(opDef, std::make_unique<Operator>(opDef))
1412dc6d205SLei Zhang               .first->second;
142eb753f4aSLei Zhang }
143eb753f4aSLei Zhang 
14412d16de5SRahul Joshi int DagNode::getNumOps() const {
1452fe8ae4fSJacques Pienaar   int count = isReplaceWithValue() ? 0 : 1;
1462fe8ae4fSJacques Pienaar   for (int i = 0, e = getNumArgs(); i != e; ++i) {
147eb753f4aSLei Zhang     if (auto child = getArgAsNestedDag(i))
148eb753f4aSLei Zhang       count += child.getNumOps();
149eb753f4aSLei Zhang   }
150eb753f4aSLei Zhang   return count;
151eb753f4aSLei Zhang }
152eb753f4aSLei Zhang 
15312d16de5SRahul Joshi int DagNode::getNumArgs() const { return node->getNumArgs(); }
154eb753f4aSLei Zhang 
15512d16de5SRahul Joshi bool DagNode::isNestedDagArg(unsigned index) const {
156eb753f4aSLei Zhang   return isa<llvm::DagInit>(node->getArg(index));
157eb753f4aSLei Zhang }
158eb753f4aSLei Zhang 
15912d16de5SRahul Joshi DagNode DagNode::getArgAsNestedDag(unsigned index) const {
160eb753f4aSLei Zhang   return DagNode(dyn_cast_or_null<llvm::DagInit>(node->getArg(index)));
161eb753f4aSLei Zhang }
162eb753f4aSLei Zhang 
16312d16de5SRahul Joshi DagLeaf DagNode::getArgAsLeaf(unsigned index) const {
164e0774c00SLei Zhang   assert(!isNestedDagArg(index));
165e0774c00SLei Zhang   return DagLeaf(node->getArg(index));
166eb753f4aSLei Zhang }
167eb753f4aSLei Zhang 
16812d16de5SRahul Joshi StringRef DagNode::getArgName(unsigned index) const {
169eb753f4aSLei Zhang   return node->getArgNameStr(index);
170eb753f4aSLei Zhang }
171eb753f4aSLei Zhang 
17212d16de5SRahul Joshi bool DagNode::isReplaceWithValue() const {
173eb753f4aSLei Zhang   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
174eb753f4aSLei Zhang   return dagOpDef->getName() == "replaceWithValue";
175eb753f4aSLei Zhang }
176eb753f4aSLei Zhang 
17712d16de5SRahul Joshi bool DagNode::isLocationDirective() const {
1783f7439b2SJacques Pienaar   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
1793f7439b2SJacques Pienaar   return dagOpDef->getName() == "location";
1803f7439b2SJacques Pienaar }
1813f7439b2SJacques Pienaar 
182cb8c30d3SMogball bool DagNode::isReturnTypeDirective() const {
183cb8c30d3SMogball   auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
184cb8c30d3SMogball   return dagOpDef->getName() == "returnType";
185cb8c30d3SMogball }
186cb8c30d3SMogball 
18712d16de5SRahul Joshi void DagNode::print(raw_ostream &os) const {
1881358df19SLei Zhang   if (node)
1891358df19SLei Zhang     node->print(os);
1901358df19SLei Zhang }
1911358df19SLei Zhang 
192ac68637bSLei Zhang //===----------------------------------------------------------------------===//
193ac68637bSLei Zhang // SymbolInfoMap
194ac68637bSLei Zhang //===----------------------------------------------------------------------===//
195ac68637bSLei Zhang 
19612d16de5SRahul Joshi StringRef SymbolInfoMap::getValuePackName(StringRef symbol, int *index) {
197ac68637bSLei Zhang   StringRef name, indexStr;
198ac68637bSLei Zhang   int idx = -1;
199ac68637bSLei Zhang   std::tie(name, indexStr) = symbol.rsplit("__");
200ac68637bSLei Zhang 
201ac68637bSLei Zhang   if (indexStr.consumeInteger(10, idx)) {
202ac68637bSLei Zhang     // The second part is not an index; we return the whole symbol as-is.
203ac68637bSLei Zhang     return symbol;
204eb753f4aSLei Zhang   }
205ac68637bSLei Zhang   if (index) {
206ac68637bSLei Zhang     *index = idx;
207ac68637bSLei Zhang   }
208ac68637bSLei Zhang   return name;
209ac68637bSLei Zhang }
210ac68637bSLei Zhang 
21112d16de5SRahul Joshi SymbolInfoMap::SymbolInfo::SymbolInfo(const Operator *op, SymbolInfo::Kind kind,
212d7314b3cSChia-hung Duan                                       Optional<DagAndConstant> dagAndConstant)
213d7314b3cSChia-hung Duan     : op(op), kind(kind), dagAndConstant(dagAndConstant) {}
214ac68637bSLei Zhang 
21512d16de5SRahul Joshi int SymbolInfoMap::SymbolInfo::getStaticValueCount() const {
216ac68637bSLei Zhang   switch (kind) {
217ac68637bSLei Zhang   case Kind::Attr:
218ac68637bSLei Zhang   case Kind::Operand:
219ac68637bSLei Zhang   case Kind::Value:
220ac68637bSLei Zhang     return 1;
221ac68637bSLei Zhang   case Kind::Result:
222ac68637bSLei Zhang     return op->getNumResults();
223d7314b3cSChia-hung Duan   case Kind::MultipleValues:
224d7314b3cSChia-hung Duan     return getSize();
225ac68637bSLei Zhang   }
22612ff145eSjpienaar   llvm_unreachable("unknown kind");
227ac68637bSLei Zhang }
228ac68637bSLei Zhang 
229008c0ea6Srdzhabarov std::string SymbolInfoMap::SymbolInfo::getVarName(StringRef name) const {
230008c0ea6Srdzhabarov   return alternativeName.hasValue() ? alternativeName.getValue() : name.str();
231008c0ea6Srdzhabarov }
232008c0ea6Srdzhabarov 
233*bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getVarTypeStr(StringRef name) const {
234*bb250606SChia-hung Duan   LLVM_DEBUG(llvm::dbgs() << "getVarTypeStr for '" << name << "': ");
235ac68637bSLei Zhang   switch (kind) {
236ac68637bSLei Zhang   case Kind::Attr: {
237*bb250606SChia-hung Duan     if (op)
238*bb250606SChia-hung Duan       return op->getArg(getArgIndex())
239b4001ae8SChia-hung Duan           .get<NamedAttribute *>()
240*bb250606SChia-hung Duan           ->attr.getStorageType()
241*bb250606SChia-hung Duan           .str();
2422bf423b0SRob Suderman     // TODO(suderman): Use a more exact type when available.
243*bb250606SChia-hung Duan     return "Attribute";
2442bf423b0SRob Suderman   }
24531cfee60SLei Zhang   case Kind::Operand: {
24631cfee60SLei Zhang     // Use operand range for captured operands (to support potential variadic
24731cfee60SLei Zhang     // operands).
248*bb250606SChia-hung Duan     return "::mlir::Operation::operand_range";
24931cfee60SLei Zhang   }
250ac68637bSLei Zhang   case Kind::Value: {
251*bb250606SChia-hung Duan     return "::mlir::Value";
252ac68637bSLei Zhang   }
253d7314b3cSChia-hung Duan   case Kind::MultipleValues: {
254*bb250606SChia-hung Duan     return "::mlir::ValueRange";
255d7314b3cSChia-hung Duan   }
256ac68637bSLei Zhang   case Kind::Result: {
25731cfee60SLei Zhang     // Use the op itself for captured results.
258*bb250606SChia-hung Duan     return op->getQualCppClassName();
259ac68637bSLei Zhang   }
260ac68637bSLei Zhang   }
26112ff145eSjpienaar   llvm_unreachable("unknown kind");
262ac68637bSLei Zhang }
263ac68637bSLei Zhang 
264*bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getVarDecl(StringRef name) const {
265*bb250606SChia-hung Duan   LLVM_DEBUG(llvm::dbgs() << "getVarDecl for '" << name << "': ");
266*bb250606SChia-hung Duan   std::string varInit = kind == Kind::Operand ? "(op0->getOperands())" : "";
267*bb250606SChia-hung Duan   return std::string(
268*bb250606SChia-hung Duan       formatv("{0} {1}{2};\n", getVarTypeStr(name), getVarName(name), varInit));
269*bb250606SChia-hung Duan }
270*bb250606SChia-hung Duan 
271*bb250606SChia-hung Duan std::string SymbolInfoMap::SymbolInfo::getArgDecl(StringRef name) const {
272*bb250606SChia-hung Duan   LLVM_DEBUG(llvm::dbgs() << "getArgDecl for '" << name << "': ");
273*bb250606SChia-hung Duan   return std::string(
274*bb250606SChia-hung Duan       formatv("{0} &{1}", getVarTypeStr(name), getVarName(name)));
275*bb250606SChia-hung Duan }
276*bb250606SChia-hung Duan 
27712d16de5SRahul Joshi std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
27831cfee60SLei Zhang     StringRef name, int index, const char *fmt, const char *separator) const {
2791358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "getValueAndRangeUse for '" << name << "': ");
28031cfee60SLei Zhang   switch (kind) {
28131cfee60SLei Zhang   case Kind::Attr: {
28231cfee60SLei Zhang     assert(index < 0);
2831358df19SLei Zhang     auto repl = formatv(fmt, name);
2841358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Attr)\n");
285adcd0268SBenjamin Kramer     return std::string(repl);
28631cfee60SLei Zhang   }
28731cfee60SLei Zhang   case Kind::Operand: {
28831cfee60SLei Zhang     assert(index < 0);
289d7314b3cSChia-hung Duan     auto *operand = op->getArg(getArgIndex()).get<NamedTypeConstraint *>();
29031cfee60SLei Zhang     // If this operand is variadic, then return a range. Otherwise, return the
29131cfee60SLei Zhang     // value itself.
292aba1acc8SRiver Riddle     if (operand->isVariableLength()) {
2931358df19SLei Zhang       auto repl = formatv(fmt, name);
2941358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicOperand)\n");
295adcd0268SBenjamin Kramer       return std::string(repl);
29631cfee60SLei Zhang     }
2971358df19SLei Zhang     auto repl = formatv(fmt, formatv("(*{0}.begin())", name));
2981358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (SingleOperand)\n");
299adcd0268SBenjamin Kramer     return std::string(repl);
30031cfee60SLei Zhang   }
30131cfee60SLei Zhang   case Kind::Result: {
30231cfee60SLei Zhang     // If `index` is greater than zero, then we are referencing a specific
30331cfee60SLei Zhang     // result of a multi-result op. The result can still be variadic.
30431cfee60SLei Zhang     if (index >= 0) {
305adcd0268SBenjamin Kramer       std::string v =
306adcd0268SBenjamin Kramer           std::string(formatv("{0}.getODSResults({1})", name, index));
30731cfee60SLei Zhang       if (!op->getResult(index).isVariadic())
308adcd0268SBenjamin Kramer         v = std::string(formatv("(*{0}.begin())", v));
3091358df19SLei Zhang       auto repl = formatv(fmt, v);
3101358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
311adcd0268SBenjamin Kramer       return std::string(repl);
31231cfee60SLei Zhang     }
31331cfee60SLei Zhang 
31423d21af6SLei Zhang     // If this op has no result at all but still we bind a symbol to it, it
31523d21af6SLei Zhang     // means we want to capture the op itself.
31623d21af6SLei Zhang     if (op->getNumResults() == 0) {
31723d21af6SLei Zhang       LLVM_DEBUG(llvm::dbgs() << name << " (Op)\n");
318adcd0268SBenjamin Kramer       return std::string(name);
31923d21af6SLei Zhang     }
32023d21af6SLei Zhang 
32131cfee60SLei Zhang     // We are referencing all results of the multi-result op. A specific result
32231cfee60SLei Zhang     // can either be a value or a range. Then join them with `separator`.
32331cfee60SLei Zhang     SmallVector<std::string, 4> values;
32431cfee60SLei Zhang     values.reserve(op->getNumResults());
32531cfee60SLei Zhang 
32631cfee60SLei Zhang     for (int i = 0, e = op->getNumResults(); i < e; ++i) {
327adcd0268SBenjamin Kramer       std::string v = std::string(formatv("{0}.getODSResults({1})", name, i));
32831cfee60SLei Zhang       if (!op->getResult(i).isVariadic()) {
329adcd0268SBenjamin Kramer         v = std::string(formatv("(*{0}.begin())", v));
33031cfee60SLei Zhang       }
331adcd0268SBenjamin Kramer       values.push_back(std::string(formatv(fmt, v)));
33231cfee60SLei Zhang     }
3331358df19SLei Zhang     auto repl = llvm::join(values, separator);
3341358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
3351358df19SLei Zhang     return repl;
33631cfee60SLei Zhang   }
33731cfee60SLei Zhang   case Kind::Value: {
33831cfee60SLei Zhang     assert(index < 0);
33931cfee60SLei Zhang     assert(op == nullptr);
3401358df19SLei Zhang     auto repl = formatv(fmt, name);
3411358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
342adcd0268SBenjamin Kramer     return std::string(repl);
34331cfee60SLei Zhang   }
344d7314b3cSChia-hung Duan   case Kind::MultipleValues: {
345d7314b3cSChia-hung Duan     assert(op == nullptr);
346d7314b3cSChia-hung Duan     assert(index < getSize());
347d7314b3cSChia-hung Duan     if (index >= 0) {
348d7314b3cSChia-hung Duan       std::string repl =
349d7314b3cSChia-hung Duan           formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));
350d7314b3cSChia-hung Duan       LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
351d7314b3cSChia-hung Duan       return repl;
352d7314b3cSChia-hung Duan     }
353d7314b3cSChia-hung Duan     // If it doesn't specify certain element, unpack them all.
354d7314b3cSChia-hung Duan     auto repl =
355d7314b3cSChia-hung Duan         formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
356d7314b3cSChia-hung Duan     LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
357d7314b3cSChia-hung Duan     return std::string(repl);
358d7314b3cSChia-hung Duan   }
35931cfee60SLei Zhang   }
36094298ceaSLei Zhang   llvm_unreachable("unknown kind");
36131cfee60SLei Zhang }
36231cfee60SLei Zhang 
36312d16de5SRahul Joshi std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(
36431cfee60SLei Zhang     StringRef name, int index, const char *fmt, const char *separator) const {
3651358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "getAllRangeUse for '" << name << "': ");
366ac68637bSLei Zhang   switch (kind) {
367ac68637bSLei Zhang   case Kind::Attr:
368ac68637bSLei Zhang   case Kind::Operand: {
369ac68637bSLei Zhang     assert(index < 0 && "only allowed for symbol bound to result");
3701358df19SLei Zhang     auto repl = formatv(fmt, name);
3711358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Operand/Attr)\n");
372adcd0268SBenjamin Kramer     return std::string(repl);
373ac68637bSLei Zhang   }
374ac68637bSLei Zhang   case Kind::Result: {
375ac68637bSLei Zhang     if (index >= 0) {
3761358df19SLei Zhang       auto repl = formatv(fmt, formatv("{0}.getODSResults({1})", name, index));
3771358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
378adcd0268SBenjamin Kramer       return std::string(repl);
379ac68637bSLei Zhang     }
380ac68637bSLei Zhang 
38131cfee60SLei Zhang     // We are referencing all results of the multi-result op. Each result should
38231cfee60SLei Zhang     // have a value range, and then join them with `separator`.
383ac68637bSLei Zhang     SmallVector<std::string, 4> values;
38431cfee60SLei Zhang     values.reserve(op->getNumResults());
38531cfee60SLei Zhang 
386ac68637bSLei Zhang     for (int i = 0, e = op->getNumResults(); i < e; ++i) {
387adcd0268SBenjamin Kramer       values.push_back(std::string(
388adcd0268SBenjamin Kramer           formatv(fmt, formatv("{0}.getODSResults({1})", name, i))));
389ac68637bSLei Zhang     }
3901358df19SLei Zhang     auto repl = llvm::join(values, separator);
3911358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
3921358df19SLei Zhang     return repl;
393ac68637bSLei Zhang   }
394ac68637bSLei Zhang   case Kind::Value: {
395ac68637bSLei Zhang     assert(index < 0 && "only allowed for symbol bound to result");
396ac68637bSLei Zhang     assert(op == nullptr);
39760f1d263SLei Zhang     auto repl = formatv(fmt, formatv("{{{0}}", name));
3981358df19SLei Zhang     LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
399adcd0268SBenjamin Kramer     return std::string(repl);
400ac68637bSLei Zhang   }
401d7314b3cSChia-hung Duan   case Kind::MultipleValues: {
402d7314b3cSChia-hung Duan     assert(op == nullptr);
403d7314b3cSChia-hung Duan     assert(index < getSize());
404d7314b3cSChia-hung Duan     if (index >= 0) {
405d7314b3cSChia-hung Duan       std::string repl =
406d7314b3cSChia-hung Duan           formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));
407d7314b3cSChia-hung Duan       LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
408d7314b3cSChia-hung Duan       return repl;
409d7314b3cSChia-hung Duan     }
410d7314b3cSChia-hung Duan     auto repl =
411d7314b3cSChia-hung Duan         formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));
412d7314b3cSChia-hung Duan     LLVM_DEBUG(llvm::dbgs() << repl << " (MultipleValues)\n");
413d7314b3cSChia-hung Duan     return std::string(repl);
414d7314b3cSChia-hung Duan   }
415ac68637bSLei Zhang   }
41612ff145eSjpienaar   llvm_unreachable("unknown kind");
417ac68637bSLei Zhang }
418ac68637bSLei Zhang 
419b4001ae8SChia-hung Duan bool SymbolInfoMap::bindOpArgument(DagNode node, StringRef symbol,
420b4001ae8SChia-hung Duan                                    const Operator &op, int argIndex) {
421ac68637bSLei Zhang   StringRef name = getValuePackName(symbol);
422ac68637bSLei Zhang   if (name != symbol) {
423ac68637bSLei Zhang     auto error = formatv(
424ac68637bSLei Zhang         "symbol '{0}' with trailing index cannot bind to op argument", symbol);
425ac68637bSLei Zhang     PrintFatalError(loc, error);
426ac68637bSLei Zhang   }
427ac68637bSLei Zhang 
428ac68637bSLei Zhang   auto symInfo = op.getArg(argIndex).is<NamedAttribute *>()
429ac68637bSLei Zhang                      ? SymbolInfo::getAttr(&op, argIndex)
430b4001ae8SChia-hung Duan                      : SymbolInfo::getOperand(node, &op, argIndex);
431ac68637bSLei Zhang 
432008c0ea6Srdzhabarov   std::string key = symbol.str();
433008c0ea6Srdzhabarov   if (symbolInfoMap.count(key)) {
434008c0ea6Srdzhabarov     // Only non unique name for the operand is supported.
435008c0ea6Srdzhabarov     if (symInfo.kind != SymbolInfo::Kind::Operand) {
436008c0ea6Srdzhabarov       return false;
437008c0ea6Srdzhabarov     }
438008c0ea6Srdzhabarov 
439008c0ea6Srdzhabarov     // Cannot add new operand if there is already non operand with the same
440008c0ea6Srdzhabarov     // name.
441008c0ea6Srdzhabarov     if (symbolInfoMap.find(key)->second.kind != SymbolInfo::Kind::Operand) {
442008c0ea6Srdzhabarov       return false;
443008c0ea6Srdzhabarov     }
444008c0ea6Srdzhabarov   }
445008c0ea6Srdzhabarov 
446008c0ea6Srdzhabarov   symbolInfoMap.emplace(key, symInfo);
447008c0ea6Srdzhabarov   return true;
448ac68637bSLei Zhang }
449ac68637bSLei Zhang 
45012d16de5SRahul Joshi bool SymbolInfoMap::bindOpResult(StringRef symbol, const Operator &op) {
451008c0ea6Srdzhabarov   std::string name = getValuePackName(symbol).str();
452008c0ea6Srdzhabarov   auto inserted = symbolInfoMap.emplace(name, SymbolInfo::getResult(&op));
453008c0ea6Srdzhabarov 
454008c0ea6Srdzhabarov   return symbolInfoMap.count(inserted->first) == 1;
455ac68637bSLei Zhang }
456ac68637bSLei Zhang 
457d7314b3cSChia-hung Duan bool SymbolInfoMap::bindValues(StringRef symbol, int numValues) {
458d7314b3cSChia-hung Duan   std::string name = getValuePackName(symbol).str();
459d7314b3cSChia-hung Duan   if (numValues > 1)
460d7314b3cSChia-hung Duan     return bindMultipleValues(name, numValues);
461d7314b3cSChia-hung Duan   return bindValue(name);
462d7314b3cSChia-hung Duan }
463d7314b3cSChia-hung Duan 
46412d16de5SRahul Joshi bool SymbolInfoMap::bindValue(StringRef symbol) {
465008c0ea6Srdzhabarov   auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getValue());
466008c0ea6Srdzhabarov   return symbolInfoMap.count(inserted->first) == 1;
467ac68637bSLei Zhang }
468ac68637bSLei Zhang 
469d7314b3cSChia-hung Duan bool SymbolInfoMap::bindMultipleValues(StringRef symbol, int numValues) {
470d7314b3cSChia-hung Duan   std::string name = getValuePackName(symbol).str();
471d7314b3cSChia-hung Duan   auto inserted =
472d7314b3cSChia-hung Duan       symbolInfoMap.emplace(name, SymbolInfo::getMultipleValues(numValues));
473d7314b3cSChia-hung Duan   return symbolInfoMap.count(inserted->first) == 1;
474d7314b3cSChia-hung Duan }
475d7314b3cSChia-hung Duan 
4762bf423b0SRob Suderman bool SymbolInfoMap::bindAttr(StringRef symbol) {
477ad1fe396SRob Suderman   auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getAttr());
4782bf423b0SRob Suderman   return symbolInfoMap.count(inserted->first) == 1;
4792bf423b0SRob Suderman }
4802bf423b0SRob Suderman 
48112d16de5SRahul Joshi bool SymbolInfoMap::contains(StringRef symbol) const {
482ac68637bSLei Zhang   return find(symbol) != symbolInfoMap.end();
483ac68637bSLei Zhang }
484ac68637bSLei Zhang 
48512d16de5SRahul Joshi SymbolInfoMap::const_iterator SymbolInfoMap::find(StringRef key) const {
486008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
487008c0ea6Srdzhabarov 
488ac68637bSLei Zhang   return symbolInfoMap.find(name);
489ac68637bSLei Zhang }
490ac68637bSLei Zhang 
491008c0ea6Srdzhabarov SymbolInfoMap::const_iterator
492b4001ae8SChia-hung Duan SymbolInfoMap::findBoundSymbol(StringRef key, DagNode node, const Operator &op,
493008c0ea6Srdzhabarov                                int argIndex) const {
494*bb250606SChia-hung Duan   return findBoundSymbol(key, SymbolInfo::getOperand(node, &op, argIndex));
495*bb250606SChia-hung Duan }
496*bb250606SChia-hung Duan 
497*bb250606SChia-hung Duan SymbolInfoMap::const_iterator
498*bb250606SChia-hung Duan SymbolInfoMap::findBoundSymbol(StringRef key, SymbolInfo symbolInfo) const {
499008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
500008c0ea6Srdzhabarov   auto range = symbolInfoMap.equal_range(name);
501008c0ea6Srdzhabarov 
502d7314b3cSChia-hung Duan   for (auto it = range.first; it != range.second; ++it)
503d7314b3cSChia-hung Duan     if (it->second.dagAndConstant == symbolInfo.dagAndConstant)
504008c0ea6Srdzhabarov       return it;
505008c0ea6Srdzhabarov 
506008c0ea6Srdzhabarov   return symbolInfoMap.end();
507008c0ea6Srdzhabarov }
508008c0ea6Srdzhabarov 
509008c0ea6Srdzhabarov std::pair<SymbolInfoMap::iterator, SymbolInfoMap::iterator>
510008c0ea6Srdzhabarov SymbolInfoMap::getRangeOfEqualElements(StringRef key) {
511008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
512008c0ea6Srdzhabarov 
513008c0ea6Srdzhabarov   return symbolInfoMap.equal_range(name);
514008c0ea6Srdzhabarov }
515008c0ea6Srdzhabarov 
516008c0ea6Srdzhabarov int SymbolInfoMap::count(StringRef key) const {
517008c0ea6Srdzhabarov   std::string name = getValuePackName(key).str();
518008c0ea6Srdzhabarov   return symbolInfoMap.count(name);
519008c0ea6Srdzhabarov }
520008c0ea6Srdzhabarov 
52112d16de5SRahul Joshi int SymbolInfoMap::getStaticValueCount(StringRef symbol) const {
522ac68637bSLei Zhang   StringRef name = getValuePackName(symbol);
523ac68637bSLei Zhang   if (name != symbol) {
524ac68637bSLei Zhang     // If there is a trailing index inside symbol, it references just one
525ac68637bSLei Zhang     // static value.
526ac68637bSLei Zhang     return 1;
527ac68637bSLei Zhang   }
528ac68637bSLei Zhang   // Otherwise, find how many it represents by querying the symbol's info.
529008c0ea6Srdzhabarov   return find(name)->second.getStaticValueCount();
530ac68637bSLei Zhang }
531ac68637bSLei Zhang 
53212d16de5SRahul Joshi std::string SymbolInfoMap::getValueAndRangeUse(StringRef symbol,
53312d16de5SRahul Joshi                                                const char *fmt,
53431cfee60SLei Zhang                                                const char *separator) const {
535ac68637bSLei Zhang   int index = -1;
536ac68637bSLei Zhang   StringRef name = getValuePackName(symbol, &index);
537ac68637bSLei Zhang 
538008c0ea6Srdzhabarov   auto it = symbolInfoMap.find(name.str());
539ac68637bSLei Zhang   if (it == symbolInfoMap.end()) {
540ac68637bSLei Zhang     auto error = formatv("referencing unbound symbol '{0}'", symbol);
541ac68637bSLei Zhang     PrintFatalError(loc, error);
542ac68637bSLei Zhang   }
543ac68637bSLei Zhang 
544008c0ea6Srdzhabarov   return it->second.getValueAndRangeUse(name, index, fmt, separator);
54531cfee60SLei Zhang }
54631cfee60SLei Zhang 
54712d16de5SRahul Joshi std::string SymbolInfoMap::getAllRangeUse(StringRef symbol, const char *fmt,
54831cfee60SLei Zhang                                           const char *separator) const {
54931cfee60SLei Zhang   int index = -1;
55031cfee60SLei Zhang   StringRef name = getValuePackName(symbol, &index);
55131cfee60SLei Zhang 
552008c0ea6Srdzhabarov   auto it = symbolInfoMap.find(name.str());
55331cfee60SLei Zhang   if (it == symbolInfoMap.end()) {
55431cfee60SLei Zhang     auto error = formatv("referencing unbound symbol '{0}'", symbol);
55531cfee60SLei Zhang     PrintFatalError(loc, error);
55631cfee60SLei Zhang   }
55731cfee60SLei Zhang 
558008c0ea6Srdzhabarov   return it->second.getAllRangeUse(name, index, fmt, separator);
559008c0ea6Srdzhabarov }
560008c0ea6Srdzhabarov 
561008c0ea6Srdzhabarov void SymbolInfoMap::assignUniqueAlternativeNames() {
562008c0ea6Srdzhabarov   llvm::StringSet<> usedNames;
563008c0ea6Srdzhabarov 
564008c0ea6Srdzhabarov   for (auto symbolInfoIt = symbolInfoMap.begin();
565008c0ea6Srdzhabarov        symbolInfoIt != symbolInfoMap.end();) {
566008c0ea6Srdzhabarov     auto range = symbolInfoMap.equal_range(symbolInfoIt->first);
567008c0ea6Srdzhabarov     auto startRange = range.first;
568008c0ea6Srdzhabarov     auto endRange = range.second;
569008c0ea6Srdzhabarov 
570008c0ea6Srdzhabarov     auto operandName = symbolInfoIt->first;
571008c0ea6Srdzhabarov     int startSearchIndex = 0;
572008c0ea6Srdzhabarov     for (++startRange; startRange != endRange; ++startRange) {
573008c0ea6Srdzhabarov       // Current operand name is not unique, find a unique one
574008c0ea6Srdzhabarov       // and set the alternative name.
575008c0ea6Srdzhabarov       for (int i = startSearchIndex;; ++i) {
576008c0ea6Srdzhabarov         std::string alternativeName = operandName + std::to_string(i);
577008c0ea6Srdzhabarov         if (!usedNames.contains(alternativeName) &&
578008c0ea6Srdzhabarov             symbolInfoMap.count(alternativeName) == 0) {
579008c0ea6Srdzhabarov           usedNames.insert(alternativeName);
580008c0ea6Srdzhabarov           startRange->second.alternativeName = alternativeName;
581008c0ea6Srdzhabarov           startSearchIndex = i + 1;
582008c0ea6Srdzhabarov 
583008c0ea6Srdzhabarov           break;
584008c0ea6Srdzhabarov         }
585008c0ea6Srdzhabarov       }
586008c0ea6Srdzhabarov     }
587008c0ea6Srdzhabarov 
588008c0ea6Srdzhabarov     symbolInfoIt = endRange;
589008c0ea6Srdzhabarov   }
590ac68637bSLei Zhang }
591ac68637bSLei Zhang 
592ac68637bSLei Zhang //===----------------------------------------------------------------------===//
593ac68637bSLei Zhang // Pattern
594ac68637bSLei Zhang //==----------------------------------------------------------------------===//
595ac68637bSLei Zhang 
59612d16de5SRahul Joshi Pattern::Pattern(const llvm::Record *def, RecordOperatorMap *mapper)
597ac68637bSLei Zhang     : def(*def), recordOpMap(mapper) {}
598eb753f4aSLei Zhang 
59912d16de5SRahul Joshi DagNode Pattern::getSourcePattern() const {
60012d16de5SRahul Joshi   return DagNode(def.getValueAsDag("sourcePattern"));
601eb753f4aSLei Zhang }
602eb753f4aSLei Zhang 
60312d16de5SRahul Joshi int Pattern::getNumResultPatterns() const {
6048f5fa566SLei Zhang   auto *results = def.getValueAsListInit("resultPatterns");
605eb753f4aSLei Zhang   return results->size();
606eb753f4aSLei Zhang }
607eb753f4aSLei Zhang 
60812d16de5SRahul Joshi DagNode Pattern::getResultPattern(unsigned index) const {
6098f5fa566SLei Zhang   auto *results = def.getValueAsListInit("resultPatterns");
61012d16de5SRahul Joshi   return DagNode(cast<llvm::DagInit>(results->getElement(index)));
611eb753f4aSLei Zhang }
612eb753f4aSLei Zhang 
61312d16de5SRahul Joshi void Pattern::collectSourcePatternBoundSymbols(SymbolInfoMap &infoMap) {
6141358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "start collecting source pattern bound symbols\n");
615ac68637bSLei Zhang   collectBoundSymbols(getSourcePattern(), infoMap, /*isSrcPattern=*/true);
6161358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "done collecting source pattern bound symbols\n");
617008c0ea6Srdzhabarov 
618008c0ea6Srdzhabarov   LLVM_DEBUG(llvm::dbgs() << "start assigning alternative names for symbols\n");
619008c0ea6Srdzhabarov   infoMap.assignUniqueAlternativeNames();
620008c0ea6Srdzhabarov   LLVM_DEBUG(llvm::dbgs() << "done assigning alternative names for symbols\n");
621eb753f4aSLei Zhang }
622eb753f4aSLei Zhang 
62312d16de5SRahul Joshi void Pattern::collectResultPatternBoundSymbols(SymbolInfoMap &infoMap) {
6241358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "start collecting result pattern bound symbols\n");
625ac68637bSLei Zhang   for (int i = 0, e = getNumResultPatterns(); i < e; ++i) {
626ac68637bSLei Zhang     auto pattern = getResultPattern(i);
627ac68637bSLei Zhang     collectBoundSymbols(pattern, infoMap, /*isSrcPattern=*/false);
628eb753f4aSLei Zhang   }
6291358df19SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "done collecting result pattern bound symbols\n");
630388fb375SJacques Pienaar }
631388fb375SJacques Pienaar 
63212d16de5SRahul Joshi const Operator &Pattern::getSourceRootOp() {
633eb753f4aSLei Zhang   return getSourcePattern().getDialectOp(recordOpMap);
634eb753f4aSLei Zhang }
635eb753f4aSLei Zhang 
63612d16de5SRahul Joshi Operator &Pattern::getDialectOp(DagNode node) {
637eb753f4aSLei Zhang   return node.getDialectOp(recordOpMap);
638eb753f4aSLei Zhang }
639388fb375SJacques Pienaar 
64012d16de5SRahul Joshi std::vector<AppliedConstraint> Pattern::getConstraints() const {
641388fb375SJacques Pienaar   auto *listInit = def.getValueAsListInit("constraints");
64212d16de5SRahul Joshi   std::vector<AppliedConstraint> ret;
643388fb375SJacques Pienaar   ret.reserve(listInit->size());
6448f5fa566SLei Zhang 
645388fb375SJacques Pienaar   for (auto it : *listInit) {
6468f5fa566SLei Zhang     auto *dagInit = dyn_cast<llvm::DagInit>(it);
6478f5fa566SLei Zhang     if (!dagInit)
6482bf423b0SRob Suderman       PrintFatalError(&def, "all elements in Pattern multi-entity "
6498f5fa566SLei Zhang                             "constraints should be DAG nodes");
6508f5fa566SLei Zhang 
6518f5fa566SLei Zhang     std::vector<std::string> entities;
6528f5fa566SLei Zhang     entities.reserve(dagInit->arg_size());
653cb40e36dSLei Zhang     for (auto *argName : dagInit->getArgNames()) {
654cb40e36dSLei Zhang       if (!argName) {
655cb40e36dSLei Zhang         PrintFatalError(
6562bf423b0SRob Suderman             &def,
657cb40e36dSLei Zhang             "operands to additional constraints can only be symbol references");
658cb40e36dSLei Zhang       }
659adcd0268SBenjamin Kramer       entities.push_back(std::string(argName->getValue()));
660cb40e36dSLei Zhang     }
6618f5fa566SLei Zhang 
6628f5fa566SLei Zhang     ret.emplace_back(cast<llvm::DefInit>(dagInit->getOperator())->getDef(),
663c72d849eSLei Zhang                      dagInit->getNameStr(), std::move(entities));
664388fb375SJacques Pienaar   }
665388fb375SJacques Pienaar   return ret;
666388fb375SJacques Pienaar }
66753035874SFeng Liu 
66812d16de5SRahul Joshi int Pattern::getBenefit() const {
669a0606ca7SFeng Liu   // The initial benefit value is a heuristic with number of ops in the source
67053035874SFeng Liu   // pattern.
671a0606ca7SFeng Liu   int initBenefit = getSourcePattern().getNumOps();
67253035874SFeng Liu   llvm::DagInit *delta = def.getValueAsDag("benefitDelta");
673a0606ca7SFeng Liu   if (delta->getNumArgs() != 1 || !isa<llvm::IntInit>(delta->getArg(0))) {
6742bf423b0SRob Suderman     PrintFatalError(&def,
675a0606ca7SFeng Liu                     "The 'addBenefit' takes and only takes one integer value");
676a0606ca7SFeng Liu   }
677a0606ca7SFeng Liu   return initBenefit + dyn_cast<llvm::IntInit>(delta->getArg(0))->getValue();
67853035874SFeng Liu }
67904b6d2f3SLei Zhang 
68012d16de5SRahul Joshi std::vector<Pattern::IdentifierLine> Pattern::getLocation() const {
6814165885aSJacques Pienaar   std::vector<std::pair<StringRef, unsigned>> result;
6824165885aSJacques Pienaar   result.reserve(def.getLoc().size());
6834165885aSJacques Pienaar   for (auto loc : def.getLoc()) {
6844165885aSJacques Pienaar     unsigned buf = llvm::SrcMgr.FindBufferContainingLoc(loc);
6854165885aSJacques Pienaar     assert(buf && "invalid source location");
6864165885aSJacques Pienaar     result.emplace_back(
6874165885aSJacques Pienaar         llvm::SrcMgr.getBufferInfo(buf).Buffer->getBufferIdentifier(),
6884165885aSJacques Pienaar         llvm::SrcMgr.getLineAndColumn(loc, buf).first);
6894165885aSJacques Pienaar   }
6904165885aSJacques Pienaar   return result;
6914165885aSJacques Pienaar }
6924165885aSJacques Pienaar 
6932bf423b0SRob Suderman void Pattern::verifyBind(bool result, StringRef symbolName) {
6942bf423b0SRob Suderman   if (!result) {
6952bf423b0SRob Suderman     auto err = formatv("symbol '{0}' bound more than once", symbolName);
6962bf423b0SRob Suderman     PrintFatalError(&def, err);
6972bf423b0SRob Suderman   }
6982bf423b0SRob Suderman }
6992bf423b0SRob Suderman 
70012d16de5SRahul Joshi void Pattern::collectBoundSymbols(DagNode tree, SymbolInfoMap &infoMap,
701e032d0dcSLei Zhang                                   bool isSrcPattern) {
702e032d0dcSLei Zhang   auto treeName = tree.getSymbol();
7032bf423b0SRob Suderman   auto numTreeArgs = tree.getNumArgs();
7042bf423b0SRob Suderman 
7052bf423b0SRob Suderman   if (tree.isNativeCodeCall()) {
706e032d0dcSLei Zhang     if (!treeName.empty()) {
70734b5482bSChia-hung Duan       if (!isSrcPattern) {
70834b5482bSChia-hung Duan         LLVM_DEBUG(llvm::dbgs() << "found symbol bound to NativeCodeCall: "
70934b5482bSChia-hung Duan                                 << treeName << '\n');
710d7314b3cSChia-hung Duan         verifyBind(
711d7314b3cSChia-hung Duan             infoMap.bindValues(treeName, tree.getNumReturnsOfNativeCode()),
712d7314b3cSChia-hung Duan             treeName);
71334b5482bSChia-hung Duan       } else {
71434b5482bSChia-hung Duan         PrintFatalError(&def,
71534b5482bSChia-hung Duan                         formatv("binding symbol '{0}' to NativecodeCall in "
71634b5482bSChia-hung Duan                                 "MatchPattern is not supported",
717e032d0dcSLei Zhang                                 treeName));
718e032d0dcSLei Zhang       }
71934b5482bSChia-hung Duan     }
7202bf423b0SRob Suderman 
7212bf423b0SRob Suderman     for (int i = 0; i != numTreeArgs; ++i) {
7222bf423b0SRob Suderman       if (auto treeArg = tree.getArgAsNestedDag(i)) {
7232bf423b0SRob Suderman         // This DAG node argument is a DAG node itself. Go inside recursively.
7242bf423b0SRob Suderman         collectBoundSymbols(treeArg, infoMap, isSrcPattern);
7252bf423b0SRob Suderman         continue;
7262bf423b0SRob Suderman       }
7272bf423b0SRob Suderman 
7282bf423b0SRob Suderman       if (!isSrcPattern)
7292bf423b0SRob Suderman         continue;
7302bf423b0SRob Suderman 
7312bf423b0SRob Suderman       // We can only bind symbols to arguments in source pattern. Those
7322bf423b0SRob Suderman       // symbols are referenced in result patterns.
7332bf423b0SRob Suderman       auto treeArgName = tree.getArgName(i);
7342bf423b0SRob Suderman 
7352bf423b0SRob Suderman       // `$_` is a special symbol meaning ignore the current argument.
7362bf423b0SRob Suderman       if (!treeArgName.empty() && treeArgName != "_") {
7372bf423b0SRob Suderman         DagLeaf leaf = tree.getArgAsLeaf(i);
73834b5482bSChia-hung Duan 
73934b5482bSChia-hung Duan         // In (NativeCodeCall<"Foo($_self, $0, $1, $2)"> I8Attr:$a, I8:$b, $c),
74034b5482bSChia-hung Duan         if (leaf.isUnspecified()) {
74134b5482bSChia-hung Duan           // This is case of $c, a Value without any constraints.
74234b5482bSChia-hung Duan           verifyBind(infoMap.bindValue(treeArgName), treeArgName);
74334b5482bSChia-hung Duan         } else {
7442bf423b0SRob Suderman           auto constraint = leaf.getAsConstraint();
7452bf423b0SRob Suderman           bool isAttr = leaf.isAttrMatcher() || leaf.isEnumAttrCase() ||
7462bf423b0SRob Suderman                         leaf.isConstantAttr() ||
7472bf423b0SRob Suderman                         constraint.getKind() == Constraint::Kind::CK_Attr;
7482bf423b0SRob Suderman 
7492bf423b0SRob Suderman           if (isAttr) {
75034b5482bSChia-hung Duan             // This is case of $a, a binding to a certain attribute.
7512bf423b0SRob Suderman             verifyBind(infoMap.bindAttr(treeArgName), treeArgName);
7522bf423b0SRob Suderman             continue;
7532bf423b0SRob Suderman           }
7542bf423b0SRob Suderman 
75534b5482bSChia-hung Duan           // This is case of $b, a binding to a certain type.
7562bf423b0SRob Suderman           verifyBind(infoMap.bindValue(treeArgName), treeArgName);
7572bf423b0SRob Suderman         }
7582bf423b0SRob Suderman       }
75934b5482bSChia-hung Duan     }
7602bf423b0SRob Suderman 
761e032d0dcSLei Zhang     return;
762e032d0dcSLei Zhang   }
763e032d0dcSLei Zhang 
7642bf423b0SRob Suderman   if (tree.isOperation()) {
76504b6d2f3SLei Zhang     auto &op = getDialectOp(tree);
76604b6d2f3SLei Zhang     auto numOpArgs = op.getNumArgs();
76704b6d2f3SLei Zhang 
768cb8c30d3SMogball     // The pattern might have trailing directives.
769cb8c30d3SMogball     int numDirectives = 0;
770cb8c30d3SMogball     for (int i = numTreeArgs - 1; i >= 0; --i) {
771cb8c30d3SMogball       if (auto dagArg = tree.getArgAsNestedDag(i)) {
772cb8c30d3SMogball         if (dagArg.isLocationDirective() || dagArg.isReturnTypeDirective())
773cb8c30d3SMogball           ++numDirectives;
774cb8c30d3SMogball         else
775cb8c30d3SMogball           break;
776cb8c30d3SMogball       }
7773f7439b2SJacques Pienaar     }
7783f7439b2SJacques Pienaar 
779cb8c30d3SMogball     if (numOpArgs != numTreeArgs - numDirectives) {
780ac68637bSLei Zhang       auto err = formatv("op '{0}' argument number mismatch: "
78104b6d2f3SLei Zhang                          "{1} in pattern vs. {2} in definition",
782ac68637bSLei Zhang                          op.getOperationName(), numTreeArgs, numOpArgs);
7832bf423b0SRob Suderman       PrintFatalError(&def, err);
78404b6d2f3SLei Zhang     }
78504b6d2f3SLei Zhang 
78604b6d2f3SLei Zhang     // The name attached to the DAG node's operator is for representing the
78704b6d2f3SLei Zhang     // results generated from this op. It should be remembered as bound results.
788ac68637bSLei Zhang     if (!treeName.empty()) {
7891358df19SLei Zhang       LLVM_DEBUG(llvm::dbgs()
7901358df19SLei Zhang                  << "found symbol bound to op result: " << treeName << '\n');
7912bf423b0SRob Suderman       verifyBind(infoMap.bindOpResult(treeName, op), treeName);
792ac68637bSLei Zhang     }
79304b6d2f3SLei Zhang 
7942fe8ae4fSJacques Pienaar     for (int i = 0; i != numTreeArgs; ++i) {
79504b6d2f3SLei Zhang       if (auto treeArg = tree.getArgAsNestedDag(i)) {
79604b6d2f3SLei Zhang         // This DAG node argument is a DAG node itself. Go inside recursively.
797ac68637bSLei Zhang         collectBoundSymbols(treeArg, infoMap, isSrcPattern);
7982bf423b0SRob Suderman         continue;
7992bf423b0SRob Suderman       }
8002bf423b0SRob Suderman 
8012bf423b0SRob Suderman       if (isSrcPattern) {
802e032d0dcSLei Zhang         // We can only bind symbols to op arguments in source pattern. Those
803e032d0dcSLei Zhang         // symbols are referenced in result patterns.
80404b6d2f3SLei Zhang         auto treeArgName = tree.getArgName(i);
8054982eaf8SLei Zhang         // `$_` is a special symbol meaning ignore the current argument.
8064982eaf8SLei Zhang         if (!treeArgName.empty() && treeArgName != "_") {
8071358df19SLei Zhang           LLVM_DEBUG(llvm::dbgs() << "found symbol bound to op argument: "
8081358df19SLei Zhang                                   << treeArgName << '\n');
809b4001ae8SChia-hung Duan           verifyBind(infoMap.bindOpArgument(tree, treeArgName, op, i),
810b4001ae8SChia-hung Duan                      treeArgName);
811ac68637bSLei Zhang         }
812ac68637bSLei Zhang       }
81304b6d2f3SLei Zhang     }
8142bf423b0SRob Suderman     return;
81504b6d2f3SLei Zhang   }
8162bf423b0SRob Suderman 
8172bf423b0SRob Suderman   if (!treeName.empty()) {
8182bf423b0SRob Suderman     PrintFatalError(
8192bf423b0SRob Suderman         &def, formatv("binding symbol '{0}' to non-operation/native code call "
8202bf423b0SRob Suderman                       "unsupported right now",
8212bf423b0SRob Suderman                       treeName));
8222bf423b0SRob Suderman   }
8232bf423b0SRob Suderman   return;
82404b6d2f3SLei Zhang }
825