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