1005 lines · cpp
1//===- Pattern.cpp - Pattern wrapper class --------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Pattern wrapper class to simplify using TableGen Record defining a MLIR10// Pattern.11//12//===----------------------------------------------------------------------===//13 14#include <utility>15 16#include "mlir/TableGen/Pattern.h"17#include "llvm/ADT/StringExtras.h"18#include "llvm/ADT/Twine.h"19#include "llvm/Support/Debug.h"20#include "llvm/Support/FormatVariadic.h"21#include "llvm/Support/Path.h"22#include "llvm/TableGen/Error.h"23#include "llvm/TableGen/Record.h"24 25#define DEBUG_TYPE "mlir-tblgen-pattern"26 27using namespace mlir;28using namespace tblgen;29 30using llvm::DagInit;31using llvm::dbgs;32using llvm::DefInit;33using llvm::formatv;34using llvm::IntInit;35using llvm::Record;36 37//===----------------------------------------------------------------------===//38// DagLeaf39//===----------------------------------------------------------------------===//40 41bool DagLeaf::isUnspecified() const {42 return isa_and_nonnull<llvm::UnsetInit>(def);43}44 45bool DagLeaf::isOperandMatcher() const {46 // Operand matchers specify a type constraint.47 return isSubClassOf("TypeConstraint");48}49 50bool DagLeaf::isAttrMatcher() const {51 // Attribute matchers specify an attribute constraint.52 return isSubClassOf("AttrConstraint");53}54 55bool DagLeaf::isPropMatcher() const {56 // Property matchers specify a property constraint.57 return isSubClassOf("PropConstraint");58}59 60bool DagLeaf::isPropDefinition() const {61 // Property matchers specify a property definition.62 return isSubClassOf("Property");63}64 65bool DagLeaf::isNativeCodeCall() const {66 return isSubClassOf("NativeCodeCall");67}68 69bool DagLeaf::isConstantAttr() const { return isSubClassOf("ConstantAttr"); }70 71bool DagLeaf::isEnumCase() const { return isSubClassOf("EnumCase"); }72 73bool DagLeaf::isConstantProp() const { return isSubClassOf("ConstantProp"); }74 75bool DagLeaf::isStringAttr() const { return isa<llvm::StringInit>(def); }76 77Constraint DagLeaf::getAsConstraint() const {78 assert((isOperandMatcher() || isAttrMatcher() || isPropMatcher()) &&79 "the DAG leaf must be operand, attribute, or property");80 return Constraint(cast<DefInit>(def)->getDef());81}82 83PropConstraint DagLeaf::getAsPropConstraint() const {84 assert(isPropMatcher() && "the DAG leaf must be a property matcher");85 return PropConstraint(cast<DefInit>(def)->getDef());86}87 88Property DagLeaf::getAsProperty() const {89 assert(isPropDefinition() && "the DAG leaf must be a property definition");90 return Property(cast<DefInit>(def)->getDef());91}92 93ConstantAttr DagLeaf::getAsConstantAttr() const {94 assert(isConstantAttr() && "the DAG leaf must be constant attribute");95 return ConstantAttr(cast<DefInit>(def));96}97 98EnumCase DagLeaf::getAsEnumCase() const {99 assert(isEnumCase() && "the DAG leaf must be an enum attribute case");100 return EnumCase(cast<DefInit>(def));101}102 103ConstantProp DagLeaf::getAsConstantProp() const {104 assert(isConstantProp() && "the DAG leaf must be a constant property value");105 return ConstantProp(cast<DefInit>(def));106}107 108std::string DagLeaf::getConditionTemplate() const {109 return getAsConstraint().getConditionTemplate();110}111 112StringRef DagLeaf::getNativeCodeTemplate() const {113 assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");114 return cast<DefInit>(def)->getDef()->getValueAsString("expression");115}116 117int DagLeaf::getNumReturnsOfNativeCode() const {118 assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");119 return cast<DefInit>(def)->getDef()->getValueAsInt("numReturns");120}121 122std::string DagLeaf::getStringAttr() const {123 assert(isStringAttr() && "the DAG leaf must be string attribute");124 return def->getAsUnquotedString();125}126bool DagLeaf::isSubClassOf(StringRef superclass) const {127 if (auto *defInit = dyn_cast_or_null<DefInit>(def))128 return defInit->getDef()->isSubClassOf(superclass);129 return false;130}131 132void DagLeaf::print(raw_ostream &os) const {133 if (def)134 def->print(os);135}136 137//===----------------------------------------------------------------------===//138// DagNode139//===----------------------------------------------------------------------===//140 141bool DagNode::isNativeCodeCall() const {142 if (auto *defInit = dyn_cast_or_null<DefInit>(node->getOperator()))143 return defInit->getDef()->isSubClassOf("NativeCodeCall");144 return false;145}146 147bool DagNode::isOperation() const {148 return !isNativeCodeCall() && !isReplaceWithValue() &&149 !isLocationDirective() && !isReturnTypeDirective() && !isEither() &&150 !isVariadic();151}152 153StringRef DagNode::getNativeCodeTemplate() const {154 assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");155 return cast<DefInit>(node->getOperator())156 ->getDef()157 ->getValueAsString("expression");158}159 160int DagNode::getNumReturnsOfNativeCode() const {161 assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");162 return cast<DefInit>(node->getOperator())163 ->getDef()164 ->getValueAsInt("numReturns");165}166 167StringRef DagNode::getSymbol() const { return node->getNameStr(); }168 169Operator &DagNode::getDialectOp(RecordOperatorMap *mapper) const {170 const Record *opDef = cast<DefInit>(node->getOperator())->getDef();171 auto [it, inserted] = mapper->try_emplace(opDef);172 if (inserted)173 it->second = std::make_unique<Operator>(opDef);174 return *it->second;175}176 177int DagNode::getNumOps() const {178 // We want to get number of operations recursively involved in the DAG tree.179 // All other directives should be excluded.180 int count = isOperation() ? 1 : 0;181 for (int i = 0, e = getNumArgs(); i != e; ++i) {182 if (auto child = getArgAsNestedDag(i))183 count += child.getNumOps();184 }185 return count;186}187 188int DagNode::getNumArgs() const { return node->getNumArgs(); }189 190bool DagNode::isNestedDagArg(unsigned index) const {191 return isa<DagInit>(node->getArg(index));192}193 194DagNode DagNode::getArgAsNestedDag(unsigned index) const {195 return DagNode(dyn_cast_or_null<DagInit>(node->getArg(index)));196}197 198DagLeaf DagNode::getArgAsLeaf(unsigned index) const {199 assert(!isNestedDagArg(index));200 return DagLeaf(node->getArg(index));201}202 203StringRef DagNode::getArgName(unsigned index) const {204 return node->getArgNameStr(index);205}206 207bool DagNode::isReplaceWithValue() const {208 auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef();209 return dagOpDef->getName() == "replaceWithValue";210}211 212bool DagNode::isLocationDirective() const {213 auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef();214 return dagOpDef->getName() == "location";215}216 217bool DagNode::isReturnTypeDirective() const {218 auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef();219 return dagOpDef->getName() == "returnType";220}221 222bool DagNode::isEither() const {223 auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef();224 return dagOpDef->getName() == "either";225}226 227bool DagNode::isVariadic() const {228 auto *dagOpDef = cast<DefInit>(node->getOperator())->getDef();229 return dagOpDef->getName() == "variadic";230}231 232void DagNode::print(raw_ostream &os) const {233 if (node)234 node->print(os);235}236 237//===----------------------------------------------------------------------===//238// SymbolInfoMap239//===----------------------------------------------------------------------===//240 241StringRef SymbolInfoMap::getValuePackName(StringRef symbol, int *index) {242 int idx = -1;243 auto [name, indexStr] = symbol.rsplit("__");244 245 if (indexStr.consumeInteger(10, idx)) {246 // The second part is not an index; we return the whole symbol as-is.247 return symbol;248 }249 if (index) {250 *index = idx;251 }252 return name;253}254 255SymbolInfoMap::SymbolInfo::SymbolInfo(256 const Operator *op, SymbolInfo::Kind kind,257 std::optional<DagAndConstant> dagAndConstant)258 : op(op), kind(kind), dagAndConstant(dagAndConstant) {}259 260int SymbolInfoMap::SymbolInfo::getStaticValueCount() const {261 switch (kind) {262 case Kind::Attr:263 case Kind::Prop:264 case Kind::Operand:265 case Kind::Value:266 return 1;267 case Kind::Result:268 return op->getNumResults();269 case Kind::MultipleValues:270 return getSize();271 }272 llvm_unreachable("unknown kind");273}274 275std::string SymbolInfoMap::SymbolInfo::getVarName(StringRef name) const {276 return alternativeName ? *alternativeName : name.str();277}278 279std::string SymbolInfoMap::SymbolInfo::getVarTypeStr(StringRef name) const {280 LLVM_DEBUG(dbgs() << "getVarTypeStr for '" << name << "': ");281 switch (kind) {282 case Kind::Attr: {283 if (op)284 return cast<NamedAttribute *>(op->getArg(getArgIndex()))285 ->attr.getStorageType()286 .str();287 // TODO(suderman): Use a more exact type when available.288 return "::mlir::Attribute";289 }290 case Kind::Prop: {291 if (op)292 return cast<NamedProperty *>(op->getArg(getArgIndex()))293 ->prop.getInterfaceType()294 .str();295 assert(dagAndConstant && dagAndConstant->dag &&296 "generic properties must carry their constraint");297 return reinterpret_cast<const DagLeaf *>(dagAndConstant->dag)298 ->getAsPropConstraint()299 .getInterfaceType()300 .str();301 }302 case Kind::Operand: {303 // Use operand range for captured operands (to support potential variadic304 // operands).305 return "::mlir::Operation::operand_range";306 }307 case Kind::Value: {308 return "::mlir::Value";309 }310 case Kind::MultipleValues: {311 return "::mlir::ValueRange";312 }313 case Kind::Result: {314 // Use the op itself for captured results.315 return op->getQualCppClassName();316 }317 }318 llvm_unreachable("unknown kind");319}320 321std::string SymbolInfoMap::SymbolInfo::getVarDecl(StringRef name) const {322 LLVM_DEBUG(dbgs() << "getVarDecl for '" << name << "': ");323 std::string varInit = kind == Kind::Operand ? "(op0->getOperands())" : "";324 return std::string(325 formatv("{0} {1}{2};\n", getVarTypeStr(name), getVarName(name), varInit));326}327 328std::string SymbolInfoMap::SymbolInfo::getArgDecl(StringRef name) const {329 LLVM_DEBUG(dbgs() << "getArgDecl for '" << name << "': ");330 return std::string(331 formatv("{0} &{1}", getVarTypeStr(name), getVarName(name)));332}333 334std::string SymbolInfoMap::SymbolInfo::getValueAndRangeUse(335 StringRef name, int index, const char *fmt, const char *separator) const {336 LLVM_DEBUG(dbgs() << "getValueAndRangeUse for '" << name << "': ");337 switch (kind) {338 case Kind::Attr: {339 assert(index < 0);340 auto repl = formatv(fmt, name);341 LLVM_DEBUG(dbgs() << repl << " (Attr)\n");342 return std::string(repl);343 }344 case Kind::Prop: {345 assert(index < 0);346 auto repl = formatv(fmt, name);347 LLVM_DEBUG(dbgs() << repl << " (Prop)\n");348 return std::string(repl);349 }350 case Kind::Operand: {351 assert(index < 0);352 auto *operand = cast<NamedTypeConstraint *>(op->getArg(getArgIndex()));353 if (operand->isOptional()) {354 auto repl = formatv(355 fmt, formatv("({0}.empty() ? ::mlir::Value() : *{0}.begin())", name));356 LLVM_DEBUG(dbgs() << repl << " (OptionalOperand)\n");357 return std::string(repl);358 }359 // If this operand is variadic and this SymbolInfo doesn't have a range360 // index, then return the full variadic operand_range. Otherwise, return361 // the value itself.362 if (operand->isVariableLength() && !getVariadicSubIndex().has_value()) {363 auto repl = formatv(fmt, name);364 LLVM_DEBUG(dbgs() << repl << " (VariadicOperand)\n");365 return std::string(repl);366 }367 auto repl = formatv(fmt, formatv("(*{0}.begin())", name));368 LLVM_DEBUG(dbgs() << repl << " (SingleOperand)\n");369 return std::string(repl);370 }371 case Kind::Result: {372 // If `index` is greater than zero, then we are referencing a specific373 // result of a multi-result op. The result can still be variadic.374 if (index >= 0) {375 std::string v =376 std::string(formatv("{0}.getODSResults({1})", name, index));377 if (!op->getResult(index).isVariadic())378 v = std::string(formatv("(*{0}.begin())", v));379 auto repl = formatv(fmt, v);380 LLVM_DEBUG(dbgs() << repl << " (SingleResult)\n");381 return std::string(repl);382 }383 384 // If this op has no result at all but still we bind a symbol to it, it385 // means we want to capture the op itself.386 if (op->getNumResults() == 0) {387 LLVM_DEBUG(dbgs() << name << " (Op)\n");388 return formatv(fmt, name);389 }390 391 // We are referencing all results of the multi-result op. A specific result392 // can either be a value or a range. Then join them with `separator`.393 SmallVector<std::string, 4> values;394 values.reserve(op->getNumResults());395 396 for (int i = 0, e = op->getNumResults(); i < e; ++i) {397 std::string v = std::string(formatv("{0}.getODSResults({1})", name, i));398 if (!op->getResult(i).isVariadic()) {399 v = std::string(formatv("(*{0}.begin())", v));400 }401 values.push_back(std::string(formatv(fmt, v)));402 }403 auto repl = llvm::join(values, separator);404 LLVM_DEBUG(dbgs() << repl << " (VariadicResult)\n");405 return repl;406 }407 case Kind::Value: {408 assert(index < 0);409 assert(op == nullptr);410 auto repl = formatv(fmt, name);411 LLVM_DEBUG(dbgs() << repl << " (Value)\n");412 return std::string(repl);413 }414 case Kind::MultipleValues: {415 assert(op == nullptr);416 assert(index < getSize());417 if (index >= 0) {418 std::string repl =419 formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));420 LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n");421 return repl;422 }423 // If it doesn't specify certain element, unpack them all.424 auto repl =425 formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));426 LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n");427 return std::string(repl);428 }429 }430 llvm_unreachable("unknown kind");431}432 433std::string SymbolInfoMap::SymbolInfo::getAllRangeUse(434 StringRef name, int index, const char *fmt, const char *separator) const {435 LLVM_DEBUG(dbgs() << "getAllRangeUse for '" << name << "': ");436 switch (kind) {437 case Kind::Attr:438 case Kind::Prop:439 case Kind::Operand: {440 assert(index < 0 && "only allowed for symbol bound to result");441 auto repl = formatv(fmt, name);442 LLVM_DEBUG(dbgs() << repl << " (Operand/Attr/Prop)\n");443 return std::string(repl);444 }445 case Kind::Result: {446 if (index >= 0) {447 auto repl = formatv(fmt, formatv("{0}.getODSResults({1})", name, index));448 LLVM_DEBUG(dbgs() << repl << " (SingleResult)\n");449 return std::string(repl);450 }451 452 // We are referencing all results of the multi-result op. Each result should453 // have a value range, and then join them with `separator`.454 SmallVector<std::string, 4> values;455 values.reserve(op->getNumResults());456 457 for (int i = 0, e = op->getNumResults(); i < e; ++i) {458 values.push_back(std::string(459 formatv(fmt, formatv("{0}.getODSResults({1})", name, i))));460 }461 auto repl = llvm::join(values, separator);462 LLVM_DEBUG(dbgs() << repl << " (VariadicResult)\n");463 return repl;464 }465 case Kind::Value: {466 assert(index < 0 && "only allowed for symbol bound to result");467 assert(op == nullptr);468 auto repl = formatv(fmt, formatv("{{{0}}", name));469 LLVM_DEBUG(dbgs() << repl << " (Value)\n");470 return std::string(repl);471 }472 case Kind::MultipleValues: {473 assert(op == nullptr);474 assert(index < getSize());475 if (index >= 0) {476 std::string repl =477 formatv(fmt, std::string(formatv("{0}[{1}]", name, index)));478 LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n");479 return repl;480 }481 auto repl =482 formatv(fmt, std::string(formatv("{0}.begin(), {0}.end()", name)));483 LLVM_DEBUG(dbgs() << repl << " (MultipleValues)\n");484 return std::string(repl);485 }486 }487 llvm_unreachable("unknown kind");488}489 490bool SymbolInfoMap::bindOpArgument(DagNode node, StringRef symbol,491 const Operator &op, int argIndex,492 std::optional<int> variadicSubIndex) {493 StringRef name = getValuePackName(symbol);494 if (name != symbol) {495 auto error = formatv(496 "symbol '{0}' with trailing index cannot bind to op argument", symbol);497 PrintFatalError(loc, error);498 }499 500 Argument arg = op.getArg(argIndex);501 SymbolInfo symInfo =502 isa<NamedAttribute *>(arg) ? SymbolInfo::getAttr(&op, argIndex)503 : isa<NamedProperty *>(arg)504 ? SymbolInfo::getProp(&op, argIndex)505 : SymbolInfo::getOperand(node, &op, argIndex, variadicSubIndex);506 507 std::string key = symbol.str();508 if (symbolInfoMap.count(key)) {509 // Only non unique name for the operand is supported.510 if (symInfo.kind != SymbolInfo::Kind::Operand) {511 return false;512 }513 514 // Cannot add new operand if there is already non operand with the same515 // name.516 if (symbolInfoMap.find(key)->second.kind != SymbolInfo::Kind::Operand) {517 return false;518 }519 }520 521 symbolInfoMap.emplace(key, symInfo);522 return true;523}524 525bool SymbolInfoMap::bindOpResult(StringRef symbol, const Operator &op) {526 std::string name = getValuePackName(symbol).str();527 auto inserted = symbolInfoMap.emplace(name, SymbolInfo::getResult(&op));528 529 return symbolInfoMap.count(inserted->first) == 1;530}531 532bool SymbolInfoMap::bindValues(StringRef symbol, int numValues) {533 std::string name = getValuePackName(symbol).str();534 if (numValues > 1)535 return bindMultipleValues(name, numValues);536 return bindValue(name);537}538 539bool SymbolInfoMap::bindValue(StringRef symbol) {540 auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getValue());541 return symbolInfoMap.count(inserted->first) == 1;542}543 544bool SymbolInfoMap::bindMultipleValues(StringRef symbol, int numValues) {545 std::string name = getValuePackName(symbol).str();546 auto inserted =547 symbolInfoMap.emplace(name, SymbolInfo::getMultipleValues(numValues));548 return symbolInfoMap.count(inserted->first) == 1;549}550 551bool SymbolInfoMap::bindAttr(StringRef symbol) {552 auto inserted = symbolInfoMap.emplace(symbol.str(), SymbolInfo::getAttr());553 return symbolInfoMap.count(inserted->first) == 1;554}555 556bool SymbolInfoMap::bindProp(StringRef symbol,557 const PropConstraint &constraint) {558 auto inserted =559 symbolInfoMap.emplace(symbol.str(), SymbolInfo::getProp(&constraint));560 return symbolInfoMap.count(inserted->first) == 1;561}562 563bool SymbolInfoMap::contains(StringRef symbol) const {564 return find(symbol) != symbolInfoMap.end();565}566 567SymbolInfoMap::const_iterator SymbolInfoMap::find(StringRef key) const {568 std::string name = getValuePackName(key).str();569 570 return symbolInfoMap.find(name);571}572 573SymbolInfoMap::const_iterator574SymbolInfoMap::findBoundSymbol(StringRef key, DagNode node, const Operator &op,575 int argIndex,576 std::optional<int> variadicSubIndex) const {577 return findBoundSymbol(578 key, SymbolInfo::getOperand(node, &op, argIndex, variadicSubIndex));579}580 581SymbolInfoMap::const_iterator582SymbolInfoMap::findBoundSymbol(StringRef key,583 const SymbolInfo &symbolInfo) const {584 std::string name = getValuePackName(key).str();585 auto range = symbolInfoMap.equal_range(name);586 587 for (auto it = range.first; it != range.second; ++it)588 if (it->second.dagAndConstant == symbolInfo.dagAndConstant)589 return it;590 591 return symbolInfoMap.end();592}593 594std::pair<SymbolInfoMap::iterator, SymbolInfoMap::iterator>595SymbolInfoMap::getRangeOfEqualElements(StringRef key) {596 std::string name = getValuePackName(key).str();597 598 return symbolInfoMap.equal_range(name);599}600 601int SymbolInfoMap::count(StringRef key) const {602 std::string name = getValuePackName(key).str();603 return symbolInfoMap.count(name);604}605 606int SymbolInfoMap::getStaticValueCount(StringRef symbol) const {607 StringRef name = getValuePackName(symbol);608 if (name != symbol) {609 // If there is a trailing index inside symbol, it references just one610 // static value.611 return 1;612 }613 // Otherwise, find how many it represents by querying the symbol's info.614 return find(name)->second.getStaticValueCount();615}616 617std::string SymbolInfoMap::getValueAndRangeUse(StringRef symbol,618 const char *fmt,619 const char *separator) const {620 int index = -1;621 StringRef name = getValuePackName(symbol, &index);622 623 auto it = symbolInfoMap.find(name.str());624 if (it == symbolInfoMap.end()) {625 auto error = formatv("referencing unbound symbol '{0}'", symbol);626 PrintFatalError(loc, error);627 }628 629 return it->second.getValueAndRangeUse(name, index, fmt, separator);630}631 632std::string SymbolInfoMap::getAllRangeUse(StringRef symbol, const char *fmt,633 const char *separator) const {634 int index = -1;635 StringRef name = getValuePackName(symbol, &index);636 637 auto it = symbolInfoMap.find(name.str());638 if (it == symbolInfoMap.end()) {639 auto error = formatv("referencing unbound symbol '{0}'", symbol);640 PrintFatalError(loc, error);641 }642 643 return it->second.getAllRangeUse(name, index, fmt, separator);644}645 646void SymbolInfoMap::assignUniqueAlternativeNames() {647 llvm::StringSet<> usedNames;648 649 for (auto symbolInfoIt = symbolInfoMap.begin();650 symbolInfoIt != symbolInfoMap.end();) {651 auto range = symbolInfoMap.equal_range(symbolInfoIt->first);652 auto startRange = range.first;653 auto endRange = range.second;654 655 auto operandName = symbolInfoIt->first;656 int startSearchIndex = 0;657 for (++startRange; startRange != endRange; ++startRange) {658 // Current operand name is not unique, find a unique one659 // and set the alternative name.660 for (int i = startSearchIndex;; ++i) {661 std::string alternativeName = operandName + std::to_string(i);662 if (!usedNames.contains(alternativeName) &&663 symbolInfoMap.count(alternativeName) == 0) {664 usedNames.insert(alternativeName);665 startRange->second.alternativeName = alternativeName;666 startSearchIndex = i + 1;667 668 break;669 }670 }671 }672 673 symbolInfoIt = endRange;674 }675}676 677//===----------------------------------------------------------------------===//678// Pattern679//==----------------------------------------------------------------------===//680 681Pattern::Pattern(const Record *def, RecordOperatorMap *mapper)682 : def(*def), recordOpMap(mapper) {}683 684DagNode Pattern::getSourcePattern() const {685 return DagNode(def.getValueAsDag("sourcePattern"));686}687 688int Pattern::getNumResultPatterns() const {689 auto *results = def.getValueAsListInit("resultPatterns");690 return results->size();691}692 693DagNode Pattern::getResultPattern(unsigned index) const {694 auto *results = def.getValueAsListInit("resultPatterns");695 return DagNode(cast<DagInit>(results->getElement(index)));696}697 698void Pattern::collectSourcePatternBoundSymbols(SymbolInfoMap &infoMap) {699 LLVM_DEBUG(dbgs() << "start collecting source pattern bound symbols\n");700 collectBoundSymbols(getSourcePattern(), infoMap, /*isSrcPattern=*/true);701 LLVM_DEBUG(dbgs() << "done collecting source pattern bound symbols\n");702 703 LLVM_DEBUG(dbgs() << "start assigning alternative names for symbols\n");704 infoMap.assignUniqueAlternativeNames();705 LLVM_DEBUG(dbgs() << "done assigning alternative names for symbols\n");706}707 708void Pattern::collectResultPatternBoundSymbols(SymbolInfoMap &infoMap) {709 LLVM_DEBUG(dbgs() << "start collecting result pattern bound symbols\n");710 for (int i = 0, e = getNumResultPatterns(); i < e; ++i) {711 auto pattern = getResultPattern(i);712 collectBoundSymbols(pattern, infoMap, /*isSrcPattern=*/false);713 }714 LLVM_DEBUG(dbgs() << "done collecting result pattern bound symbols\n");715}716 717const Operator &Pattern::getSourceRootOp() {718 return getSourcePattern().getDialectOp(recordOpMap);719}720 721Operator &Pattern::getDialectOp(DagNode node) {722 return node.getDialectOp(recordOpMap);723}724 725std::vector<AppliedConstraint> Pattern::getConstraints() const {726 auto *listInit = def.getValueAsListInit("constraints");727 std::vector<AppliedConstraint> ret;728 ret.reserve(listInit->size());729 730 for (auto *it : *listInit) {731 auto *dagInit = dyn_cast<DagInit>(it);732 if (!dagInit)733 PrintFatalError(&def, "all elements in Pattern multi-entity "734 "constraints should be DAG nodes");735 736 std::vector<std::string> entities;737 entities.reserve(dagInit->arg_size());738 for (auto *argName : dagInit->getArgNames()) {739 if (!argName) {740 PrintFatalError(741 &def,742 "operands to additional constraints can only be symbol references");743 }744 entities.emplace_back(argName->getValue());745 }746 747 ret.emplace_back(cast<DefInit>(dagInit->getOperator())->getDef(),748 dagInit->getNameStr(), std::move(entities));749 }750 return ret;751}752 753int Pattern::getNumSupplementalPatterns() const {754 auto *results = def.getValueAsListInit("supplementalPatterns");755 return results->size();756}757 758DagNode Pattern::getSupplementalPattern(unsigned index) const {759 auto *results = def.getValueAsListInit("supplementalPatterns");760 return DagNode(cast<DagInit>(results->getElement(index)));761}762 763int Pattern::getBenefit() const {764 // The initial benefit value is a heuristic with number of ops in the source765 // pattern.766 int initBenefit = getSourcePattern().getNumOps();767 const DagInit *delta = def.getValueAsDag("benefitDelta");768 if (delta->getNumArgs() != 1 || !isa<IntInit>(delta->getArg(0))) {769 PrintFatalError(&def,770 "The 'addBenefit' takes and only takes one integer value");771 }772 return initBenefit + dyn_cast<IntInit>(delta->getArg(0))->getValue();773}774 775std::vector<Pattern::IdentifierLine>776Pattern::getLocation(bool forSourceOutput) const {777 std::vector<std::pair<StringRef, unsigned>> result;778 result.reserve(def.getLoc().size());779 for (auto loc : def.getLoc()) {780 unsigned buf = llvm::SrcMgr.FindBufferContainingLoc(loc);781 assert(buf && "invalid source location");782 783 StringRef bufferName =784 llvm::SrcMgr.getBufferInfo(buf).Buffer->getBufferIdentifier();785 // If we're emitting a generated file, we'd like to have some indication of786 // where our patterns came from. However, LLVM's build rules use absolute787 // paths as arguments to TableGen, and naively echoing such paths makes the788 // contents of the generated source file depend on the build location,789 // making MLIR builds substantially less reproducable. As a compromise, we790 // trim absolute paths back to only the filename component.791 if (forSourceOutput && llvm::sys::path::is_absolute(bufferName))792 bufferName = llvm::sys::path::filename(bufferName);793 794 result.emplace_back(bufferName,795 llvm::SrcMgr.getLineAndColumn(loc, buf).first);796 }797 return result;798}799 800void Pattern::verifyBind(bool result, StringRef symbolName) {801 if (!result) {802 auto err = formatv("symbol '{0}' bound more than once", symbolName);803 PrintFatalError(&def, err);804 }805}806 807void Pattern::collectBoundSymbols(DagNode tree, SymbolInfoMap &infoMap,808 bool isSrcPattern) {809 auto treeName = tree.getSymbol();810 auto numTreeArgs = tree.getNumArgs();811 812 if (tree.isNativeCodeCall()) {813 if (!treeName.empty()) {814 if (!isSrcPattern) {815 LLVM_DEBUG(dbgs() << "found symbol bound to NativeCodeCall: "816 << treeName << '\n');817 verifyBind(818 infoMap.bindValues(treeName, tree.getNumReturnsOfNativeCode()),819 treeName);820 } else {821 PrintFatalError(&def,822 formatv("binding symbol '{0}' to NativecodeCall in "823 "MatchPattern is not supported",824 treeName));825 }826 }827 828 for (int i = 0; i != numTreeArgs; ++i) {829 if (auto treeArg = tree.getArgAsNestedDag(i)) {830 // This DAG node argument is a DAG node itself. Go inside recursively.831 collectBoundSymbols(treeArg, infoMap, isSrcPattern);832 continue;833 }834 835 if (!isSrcPattern)836 continue;837 838 // We can only bind symbols to arguments in source pattern. Those839 // symbols are referenced in result patterns.840 auto treeArgName = tree.getArgName(i);841 842 // `$_` is a special symbol meaning ignore the current argument.843 if (!treeArgName.empty() && treeArgName != "_") {844 DagLeaf leaf = tree.getArgAsLeaf(i);845 846 // In (NativeCodeCall<"Foo($_self, $0, $1, $2, $3)"> I8Attr:$a, I8:$b,847 // $c, I8Prop:$d),848 if (leaf.isUnspecified()) {849 // This is case of $c, a Value without any constraints.850 verifyBind(infoMap.bindValue(treeArgName), treeArgName);851 } else if (leaf.isPropMatcher()) {852 // This is case of $d, a binding to a certain property.853 auto propConstraint = leaf.getAsPropConstraint();854 if (propConstraint.getInterfaceType().empty()) {855 PrintFatalError(&def,856 formatv("binding symbol '{0}' in NativeCodeCall to "857 "a property constraint without specifying "858 "that constraint's type is unsupported",859 treeArgName));860 }861 verifyBind(infoMap.bindProp(treeArgName, propConstraint),862 treeArgName);863 } else {864 auto constraint = leaf.getAsConstraint();865 bool isAttr = leaf.isAttrMatcher() || leaf.isEnumCase() ||866 leaf.isConstantAttr() ||867 constraint.getKind() == Constraint::Kind::CK_Attr;868 869 if (isAttr) {870 // This is case of $a, a binding to a certain attribute.871 verifyBind(infoMap.bindAttr(treeArgName), treeArgName);872 continue;873 }874 875 // This is case of $b, a binding to a certain type.876 verifyBind(infoMap.bindValue(treeArgName), treeArgName);877 }878 }879 }880 881 return;882 }883 884 if (tree.isOperation()) {885 auto &op = getDialectOp(tree);886 auto numOpArgs = op.getNumArgs();887 int numEither = 0;888 889 // We need to exclude the trailing directives and `either` directive groups890 // two operands of the operation.891 int numDirectives = 0;892 for (int i = numTreeArgs - 1; i >= 0; --i) {893 if (auto dagArg = tree.getArgAsNestedDag(i)) {894 if (dagArg.isLocationDirective() || dagArg.isReturnTypeDirective())895 ++numDirectives;896 else if (dagArg.isEither())897 ++numEither;898 }899 }900 901 if (numOpArgs != numTreeArgs - numDirectives + numEither) {902 auto err =903 formatv("op '{0}' argument number mismatch: "904 "{1} in pattern vs. {2} in definition",905 op.getOperationName(), numTreeArgs + numEither, numOpArgs);906 PrintFatalError(&def, err);907 }908 909 // The name attached to the DAG node's operator is for representing the910 // results generated from this op. It should be remembered as bound results.911 if (!treeName.empty()) {912 LLVM_DEBUG(dbgs() << "found symbol bound to op result: " << treeName913 << '\n');914 verifyBind(infoMap.bindOpResult(treeName, op), treeName);915 }916 917 // The operand in `either` DAG should be bound to the operation in the918 // parent DagNode.919 auto collectSymbolInEither = [&](DagNode parent, DagNode tree,920 int opArgIdx) {921 for (int i = 0; i < tree.getNumArgs(); ++i, ++opArgIdx) {922 if (DagNode subTree = tree.getArgAsNestedDag(i)) {923 collectBoundSymbols(subTree, infoMap, isSrcPattern);924 } else {925 auto argName = tree.getArgName(i);926 if (!argName.empty() && argName != "_") {927 verifyBind(infoMap.bindOpArgument(parent, argName, op, opArgIdx),928 argName);929 }930 }931 }932 };933 934 // The operand in `variadic` DAG should be bound to the operation in the935 // parent DagNode. The range index must be included as well to distinguish936 // (potentially) repeating argName within the `variadic` DAG.937 auto collectSymbolInVariadic = [&](DagNode parent, DagNode tree,938 int opArgIdx) {939 auto treeName = tree.getSymbol();940 if (!treeName.empty()) {941 // If treeName is specified, bind to the full variadic operand_range.942 verifyBind(infoMap.bindOpArgument(parent, treeName, op, opArgIdx,943 std::nullopt),944 treeName);945 }946 947 for (int i = 0; i < tree.getNumArgs(); ++i) {948 if (DagNode subTree = tree.getArgAsNestedDag(i)) {949 collectBoundSymbols(subTree, infoMap, isSrcPattern);950 } else {951 auto argName = tree.getArgName(i);952 if (!argName.empty() && argName != "_") {953 verifyBind(infoMap.bindOpArgument(parent, argName, op, opArgIdx,954 /*variadicSubIndex=*/i),955 argName);956 }957 }958 }959 };960 961 for (int i = 0, opArgIdx = 0; i != numTreeArgs; ++i, ++opArgIdx) {962 if (auto treeArg = tree.getArgAsNestedDag(i)) {963 if (treeArg.isEither()) {964 collectSymbolInEither(tree, treeArg, opArgIdx);965 // `either` DAG is *flattened*. For example,966 //967 // (FooOp (either arg0, arg1), arg2)968 //969 // can be viewed as:970 //971 // (FooOp arg0, arg1, arg2)972 ++opArgIdx;973 } else if (treeArg.isVariadic()) {974 collectSymbolInVariadic(tree, treeArg, opArgIdx);975 } else {976 // This DAG node argument is a DAG node itself. Go inside recursively.977 collectBoundSymbols(treeArg, infoMap, isSrcPattern);978 }979 continue;980 }981 982 if (isSrcPattern) {983 // We can only bind symbols to op arguments in source pattern. Those984 // symbols are referenced in result patterns.985 auto treeArgName = tree.getArgName(i);986 // `$_` is a special symbol meaning ignore the current argument.987 if (!treeArgName.empty() && treeArgName != "_") {988 LLVM_DEBUG(dbgs() << "found symbol bound to op argument: "989 << treeArgName << '\n');990 verifyBind(infoMap.bindOpArgument(tree, treeArgName, op, opArgIdx),991 treeArgName);992 }993 }994 }995 return;996 }997 998 if (!treeName.empty()) {999 PrintFatalError(1000 &def, formatv("binding symbol '{0}' to non-operation/native code call "1001 "unsupported right now",1002 treeName));1003 }1004}1005