2019-05-15 06:03:48 +08:00
|
|
|
//===- Pattern.cpp - Pattern wrapper class --------------------------------===//
|
2019-01-29 06:04:40 +08:00
|
|
|
//
|
2020-01-26 11:58:30 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2019-12-24 01:35:36 +08:00
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2019-01-29 06:04:40 +08:00
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-01-29 06:04:40 +08:00
|
|
|
//
|
|
|
|
// Pattern wrapper class to simplify using TableGen Record defining a MLIR
|
|
|
|
// Pattern.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "mlir/TableGen/Pattern.h"
|
2020-03-01 09:11:12 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2019-01-29 06:04:40 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2019-10-17 22:25:50 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2019-04-09 06:14:59 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
#include "llvm/TableGen/Error.h"
|
2019-01-29 06:04:40 +08:00
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
|
2019-10-17 22:25:50 +08:00
|
|
|
#define DEBUG_TYPE "mlir-tblgen-pattern"
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
using namespace mlir;
|
|
|
|
|
2019-04-30 00:24:09 +08:00
|
|
|
using llvm::formatv;
|
2019-01-29 06:04:40 +08:00
|
|
|
using mlir::tblgen::Operator;
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DagLeaf
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-02-02 07:40:22 +08:00
|
|
|
bool tblgen::DagLeaf::isUnspecified() const {
|
2019-04-01 23:58:53 +08:00
|
|
|
return dyn_cast_or_null<llvm::UnsetInit>(def);
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::DagLeaf::isOperandMatcher() const {
|
|
|
|
// Operand matchers specify a type constraint.
|
2019-04-01 23:58:53 +08:00
|
|
|
return isSubClassOf("TypeConstraint");
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::DagLeaf::isAttrMatcher() const {
|
2019-03-13 04:55:50 +08:00
|
|
|
// Attribute matchers specify an attribute constraint.
|
2019-04-01 23:58:53 +08:00
|
|
|
return isSubClassOf("AttrConstraint");
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
2019-04-23 05:13:45 +08:00
|
|
|
bool tblgen::DagLeaf::isNativeCodeCall() const {
|
|
|
|
return isSubClassOf("NativeCodeCall");
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::DagLeaf::isConstantAttr() const {
|
2019-04-01 23:58:53 +08:00
|
|
|
return isSubClassOf("ConstantAttr");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::DagLeaf::isEnumAttrCase() const {
|
2019-07-01 20:26:14 +08:00
|
|
|
return isSubClassOf("EnumAttrCaseInfo");
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
tblgen::Constraint tblgen::DagLeaf::getAsConstraint() const {
|
|
|
|
assert((isOperandMatcher() || isAttrMatcher()) &&
|
|
|
|
"the DAG leaf must be operand or attribute");
|
|
|
|
return Constraint(cast<llvm::DefInit>(def)->getDef());
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::ConstantAttr tblgen::DagLeaf::getAsConstantAttr() const {
|
|
|
|
assert(isConstantAttr() && "the DAG leaf must be constant attribute");
|
|
|
|
return ConstantAttr(cast<llvm::DefInit>(def));
|
|
|
|
}
|
|
|
|
|
2019-04-01 23:58:53 +08:00
|
|
|
tblgen::EnumAttrCase tblgen::DagLeaf::getAsEnumAttrCase() const {
|
|
|
|
assert(isEnumAttrCase() && "the DAG leaf must be an enum attribute case");
|
|
|
|
return EnumAttrCase(cast<llvm::DefInit>(def));
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:40:22 +08:00
|
|
|
std::string tblgen::DagLeaf::getConditionTemplate() const {
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
return getAsConstraint().getConditionTemplate();
|
2019-02-02 07:40:22 +08:00
|
|
|
}
|
|
|
|
|
2019-04-23 05:13:45 +08:00
|
|
|
llvm::StringRef tblgen::DagLeaf::getNativeCodeTemplate() const {
|
|
|
|
assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
|
|
|
|
return cast<llvm::DefInit>(def)->getDef()->getValueAsString("expression");
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 23:58:53 +08:00
|
|
|
bool tblgen::DagLeaf::isSubClassOf(StringRef superclass) const {
|
|
|
|
if (auto *defInit = dyn_cast_or_null<llvm::DefInit>(def))
|
|
|
|
return defInit->getDef()->isSubClassOf(superclass);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-17 22:25:50 +08:00
|
|
|
void tblgen::DagLeaf::print(raw_ostream &os) const {
|
|
|
|
if (def)
|
|
|
|
def->print(os);
|
|
|
|
}
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DagNode
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-04-23 05:13:45 +08:00
|
|
|
bool tblgen::DagNode::isNativeCodeCall() const {
|
|
|
|
if (auto *defInit = dyn_cast_or_null<llvm::DefInit>(node->getOperator()))
|
|
|
|
return defInit->getDef()->isSubClassOf("NativeCodeCall");
|
|
|
|
return false;
|
2019-03-13 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
2019-05-25 10:35:23 +08:00
|
|
|
bool tblgen::DagNode::isOperation() const {
|
2020-04-07 22:44:19 +08:00
|
|
|
return !isNativeCodeCall() && !isReplaceWithValue() && !isLocationDirective();
|
2019-05-25 10:35:23 +08:00
|
|
|
}
|
|
|
|
|
2019-04-23 05:13:45 +08:00
|
|
|
llvm::StringRef tblgen::DagNode::getNativeCodeTemplate() const {
|
|
|
|
assert(isNativeCodeCall() && "the DAG leaf must be NativeCodeCall");
|
2019-03-13 04:55:50 +08:00
|
|
|
return cast<llvm::DefInit>(node->getOperator())
|
|
|
|
->getDef()
|
2019-04-23 05:13:45 +08:00
|
|
|
->getValueAsString("expression");
|
2019-03-13 04:55:50 +08:00
|
|
|
}
|
|
|
|
|
Fix support for auxiliary ops in declarative rewrite rules
We allow to generate more ops than what are needed for replacing
the matched root op. Only the last N static values generated are
used as replacement; the others serve as auxiliary ops/values for
building the replacement.
With the introduction of multi-result op support, an op, if used
as a whole, may be used to replace multiple static values of
the matched root op. We need to consider this when calculating
the result range an generated op is to replace.
For example, we can have the following pattern:
```tblgen
def : Pattern<(ThreeResultOp ...),
[(OneResultOp ...), (OneResultOp ...), (OneResultOp ...)]>;
// Two op to replace all three results
def : Pattern<(ThreeResultOp ...),
[(TwoResultOp ...), (OneResultOp ...)]>;
// One op to replace all three results
def : Pat<(ThreeResultOp ...), (ThreeResultOp ...)>;
def : Pattern<(ThreeResultOp ...),
[(AuxiliaryOp ...), (ThreeResultOp ...)]>;
```
PiperOrigin-RevId: 261017235
2019-08-01 07:03:13 +08:00
|
|
|
llvm::StringRef tblgen::DagNode::getSymbol() const {
|
2019-02-14 06:30:40 +08:00
|
|
|
return node->getNameStr();
|
|
|
|
}
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
Operator &tblgen::DagNode::getDialectOp(RecordOperatorMap *mapper) const {
|
|
|
|
llvm::Record *opDef = cast<llvm::DefInit>(node->getOperator())->getDef();
|
2019-04-13 00:52:11 +08:00
|
|
|
auto it = mapper->find(opDef);
|
|
|
|
if (it != mapper->end())
|
|
|
|
return *it->second;
|
2019-08-18 02:05:35 +08:00
|
|
|
return *mapper->try_emplace(opDef, std::make_unique<Operator>(opDef))
|
2019-04-13 00:52:11 +08:00
|
|
|
.first->second;
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
2019-05-04 10:48:57 +08:00
|
|
|
int tblgen::DagNode::getNumOps() const {
|
|
|
|
int count = isReplaceWithValue() ? 0 : 1;
|
|
|
|
for (int i = 0, e = getNumArgs(); i != e; ++i) {
|
2019-01-29 06:04:40 +08:00
|
|
|
if (auto child = getArgAsNestedDag(i))
|
|
|
|
count += child.getNumOps();
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2019-05-04 10:48:57 +08:00
|
|
|
int tblgen::DagNode::getNumArgs() const { return node->getNumArgs(); }
|
2019-01-29 06:04:40 +08:00
|
|
|
|
|
|
|
bool tblgen::DagNode::isNestedDagArg(unsigned index) const {
|
|
|
|
return isa<llvm::DagInit>(node->getArg(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::DagNode tblgen::DagNode::getArgAsNestedDag(unsigned index) const {
|
|
|
|
return DagNode(dyn_cast_or_null<llvm::DagInit>(node->getArg(index)));
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:40:22 +08:00
|
|
|
tblgen::DagLeaf tblgen::DagNode::getArgAsLeaf(unsigned index) const {
|
|
|
|
assert(!isNestedDagArg(index));
|
|
|
|
return DagLeaf(node->getArg(index));
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef tblgen::DagNode::getArgName(unsigned index) const {
|
|
|
|
return node->getArgNameStr(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::DagNode::isReplaceWithValue() const {
|
|
|
|
auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
|
|
|
|
return dagOpDef->getName() == "replaceWithValue";
|
|
|
|
}
|
|
|
|
|
2020-04-07 22:44:19 +08:00
|
|
|
bool tblgen::DagNode::isLocationDirective() const {
|
|
|
|
auto *dagOpDef = cast<llvm::DefInit>(node->getOperator())->getDef();
|
|
|
|
return dagOpDef->getName() == "location";
|
|
|
|
}
|
|
|
|
|
2019-10-17 22:25:50 +08:00
|
|
|
void tblgen::DagNode::print(raw_ostream &os) const {
|
|
|
|
if (node)
|
|
|
|
node->print(os);
|
|
|
|
}
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// SymbolInfoMap
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
StringRef tblgen::SymbolInfoMap::getValuePackName(StringRef symbol,
|
|
|
|
int *index) {
|
|
|
|
StringRef name, indexStr;
|
|
|
|
int idx = -1;
|
|
|
|
std::tie(name, indexStr) = symbol.rsplit("__");
|
|
|
|
|
|
|
|
if (indexStr.consumeInteger(10, idx)) {
|
|
|
|
// The second part is not an index; we return the whole symbol as-is.
|
|
|
|
return symbol;
|
|
|
|
}
|
|
|
|
if (index) {
|
|
|
|
*index = idx;
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::SymbolInfoMap::SymbolInfo::SymbolInfo(const Operator *op,
|
|
|
|
SymbolInfo::Kind kind,
|
|
|
|
Optional<int> index)
|
|
|
|
: op(op), kind(kind), argIndex(index) {}
|
|
|
|
|
|
|
|
int tblgen::SymbolInfoMap::SymbolInfo::getStaticValueCount() const {
|
|
|
|
switch (kind) {
|
|
|
|
case Kind::Attr:
|
|
|
|
case Kind::Operand:
|
|
|
|
case Kind::Value:
|
|
|
|
return 1;
|
|
|
|
case Kind::Result:
|
|
|
|
return op->getNumResults();
|
|
|
|
}
|
2019-08-14 05:22:58 +08:00
|
|
|
llvm_unreachable("unknown kind");
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
tblgen::SymbolInfoMap::SymbolInfo::getVarDecl(StringRef name) const {
|
2019-11-15 03:02:52 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "getVarDecl for '" << name << "': ");
|
2019-08-10 10:03:58 +08:00
|
|
|
switch (kind) {
|
|
|
|
case Kind::Attr: {
|
|
|
|
auto type =
|
|
|
|
op->getArg(*argIndex).get<NamedAttribute *>()->attr.getStorageType();
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(formatv("{0} {1};\n", type, name));
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
2019-08-21 20:35:07 +08:00
|
|
|
case Kind::Operand: {
|
|
|
|
// Use operand range for captured operands (to support potential variadic
|
|
|
|
// operands).
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(
|
|
|
|
formatv("Operation::operand_range {0}(op0->getOperands());\n", name));
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
2019-08-10 10:03:58 +08:00
|
|
|
case Kind::Value: {
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(formatv("ArrayRef<Value> {0};\n", name));
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
case Kind::Result: {
|
2019-08-21 20:35:07 +08:00
|
|
|
// Use the op itself for captured results.
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(formatv("{0} {1};\n", op->getQualCppClassName(), name));
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
}
|
2019-08-14 05:22:58 +08:00
|
|
|
llvm_unreachable("unknown kind");
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
|
2019-08-21 20:35:07 +08:00
|
|
|
std::string tblgen::SymbolInfoMap::SymbolInfo::getValueAndRangeUse(
|
|
|
|
StringRef name, int index, const char *fmt, const char *separator) const {
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "getValueAndRangeUse for '" << name << "': ");
|
2019-08-21 20:35:07 +08:00
|
|
|
switch (kind) {
|
|
|
|
case Kind::Attr: {
|
|
|
|
assert(index < 0);
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, name);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (Attr)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
|
|
|
case Kind::Operand: {
|
|
|
|
assert(index < 0);
|
|
|
|
auto *operand = op->getArg(*argIndex).get<NamedTypeConstraint *>();
|
|
|
|
// If this operand is variadic, then return a range. Otherwise, return the
|
|
|
|
// value itself.
|
|
|
|
if (operand->isVariadic()) {
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, name);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicOperand)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, formatv("(*{0}.begin())", name));
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (SingleOperand)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
|
|
|
case Kind::Result: {
|
|
|
|
// If `index` is greater than zero, then we are referencing a specific
|
|
|
|
// result of a multi-result op. The result can still be variadic.
|
|
|
|
if (index >= 0) {
|
2020-01-29 03:23:46 +08:00
|
|
|
std::string v =
|
|
|
|
std::string(formatv("{0}.getODSResults({1})", name, index));
|
2019-08-21 20:35:07 +08:00
|
|
|
if (!op->getResult(index).isVariadic())
|
2020-01-29 03:23:46 +08:00
|
|
|
v = std::string(formatv("(*{0}.begin())", v));
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, v);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-10-18 00:01:56 +08:00
|
|
|
// If this op has no result at all but still we bind a symbol to it, it
|
|
|
|
// means we want to capture the op itself.
|
|
|
|
if (op->getNumResults() == 0) {
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << name << " (Op)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(name);
|
2019-10-18 00:01:56 +08:00
|
|
|
}
|
|
|
|
|
2019-08-21 20:35:07 +08:00
|
|
|
// We are referencing all results of the multi-result op. A specific result
|
|
|
|
// can either be a value or a range. Then join them with `separator`.
|
|
|
|
SmallVector<std::string, 4> values;
|
|
|
|
values.reserve(op->getNumResults());
|
|
|
|
|
|
|
|
for (int i = 0, e = op->getNumResults(); i < e; ++i) {
|
2020-01-29 03:23:46 +08:00
|
|
|
std::string v = std::string(formatv("{0}.getODSResults({1})", name, i));
|
2019-08-21 20:35:07 +08:00
|
|
|
if (!op->getResult(i).isVariadic()) {
|
2020-01-29 03:23:46 +08:00
|
|
|
v = std::string(formatv("(*{0}.begin())", v));
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
2020-01-29 03:23:46 +08:00
|
|
|
values.push_back(std::string(formatv(fmt, v)));
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = llvm::join(values, separator);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
|
|
|
|
return repl;
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
|
|
|
case Kind::Value: {
|
|
|
|
assert(index < 0);
|
|
|
|
assert(op == nullptr);
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, name);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
|
|
|
}
|
2019-09-26 10:04:59 +08:00
|
|
|
llvm_unreachable("unknown kind");
|
2019-08-21 20:35:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string tblgen::SymbolInfoMap::SymbolInfo::getAllRangeUse(
|
|
|
|
StringRef name, int index, const char *fmt, const char *separator) const {
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "getAllRangeUse for '" << name << "': ");
|
2019-08-10 10:03:58 +08:00
|
|
|
switch (kind) {
|
|
|
|
case Kind::Attr:
|
|
|
|
case Kind::Operand: {
|
|
|
|
assert(index < 0 && "only allowed for symbol bound to result");
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, name);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (Operand/Attr)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
case Kind::Result: {
|
|
|
|
if (index >= 0) {
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, formatv("{0}.getODSResults({1})", name, index));
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (SingleResult)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
|
2019-08-21 20:35:07 +08:00
|
|
|
// We are referencing all results of the multi-result op. Each result should
|
|
|
|
// have a value range, and then join them with `separator`.
|
2019-08-10 10:03:58 +08:00
|
|
|
SmallVector<std::string, 4> values;
|
2019-08-21 20:35:07 +08:00
|
|
|
values.reserve(op->getNumResults());
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
for (int i = 0, e = op->getNumResults(); i < e; ++i) {
|
2020-01-29 03:23:46 +08:00
|
|
|
values.push_back(std::string(
|
|
|
|
formatv(fmt, formatv("{0}.getODSResults({1})", name, i))));
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = llvm::join(values, separator);
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (VariadicResult)\n");
|
|
|
|
return repl;
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
case Kind::Value: {
|
|
|
|
assert(index < 0 && "only allowed for symbol bound to result");
|
|
|
|
assert(op == nullptr);
|
2019-10-17 22:25:50 +08:00
|
|
|
auto repl = formatv(fmt, formatv("{{{0}}", name));
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << repl << " (Value)\n");
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(repl);
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
}
|
2019-08-14 05:22:58 +08:00
|
|
|
llvm_unreachable("unknown kind");
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::SymbolInfoMap::bindOpArgument(StringRef symbol, const Operator &op,
|
|
|
|
int argIndex) {
|
|
|
|
StringRef name = getValuePackName(symbol);
|
|
|
|
if (name != symbol) {
|
|
|
|
auto error = formatv(
|
|
|
|
"symbol '{0}' with trailing index cannot bind to op argument", symbol);
|
|
|
|
PrintFatalError(loc, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto symInfo = op.getArg(argIndex).is<NamedAttribute *>()
|
|
|
|
? SymbolInfo::getAttr(&op, argIndex)
|
|
|
|
: SymbolInfo::getOperand(&op, argIndex);
|
|
|
|
|
|
|
|
return symbolInfoMap.insert({symbol, symInfo}).second;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::SymbolInfoMap::bindOpResult(StringRef symbol, const Operator &op) {
|
|
|
|
StringRef name = getValuePackName(symbol);
|
|
|
|
return symbolInfoMap.insert({name, SymbolInfo::getResult(&op)}).second;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::SymbolInfoMap::bindValue(StringRef symbol) {
|
|
|
|
return symbolInfoMap.insert({symbol, SymbolInfo::getValue()}).second;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::SymbolInfoMap::contains(StringRef symbol) const {
|
|
|
|
return find(symbol) != symbolInfoMap.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::SymbolInfoMap::const_iterator
|
|
|
|
tblgen::SymbolInfoMap::find(StringRef key) const {
|
|
|
|
StringRef name = getValuePackName(key);
|
|
|
|
return symbolInfoMap.find(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
int tblgen::SymbolInfoMap::getStaticValueCount(StringRef symbol) const {
|
|
|
|
StringRef name = getValuePackName(symbol);
|
|
|
|
if (name != symbol) {
|
|
|
|
// If there is a trailing index inside symbol, it references just one
|
|
|
|
// static value.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// Otherwise, find how many it represents by querying the symbol's info.
|
|
|
|
return find(name)->getValue().getStaticValueCount();
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
2019-08-21 20:35:07 +08:00
|
|
|
std::string
|
|
|
|
tblgen::SymbolInfoMap::getValueAndRangeUse(StringRef symbol, const char *fmt,
|
|
|
|
const char *separator) const {
|
|
|
|
int index = -1;
|
|
|
|
StringRef name = getValuePackName(symbol, &index);
|
|
|
|
|
|
|
|
auto it = symbolInfoMap.find(name);
|
|
|
|
if (it == symbolInfoMap.end()) {
|
|
|
|
auto error = formatv("referencing unbound symbol '{0}'", symbol);
|
|
|
|
PrintFatalError(loc, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return it->getValue().getValueAndRangeUse(name, index, fmt, separator);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string tblgen::SymbolInfoMap::getAllRangeUse(StringRef symbol,
|
|
|
|
const char *fmt,
|
|
|
|
const char *separator) const {
|
2019-08-10 10:03:58 +08:00
|
|
|
int index = -1;
|
|
|
|
StringRef name = getValuePackName(symbol, &index);
|
|
|
|
|
|
|
|
auto it = symbolInfoMap.find(name);
|
|
|
|
if (it == symbolInfoMap.end()) {
|
|
|
|
auto error = formatv("referencing unbound symbol '{0}'", symbol);
|
|
|
|
PrintFatalError(loc, error);
|
|
|
|
}
|
|
|
|
|
2019-08-21 20:35:07 +08:00
|
|
|
return it->getValue().getAllRangeUse(name, index, fmt, separator);
|
2019-08-10 10:03:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Pattern
|
|
|
|
//==----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
tblgen::Pattern::Pattern(const llvm::Record *def, RecordOperatorMap *mapper)
|
|
|
|
: def(*def), recordOpMap(mapper) {}
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
tblgen::DagNode tblgen::Pattern::getSourcePattern() const {
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
return tblgen::DagNode(def.getValueAsDag("sourcePattern"));
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
Fix support for auxiliary ops in declarative rewrite rules
We allow to generate more ops than what are needed for replacing
the matched root op. Only the last N static values generated are
used as replacement; the others serve as auxiliary ops/values for
building the replacement.
With the introduction of multi-result op support, an op, if used
as a whole, may be used to replace multiple static values of
the matched root op. We need to consider this when calculating
the result range an generated op is to replace.
For example, we can have the following pattern:
```tblgen
def : Pattern<(ThreeResultOp ...),
[(OneResultOp ...), (OneResultOp ...), (OneResultOp ...)]>;
// Two op to replace all three results
def : Pattern<(ThreeResultOp ...),
[(TwoResultOp ...), (OneResultOp ...)]>;
// One op to replace all three results
def : Pat<(ThreeResultOp ...), (ThreeResultOp ...)>;
def : Pattern<(ThreeResultOp ...),
[(AuxiliaryOp ...), (ThreeResultOp ...)]>;
```
PiperOrigin-RevId: 261017235
2019-08-01 07:03:13 +08:00
|
|
|
int tblgen::Pattern::getNumResultPatterns() const {
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
auto *results = def.getValueAsListInit("resultPatterns");
|
2019-01-29 06:04:40 +08:00
|
|
|
return results->size();
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::DagNode tblgen::Pattern::getResultPattern(unsigned index) const {
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
auto *results = def.getValueAsListInit("resultPatterns");
|
2019-01-29 06:04:40 +08:00
|
|
|
return tblgen::DagNode(cast<llvm::DagInit>(results->getElement(index)));
|
|
|
|
}
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
void tblgen::Pattern::collectSourcePatternBoundSymbols(
|
|
|
|
tblgen::SymbolInfoMap &infoMap) {
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "start collecting source pattern bound symbols\n");
|
2019-08-10 10:03:58 +08:00
|
|
|
collectBoundSymbols(getSourcePattern(), infoMap, /*isSrcPattern=*/true);
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "done collecting source pattern bound symbols\n");
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
void tblgen::Pattern::collectResultPatternBoundSymbols(
|
|
|
|
tblgen::SymbolInfoMap &infoMap) {
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "start collecting result pattern bound symbols\n");
|
2019-08-10 10:03:58 +08:00
|
|
|
for (int i = 0, e = getNumResultPatterns(); i < e; ++i) {
|
|
|
|
auto pattern = getResultPattern(i);
|
|
|
|
collectBoundSymbols(pattern, infoMap, /*isSrcPattern=*/false);
|
|
|
|
}
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "done collecting result pattern bound symbols\n");
|
2019-02-14 06:30:40 +08:00
|
|
|
}
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
const tblgen::Operator &tblgen::Pattern::getSourceRootOp() {
|
|
|
|
return getSourcePattern().getDialectOp(recordOpMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::Operator &tblgen::Pattern::getDialectOp(DagNode node) {
|
|
|
|
return node.getDialectOp(recordOpMap);
|
|
|
|
}
|
2019-02-14 06:30:40 +08:00
|
|
|
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
std::vector<tblgen::AppliedConstraint> tblgen::Pattern::getConstraints() const {
|
2019-02-14 06:30:40 +08:00
|
|
|
auto *listInit = def.getValueAsListInit("constraints");
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
std::vector<tblgen::AppliedConstraint> ret;
|
2019-02-14 06:30:40 +08:00
|
|
|
ret.reserve(listInit->size());
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
|
2019-02-14 06:30:40 +08:00
|
|
|
for (auto it : *listInit) {
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
auto *dagInit = dyn_cast<llvm::DagInit>(it);
|
|
|
|
if (!dagInit)
|
2019-10-20 15:11:03 +08:00
|
|
|
PrintFatalError(def.getLoc(), "all elements in Pattern multi-entity "
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
"constraints should be DAG nodes");
|
|
|
|
|
|
|
|
std::vector<std::string> entities;
|
|
|
|
entities.reserve(dagInit->arg_size());
|
2019-10-31 02:12:21 +08:00
|
|
|
for (auto *argName : dagInit->getArgNames()) {
|
|
|
|
if (!argName) {
|
|
|
|
PrintFatalError(
|
|
|
|
def.getLoc(),
|
|
|
|
"operands to additional constraints can only be symbol references");
|
|
|
|
}
|
2020-01-29 03:23:46 +08:00
|
|
|
entities.push_back(std::string(argName->getValue()));
|
2019-10-31 02:12:21 +08:00
|
|
|
}
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
|
|
|
|
ret.emplace_back(cast<llvm::DefInit>(dagInit->getOperator())->getDef(),
|
2019-08-02 02:50:47 +08:00
|
|
|
dagInit->getNameStr(), std::move(entities));
|
2019-02-14 06:30:40 +08:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2019-03-30 00:36:09 +08:00
|
|
|
|
|
|
|
int tblgen::Pattern::getBenefit() const {
|
2019-04-02 00:39:59 +08:00
|
|
|
// The initial benefit value is a heuristic with number of ops in the source
|
2019-03-30 00:36:09 +08:00
|
|
|
// pattern.
|
2019-04-02 00:39:59 +08:00
|
|
|
int initBenefit = getSourcePattern().getNumOps();
|
2019-03-30 00:36:09 +08:00
|
|
|
llvm::DagInit *delta = def.getValueAsDag("benefitDelta");
|
2019-04-02 00:39:59 +08:00
|
|
|
if (delta->getNumArgs() != 1 || !isa<llvm::IntInit>(delta->getArg(0))) {
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
"The 'addBenefit' takes and only takes one integer value");
|
|
|
|
}
|
|
|
|
return initBenefit + dyn_cast<llvm::IntInit>(delta->getArg(0))->getValue();
|
2019-03-30 00:36:09 +08:00
|
|
|
}
|
2019-04-09 06:14:59 +08:00
|
|
|
|
2019-05-24 07:08:52 +08:00
|
|
|
std::vector<tblgen::Pattern::IdentifierLine>
|
|
|
|
tblgen::Pattern::getLocation() const {
|
|
|
|
std::vector<std::pair<StringRef, unsigned>> result;
|
|
|
|
result.reserve(def.getLoc().size());
|
|
|
|
for (auto loc : def.getLoc()) {
|
|
|
|
unsigned buf = llvm::SrcMgr.FindBufferContainingLoc(loc);
|
|
|
|
assert(buf && "invalid source location");
|
|
|
|
result.emplace_back(
|
|
|
|
llvm::SrcMgr.getBufferInfo(buf).Buffer->getBufferIdentifier(),
|
|
|
|
llvm::SrcMgr.getLineAndColumn(loc, buf).first);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-08-10 10:03:58 +08:00
|
|
|
void tblgen::Pattern::collectBoundSymbols(DagNode tree, SymbolInfoMap &infoMap,
|
Fix support for auxiliary ops in declarative rewrite rules
We allow to generate more ops than what are needed for replacing
the matched root op. Only the last N static values generated are
used as replacement; the others serve as auxiliary ops/values for
building the replacement.
With the introduction of multi-result op support, an op, if used
as a whole, may be used to replace multiple static values of
the matched root op. We need to consider this when calculating
the result range an generated op is to replace.
For example, we can have the following pattern:
```tblgen
def : Pattern<(ThreeResultOp ...),
[(OneResultOp ...), (OneResultOp ...), (OneResultOp ...)]>;
// Two op to replace all three results
def : Pattern<(ThreeResultOp ...),
[(TwoResultOp ...), (OneResultOp ...)]>;
// One op to replace all three results
def : Pat<(ThreeResultOp ...), (ThreeResultOp ...)>;
def : Pattern<(ThreeResultOp ...),
[(AuxiliaryOp ...), (ThreeResultOp ...)]>;
```
PiperOrigin-RevId: 261017235
2019-08-01 07:03:13 +08:00
|
|
|
bool isSrcPattern) {
|
|
|
|
auto treeName = tree.getSymbol();
|
|
|
|
if (!tree.isOperation()) {
|
|
|
|
if (!treeName.empty()) {
|
|
|
|
PrintFatalError(
|
|
|
|
def.getLoc(),
|
|
|
|
formatv("binding symbol '{0}' to non-operation unsupported right now",
|
|
|
|
treeName));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-09 06:14:59 +08:00
|
|
|
auto &op = getDialectOp(tree);
|
|
|
|
auto numOpArgs = op.getNumArgs();
|
|
|
|
auto numTreeArgs = tree.getNumArgs();
|
|
|
|
|
2020-04-07 22:44:19 +08:00
|
|
|
// The pattern might have the last argument specifying the location.
|
|
|
|
bool hasLocDirective = false;
|
|
|
|
if (numTreeArgs != 0) {
|
|
|
|
if (auto lastArg = tree.getArgAsNestedDag(numTreeArgs - 1))
|
|
|
|
hasLocDirective = lastArg.isLocationDirective();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numOpArgs != numTreeArgs - hasLocDirective) {
|
2019-08-10 10:03:58 +08:00
|
|
|
auto err = formatv("op '{0}' argument number mismatch: "
|
|
|
|
"{1} in pattern vs. {2} in definition",
|
|
|
|
op.getOperationName(), numTreeArgs, numOpArgs);
|
|
|
|
PrintFatalError(def.getLoc(), err);
|
2019-04-09 06:14:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// The name attached to the DAG node's operator is for representing the
|
|
|
|
// results generated from this op. It should be remembered as bound results.
|
2019-08-10 10:03:58 +08:00
|
|
|
if (!treeName.empty()) {
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
|
|
<< "found symbol bound to op result: " << treeName << '\n');
|
2019-08-10 10:03:58 +08:00
|
|
|
if (!infoMap.bindOpResult(treeName, op))
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
formatv("symbol '{0}' bound more than once", treeName));
|
|
|
|
}
|
2019-04-09 06:14:59 +08:00
|
|
|
|
2019-05-04 10:48:57 +08:00
|
|
|
for (int i = 0; i != numTreeArgs; ++i) {
|
2019-04-09 06:14:59 +08:00
|
|
|
if (auto treeArg = tree.getArgAsNestedDag(i)) {
|
|
|
|
// This DAG node argument is a DAG node itself. Go inside recursively.
|
2019-08-10 10:03:58 +08:00
|
|
|
collectBoundSymbols(treeArg, infoMap, isSrcPattern);
|
Fix support for auxiliary ops in declarative rewrite rules
We allow to generate more ops than what are needed for replacing
the matched root op. Only the last N static values generated are
used as replacement; the others serve as auxiliary ops/values for
building the replacement.
With the introduction of multi-result op support, an op, if used
as a whole, may be used to replace multiple static values of
the matched root op. We need to consider this when calculating
the result range an generated op is to replace.
For example, we can have the following pattern:
```tblgen
def : Pattern<(ThreeResultOp ...),
[(OneResultOp ...), (OneResultOp ...), (OneResultOp ...)]>;
// Two op to replace all three results
def : Pattern<(ThreeResultOp ...),
[(TwoResultOp ...), (OneResultOp ...)]>;
// One op to replace all three results
def : Pat<(ThreeResultOp ...), (ThreeResultOp ...)>;
def : Pattern<(ThreeResultOp ...),
[(AuxiliaryOp ...), (ThreeResultOp ...)]>;
```
PiperOrigin-RevId: 261017235
2019-08-01 07:03:13 +08:00
|
|
|
} else if (isSrcPattern) {
|
|
|
|
// We can only bind symbols to op arguments in source pattern. Those
|
|
|
|
// symbols are referenced in result patterns.
|
2019-04-09 06:14:59 +08:00
|
|
|
auto treeArgName = tree.getArgName(i);
|
2019-12-02 23:54:23 +08:00
|
|
|
// `$_` is a special symbol meaning ignore the current argument.
|
|
|
|
if (!treeArgName.empty() && treeArgName != "_") {
|
2019-10-17 22:25:50 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "found symbol bound to op argument: "
|
|
|
|
<< treeArgName << '\n');
|
2019-08-10 10:03:58 +08:00
|
|
|
if (!infoMap.bindOpArgument(treeArgName, op, i)) {
|
|
|
|
auto err = formatv("symbol '{0}' bound more than once", treeArgName);
|
|
|
|
PrintFatalError(def.getLoc(), err);
|
|
|
|
}
|
|
|
|
}
|
2019-04-09 06:14:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|