TableGen/ISel: Allow PatFrag predicate code to access captured operands

Summary:
This simplifies writing predicates for pattern fragments that are
automatically re-associated or commuted.

For example, a followup patch adds patterns for fragments of the form
(add (shl $x, $y), $z) to the AMDGPU backend. Such patterns are
automatically commuted to (add $z, (shl $x, $y)), which makes it basically
impossible to refer to $x, $y, and $z generically in the PredicateCode.

With this change, the PredicateCode can refer to $x, $y, and $z simply
as `Operands[i]`.

Test confirmed that there are no changes to any of the generated files
when building all (non-experimental) targets.

Change-Id: I61c00ace7eed42c1d4edc4c5351174b56b77a79c

Reviewers: arsenm, rampitec, RKSimon, craig.topper, hfinkel, uweigand

Subscribers: wdng, tpr, llvm-commits

Differential Revision: https://reviews.llvm.org/D51994

llvm-svn: 347992
This commit is contained in:
Nicolai Haehnle 2018-11-30 14:15:13 +00:00
parent 4830fdd21a
commit 445b0b6260
11 changed files with 315 additions and 92 deletions

View File

@ -132,6 +132,7 @@ public:
OPC_CheckChild2Same, OPC_CheckChild3Same,
OPC_CheckPatternPredicate,
OPC_CheckPredicate,
OPC_CheckPredicateWithOperands,
OPC_CheckOpcode,
OPC_SwitchOpcode,
OPC_CheckType,
@ -267,6 +268,17 @@ public:
llvm_unreachable("Tblgen should generate the implementation of this!");
}
/// CheckNodePredicateWithOperands - This function is generated by tblgen in
/// the target.
/// It runs node predicate number PredNo and returns true if it succeeds or
/// false if it fails. The number is a private implementation detail to the
/// code tblgen produces.
virtual bool CheckNodePredicateWithOperands(
SDNode *N, unsigned PredNo,
const SmallVectorImpl<SDValue> &Operands) const {
llvm_unreachable("Tblgen should generate the implementation of this!");
}
virtual bool CheckComplexPattern(SDNode *Root, SDNode *Parent, SDValue N,
unsigned PatternNo,
SmallVectorImpl<std::pair<SDValue, SDNode*> > &Result) {

View File

@ -630,6 +630,15 @@ class PatFrags<dag ops, list<dag> frags, code pred = [{}],
code ImmediateCode = [{}];
SDNodeXForm OperandTransform = xform;
// When this is set, the PredicateCode may refer to a constant Operands
// vector which contains the captured nodes of the DAG, in the order listed
// by the Operands field above.
//
// This is useful when Fragments involves associative / commutative
// operators: a single piece of code can easily refer to all operands even
// when re-associated / commuted variants of the fragment are matched.
bit PredicateCodeUsesOperands = 0;
// Define a few pre-packaged predicates. This helps GlobalISel import
// existing rules from SelectionDAG for many common cases.
// They will be tested prior to the code in pred and must not be used in

View File

@ -3207,6 +3207,18 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
N.getNode()))
break;
continue;
case OPC_CheckPredicateWithOperands: {
unsigned OpNum = MatcherTable[MatcherIndex++];
SmallVector<SDValue, 8> Operands;
for (unsigned i = 0; i < OpNum; ++i)
Operands.push_back(RecordedNodes[MatcherTable[MatcherIndex++]].first);
unsigned PredNo = MatcherTable[MatcherIndex++];
if (!CheckNodePredicateWithOperands(N.getNode(), PredNo, Operands))
break;
continue;
}
case OPC_CheckComplexPat: {
unsigned CPNum = MatcherTable[MatcherIndex++];
unsigned RecNo = MatcherTable[MatcherIndex++];

View File

@ -824,6 +824,20 @@ TypeInfer::ValidateOnExit::~ValidateOnExit() {
}
#endif
//===----------------------------------------------------------------------===//
// ScopedName Implementation
//===----------------------------------------------------------------------===//
bool ScopedName::operator==(const ScopedName &o) const {
return Scope == o.Scope && Identifier == o.Identifier;
}
bool ScopedName::operator!=(const ScopedName &o) const {
return !(*this == o);
}
//===----------------------------------------------------------------------===//
// TreePredicateFn Implementation
//===----------------------------------------------------------------------===//
@ -1069,6 +1083,9 @@ bool TreePredicateFn::isPredefinedPredicateEqualTo(StringRef Field,
return false;
return Result == Value;
}
bool TreePredicateFn::usesOperands() const {
return isPredefinedPredicateEqualTo("PredicateCodeUsesOperands", true);
}
bool TreePredicateFn::isLoad() const {
return isPredefinedPredicateEqualTo("IsLoad", true);
}
@ -1250,7 +1267,7 @@ std::string TreePredicateFn::getCodeToRunOnSDNode() const {
else
Result = " auto *N = cast<" + ClassName.str() + ">(Node);\n";
return Result + getPredCode();
return (Twine(Result) + " (void)N;\n" + getPredCode()).str();
}
//===----------------------------------------------------------------------===//
@ -1276,7 +1293,7 @@ static unsigned getPatternSize(const TreePatternNode *P,
// If this node has some predicate function that must match, it adds to the
// complexity of this node.
if (!P->getPredicateFns().empty())
if (!P->getPredicateCalls().empty())
++Size;
// Count children in the count if they are also nodes.
@ -1296,7 +1313,7 @@ static unsigned getPatternSize(const TreePatternNode *P,
Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
else if (Child->getComplexPatternInfo(CGP))
Size += getPatternSize(Child, CGP);
else if (!Child->getPredicateFns().empty())
else if (!Child->getPredicateCalls().empty())
++Size;
}
}
@ -1751,13 +1768,19 @@ void TreePatternNode::print(raw_ostream &OS) const {
OS << ")";
}
for (const TreePredicateFn &Pred : PredicateFns)
OS << "<<P:" << Pred.getFnName() << ">>";
for (const TreePredicateCall &Pred : PredicateCalls) {
OS << "<<P:";
if (Pred.Scope)
OS << Pred.Scope << ":";
OS << Pred.Fn.getFnName() << ">>";
}
if (TransformFn)
OS << "<<X:" << TransformFn->getName() << ">>";
if (!getName().empty())
OS << ":$" << getName();
for (const ScopedName &Name : NamesAsPredicateArg)
OS << ":$pred:" << Name.getScope() << ":" << Name.getIdentifier();
}
void TreePatternNode::dump() const {
print(errs());
@ -1774,7 +1797,7 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
const MultipleUseVarSet &DepVars) const {
if (N == this) return true;
if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() ||
getPredicateFns() != N->getPredicateFns() ||
getPredicateCalls() != N->getPredicateCalls() ||
getTransformFn() != N->getTransformFn())
return false;
@ -1812,8 +1835,9 @@ TreePatternNodePtr TreePatternNode::clone() const {
getNumTypes());
}
New->setName(getName());
New->setNamesAsPredicateArg(getNamesAsPredicateArg());
New->Types = Types;
New->setPredicateFns(getPredicateFns());
New->setPredicateCalls(getPredicateCalls());
New->setTransformFn(getTransformFn());
return New;
}
@ -1845,8 +1869,8 @@ void TreePatternNode::SubstituteFormalArguments(
// We found a use of a formal argument, replace it with its value.
TreePatternNodePtr NewChild = ArgMap[Child->getName()];
assert(NewChild && "Couldn't find formal argument!");
assert((Child->getPredicateFns().empty() ||
NewChild->getPredicateFns() == Child->getPredicateFns()) &&
assert((Child->getPredicateCalls().empty() ||
NewChild->getPredicateCalls() == Child->getPredicateCalls()) &&
"Non-empty child predicate clobbered!");
setChild(i, std::move(NewChild));
}
@ -1892,8 +1916,8 @@ void TreePatternNode::InlinePatternFragments(
return;
for (auto NewChild : ChildAlternatives[i])
assert((Child->getPredicateFns().empty() ||
NewChild->getPredicateFns() == Child->getPredicateFns()) &&
assert((Child->getPredicateCalls().empty() ||
NewChild->getPredicateCalls() == Child->getPredicateCalls()) &&
"Non-empty child predicate clobbered!");
}
@ -1911,7 +1935,8 @@ void TreePatternNode::InlinePatternFragments(
// Copy over properties.
R->setName(getName());
R->setPredicateFns(getPredicateFns());
R->setNamesAsPredicateArg(getNamesAsPredicateArg());
R->setPredicateCalls(getPredicateCalls());
R->setTransformFn(getTransformFn());
for (unsigned i = 0, e = getNumTypes(); i != e; ++i)
R->setType(i, getExtType(i));
@ -1946,10 +1971,19 @@ void TreePatternNode::InlinePatternFragments(
return;
}
TreePredicateFn PredFn(Frag);
unsigned Scope = 0;
if (TreePredicateFn(Frag).usesOperands())
Scope = TP.getDAGPatterns().allocateScope();
// Compute the map of formal to actual arguments.
std::map<std::string, TreePatternNodePtr> ArgMap;
for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) {
const TreePatternNodePtr &Child = getChildShared(i);
TreePatternNodePtr Child = getChildShared(i);
if (Scope != 0) {
Child = Child->clone();
Child->addNameAsPredicateArg(ScopedName(Scope, Frag->getArgName(i)));
}
ArgMap[Frag->getArgName(i)] = Child;
}
@ -1957,9 +1991,8 @@ void TreePatternNode::InlinePatternFragments(
for (auto Alternative : Frag->getTrees()) {
TreePatternNodePtr FragTree = Alternative->clone();
TreePredicateFn PredFn(Frag);
if (!PredFn.isAlwaysTrue())
FragTree->addPredicateFn(PredFn);
FragTree->addPredicateCall(PredFn, Scope);
// Resolve formal arguments to their actual value.
if (Frag->getNumArgs())
@ -1972,8 +2005,8 @@ void TreePatternNode::InlinePatternFragments(
FragTree->UpdateNodeType(i, getExtType(i), TP);
// Transfer in the old predicates.
for (const TreePredicateFn &Pred : getPredicateFns())
FragTree->addPredicateFn(Pred);
for (const TreePredicateCall &Pred : getPredicateCalls())
FragTree->addPredicateCall(Pred);
// The fragment we inlined could have recursive inlining that is needed. See
// if there are any pattern fragments in it and inline them as needed.
@ -3596,7 +3629,7 @@ void CodeGenDAGPatterns::parseInstructionPattern(
TreePatternNodePtr OpNode = InVal->clone();
// No predicate is useful on the result.
OpNode->clearPredicateFns();
OpNode->clearPredicateCalls();
// Promote the xform function to be an explicit node if set.
if (Record *Xform = OpNode->getTransformFn()) {
@ -4251,7 +4284,8 @@ static void CombineChildVariants(
// Copy over properties.
R->setName(Orig->getName());
R->setPredicateFns(Orig->getPredicateFns());
R->setNamesAsPredicateArg(Orig->getNamesAsPredicateArg());
R->setPredicateCalls(Orig->getPredicateCalls());
R->setTransformFn(Orig->getTransformFn());
for (unsigned i = 0, e = Orig->getNumTypes(); i != e; ++i)
R->setType(i, Orig->getExtType(i));
@ -4303,7 +4337,7 @@ GatherChildrenOfAssociativeOpcode(TreePatternNodePtr N,
Record *Operator = N->getOperator();
// Only permit raw nodes.
if (!N->getName().empty() || !N->getPredicateFns().empty() ||
if (!N->getName().empty() || !N->getPredicateCalls().empty() ||
N->getTransformFn()) {
Children.push_back(N);
return;

View File

@ -408,6 +408,29 @@ struct SDTypeConstraint {
TreePattern &TP) const;
};
/// ScopedName - A name of a node associated with a "scope" that indicates
/// the context (e.g. instance of Pattern or PatFrag) in which the name was
/// used. This enables substitution of pattern fragments while keeping track
/// of what name(s) were originally given to various nodes in the tree.
class ScopedName {
unsigned Scope;
std::string Identifier;
public:
ScopedName(unsigned Scope, StringRef Identifier)
: Scope(Scope), Identifier(Identifier) {
assert(Scope != 0 &&
"Scope == 0 is used to indicate predicates without arguments");
}
unsigned getScope() const { return Scope; }
const std::string &getIdentifier() const { return Identifier; }
std::string getFullName() const;
bool operator==(const ScopedName &o) const;
bool operator!=(const ScopedName &o) const;
};
/// SDNodeInfo - One of these records is created for each SDNode instance in
/// the target .td file. This represents the various dag nodes we will be
/// processing.
@ -503,6 +526,9 @@ public:
/// usable as part of an identifier.
StringRef getImmTypeIdentifier() const;
// Predicate code uses the PatFrag's captured operands.
bool usesOperands() const;
// Is the desired predefined predicate for a load?
bool isLoad() const;
// Is the desired predefined predicate for a store?
@ -570,6 +596,23 @@ private:
bool isPredefinedPredicateEqualTo(StringRef Field, bool Value) const;
};
struct TreePredicateCall {
TreePredicateFn Fn;
// Scope -- unique identifier for retrieving named arguments. 0 is used when
// the predicate does not use named arguments.
unsigned Scope;
TreePredicateCall(const TreePredicateFn &Fn, unsigned Scope)
: Fn(Fn), Scope(Scope) {}
bool operator==(const TreePredicateCall &o) const {
return Fn == o.Fn && Scope == o.Scope;
}
bool operator!=(const TreePredicateCall &o) const {
return !(*this == o);
}
};
class TreePatternNode {
/// The type of each node result. Before and during type inference, each
@ -589,9 +632,11 @@ class TreePatternNode {
///
std::string Name;
/// PredicateFns - The predicate functions to execute on this node to check
std::vector<ScopedName> NamesAsPredicateArg;
/// PredicateCalls - The predicate functions to execute on this node to check
/// for a match. If this list is empty, no predicate is involved.
std::vector<TreePredicateFn> PredicateFns;
std::vector<TreePredicateCall> PredicateCalls;
/// TransformFn - The transformation function to execute on this node before
/// it can be substituted into the resulting instruction on a pattern match.
@ -615,6 +660,16 @@ public:
const std::string &getName() const { return Name; }
void setName(StringRef N) { Name.assign(N.begin(), N.end()); }
const std::vector<ScopedName> &getNamesAsPredicateArg() const {
return NamesAsPredicateArg;
}
void setNamesAsPredicateArg(const std::vector<ScopedName>& Names) {
NamesAsPredicateArg = Names;
}
void addNameAsPredicateArg(const ScopedName &N) {
NamesAsPredicateArg.push_back(N);
}
bool isLeaf() const { return Val != nullptr; }
// Type accessors.
@ -661,20 +716,24 @@ public:
bool hasPossibleType() const;
bool setDefaultMode(unsigned Mode);
bool hasAnyPredicate() const { return !PredicateFns.empty(); }
bool hasAnyPredicate() const { return !PredicateCalls.empty(); }
const std::vector<TreePredicateFn> &getPredicateFns() const {
return PredicateFns;
const std::vector<TreePredicateCall> &getPredicateCalls() const {
return PredicateCalls;
}
void clearPredicateFns() { PredicateFns.clear(); }
void setPredicateFns(const std::vector<TreePredicateFn> &Fns) {
assert(PredicateFns.empty() && "Overwriting non-empty predicate list!");
PredicateFns = Fns;
void clearPredicateCalls() { PredicateCalls.clear(); }
void setPredicateCalls(const std::vector<TreePredicateCall> &Calls) {
assert(PredicateCalls.empty() && "Overwriting non-empty predicate list!");
PredicateCalls = Calls;
}
void addPredicateFn(const TreePredicateFn &Fn) {
assert(!Fn.isAlwaysTrue() && "Empty predicate string!");
assert(!is_contained(PredicateFns, Fn) && "predicate applied recursively");
PredicateFns.push_back(Fn);
void addPredicateCall(const TreePredicateCall &Call) {
assert(!Call.Fn.isAlwaysTrue() && "Empty predicate string!");
assert(!is_contained(PredicateCalls, Call) && "predicate applied recursively");
PredicateCalls.push_back(Call);
}
void addPredicateCall(const TreePredicateFn &Fn, unsigned Scope) {
assert((Scope != 0) == Fn.usesOperands());
addPredicateCall(TreePredicateCall(Fn, Scope));
}
Record *getTransformFn() const { return TransformFn; }
@ -1081,6 +1140,8 @@ class CodeGenDAGPatterns {
using PatternRewriterFn = std::function<void (TreePattern *)>;
PatternRewriterFn PatternRewriter;
unsigned NumScopes = 0;
public:
CodeGenDAGPatterns(RecordKeeper &R,
PatternRewriterFn PatternRewriter = nullptr);
@ -1196,6 +1257,8 @@ public:
bool hasTargetIntrinsics() { return !TgtIntrinsics.empty(); }
unsigned allocateScope() { return ++NumScopes; }
private:
void ParseNodeInfo();
void ParseNodeTransforms();

View File

@ -93,13 +93,23 @@ SwitchTypeMatcher::~SwitchTypeMatcher() {
delete C.second;
}
CheckPredicateMatcher::CheckPredicateMatcher(const TreePredicateFn &pred)
: Matcher(CheckPredicate), Pred(pred.getOrigPatFragRecord()) {}
CheckPredicateMatcher::CheckPredicateMatcher(
const TreePredicateFn &pred, const SmallVectorImpl<unsigned> &Ops)
: Matcher(CheckPredicate), Pred(pred.getOrigPatFragRecord()),
Operands(Ops.begin(), Ops.end()) {}
TreePredicateFn CheckPredicateMatcher::getPredicate() const {
return TreePredicateFn(Pred);
}
unsigned CheckPredicateMatcher::getNumOperands() const {
return Operands.size();
}
unsigned CheckPredicateMatcher::getOperandNo(unsigned i) const {
assert(i < Operands.size());
return Operands[i];
}
// printImpl methods.

View File

@ -414,10 +414,14 @@ private:
/// see if the node is acceptable.
class CheckPredicateMatcher : public Matcher {
TreePattern *Pred;
const SmallVector<unsigned, 4> Operands;
public:
CheckPredicateMatcher(const TreePredicateFn &pred);
CheckPredicateMatcher(const TreePredicateFn &pred,
const SmallVectorImpl<unsigned> &Operands);
TreePredicateFn getPredicate() const;
unsigned getNumOperands() const;
unsigned getOperandNo(unsigned i) const;
static bool classof(const Matcher *N) {
return N->getKind() == CheckPredicate;

View File

@ -50,6 +50,7 @@ class MatcherTableEmitter {
DenseMap<TreePattern *, unsigned> NodePredicateMap;
std::vector<TreePredicateFn> NodePredicates;
std::vector<TreePredicateFn> NodePredicatesWithOperands;
// We de-duplicate the predicates by code string, and use this map to track
// all the patterns with "identical" predicates.
@ -92,6 +93,9 @@ public:
void EmitPatternMatchTable(raw_ostream &OS);
private:
void EmitNodePredicatesFunction(const std::vector<TreePredicateFn> &Preds,
StringRef Decl, raw_ostream &OS);
unsigned EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS);
@ -103,12 +107,20 @@ private:
NodePredicatesByCodeToRun[Pred.getCodeToRunOnSDNode()];
if (SameCodePreds.empty()) {
// We've never seen a predicate with the same code: allocate an entry.
NodePredicates.push_back(Pred);
Entry = NodePredicates.size();
if (Pred.usesOperands()) {
NodePredicatesWithOperands.push_back(Pred);
Entry = NodePredicatesWithOperands.size();
} else {
NodePredicates.push_back(Pred);
Entry = NodePredicates.size();
}
} else {
// We did see an identical predicate: re-use it.
Entry = NodePredicateMap[SameCodePreds.front()];
assert(Entry != 0);
assert(TreePredicateFn(SameCodePreds.front()).usesOperands() ==
Pred.usesOperands() &&
"PatFrags with some code must have same usesOperands setting");
}
// In both cases, we've never seen this particular predicate before, so
// mark it in the list of predicates sharing the same code.
@ -396,11 +408,23 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
}
case Matcher::CheckPredicate: {
TreePredicateFn Pred = cast<CheckPredicateMatcher>(N)->getPredicate();
OS << "OPC_CheckPredicate, " << getNodePredicate(Pred) << ',';
unsigned OperandBytes = 0;
if (Pred.usesOperands()) {
unsigned NumOps = cast<CheckPredicateMatcher>(N)->getNumOperands();
OS << "OPC_CheckPredicateWithOperands, " << NumOps << "/*#Ops*/, ";
for (unsigned i = 0; i < NumOps; ++i)
OS << cast<CheckPredicateMatcher>(N)->getOperandNo(i) << ", ";
OperandBytes = 1 + NumOps;
} else {
OS << "OPC_CheckPredicate, ";
}
OS << getNodePredicate(Pred) << ',';
if (!OmitComments)
OS << " // " << Pred.getFnName();
OS << '\n';
return 2;
return 2 + OperandBytes;
}
case Matcher::CheckOpcode:
@ -783,6 +807,33 @@ EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
return Size;
}
void MatcherTableEmitter::EmitNodePredicatesFunction(
const std::vector<TreePredicateFn> &Preds, StringRef Decl,
raw_ostream &OS) {
if (Preds.empty())
return;
BeginEmitFunction(OS, "bool", Decl, true/*AddOverride*/);
OS << "{\n";
OS << " switch (PredNo) {\n";
OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
for (unsigned i = 0, e = Preds.size(); i != e; ++i) {
// Emit the predicate code corresponding to this pattern.
TreePredicateFn PredFn = Preds[i];
assert(!PredFn.isAlwaysTrue() && "No code in this predicate");
OS << " case " << i << ": { \n";
for (auto *SimilarPred :
NodePredicatesByCodeToRun[PredFn.getCodeToRunOnSDNode()])
OS << " // " << TreePredicateFn(SimilarPred).getFnName() <<'\n';
OS << PredFn.getCodeToRunOnSDNode() << "\n }\n";
}
OS << " }\n";
OS << "}\n";
EndEmitFunction(OS);
}
void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
// Emit pattern predicates.
if (!PatternPredicates.empty()) {
@ -799,29 +850,14 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
}
// Emit Node predicates.
if (!NodePredicates.empty()) {
BeginEmitFunction(OS, "bool",
"CheckNodePredicate(SDNode *Node, unsigned PredNo) const",
true/*AddOverride*/);
OS << "{\n";
OS << " switch (PredNo) {\n";
OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
for (unsigned i = 0, e = NodePredicates.size(); i != e; ++i) {
// Emit the predicate code corresponding to this pattern.
TreePredicateFn PredFn = NodePredicates[i];
assert(!PredFn.isAlwaysTrue() && "No code in this predicate");
OS << " case " << i << ": { \n";
for (auto *SimilarPred :
NodePredicatesByCodeToRun[PredFn.getCodeToRunOnSDNode()])
OS << " // " << TreePredicateFn(SimilarPred).getFnName() <<'\n';
OS << PredFn.getCodeToRunOnSDNode() << "\n }\n";
}
OS << " }\n";
OS << "}\n";
EndEmitFunction(OS);
}
EmitNodePredicatesFunction(
NodePredicates, "CheckNodePredicate(SDNode *Node, unsigned PredNo) const",
OS);
EmitNodePredicatesFunction(
NodePredicatesWithOperands,
"CheckNodePredicateWithOperands(SDNode *Node, unsigned PredNo, "
"const SmallVectorImpl<SDValue> &Operands) const",
OS);
// Emit CompletePattern matchers.
// FIXME: This should be const.

View File

@ -120,7 +120,7 @@ namespace {
/// If this is the first time a node with unique identifier Name has been
/// seen, record it. Otherwise, emit a check to make sure this is the same
/// node. Returns true if this is the first encounter.
bool recordUniqueNode(const std::string &Name);
bool recordUniqueNode(ArrayRef<std::string> Names);
// Result Code Generation.
unsigned getNamedArgumentSlot(StringRef Name) {
@ -319,8 +319,8 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
// to handle this.
if ((N->getOperator()->getName() == "and" ||
N->getOperator()->getName() == "or") &&
N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateFns().empty() &&
N->getPredicateFns().empty()) {
N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateCalls().empty() &&
N->getPredicateCalls().empty()) {
if (IntInit *II = dyn_cast<IntInit>(N->getChild(1)->getLeafValue())) {
if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits.
// If this is at the root of the pattern, we emit a redundant
@ -441,21 +441,39 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
}
}
bool MatcherGen::recordUniqueNode(const std::string &Name) {
unsigned &VarMapEntry = VariableMap[Name];
if (VarMapEntry == 0) {
// If it is a named node, we must emit a 'Record' opcode.
AddMatcher(new RecordMatcher("$" + Name, NextRecordedOperandNo));
VarMapEntry = ++NextRecordedOperandNo;
return true;
bool MatcherGen::recordUniqueNode(ArrayRef<std::string> Names) {
unsigned Entry = 0;
for (const std::string &Name : Names) {
unsigned &VarMapEntry = VariableMap[Name];
if (!Entry)
Entry = VarMapEntry;
assert(Entry == VarMapEntry);
}
// If we get here, this is a second reference to a specific name. Since
// we already have checked that the first reference is valid, we don't
// have to recursively match it, just check that it's the same as the
// previously named thing.
AddMatcher(new CheckSameMatcher(VarMapEntry-1));
return false;
bool NewRecord = false;
if (Entry == 0) {
// If it is a named node, we must emit a 'Record' opcode.
std::string WhatFor;
for (const std::string &Name : Names) {
if (!WhatFor.empty())
WhatFor += ',';
WhatFor += "$" + Name;
}
AddMatcher(new RecordMatcher(WhatFor, NextRecordedOperandNo));
Entry = ++NextRecordedOperandNo;
NewRecord = true;
} else {
// If we get here, this is a second reference to a specific name. Since
// we already have checked that the first reference is valid, we don't
// have to recursively match it, just check that it's the same as the
// previously named thing.
AddMatcher(new CheckSameMatcher(Entry-1));
}
for (const std::string &Name : Names)
VariableMap[Name] = Entry;
return NewRecord;
}
void MatcherGen::EmitMatchCode(const TreePatternNode *N,
@ -475,9 +493,18 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
// If this node has a name associated with it, capture it in VariableMap. If
// we already saw this in the pattern, emit code to verify dagness.
SmallVector<std::string, 4> Names;
if (!N->getName().empty())
if (!recordUniqueNode(N->getName()))
Names.push_back(N->getName());
for (const ScopedName &Name : N->getNamesAsPredicateArg()) {
Names.push_back(("pred:" + Twine(Name.getScope()) + ":" + Name.getIdentifier()).str());
}
if (!Names.empty()) {
if (!recordUniqueNode(Names))
return;
}
if (N->isLeaf())
EmitLeafMatchCode(N);
@ -485,8 +512,19 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
EmitOperatorMatchCode(N, NodeNoTypes, ForceMode);
// If there are node predicates for this node, generate their checks.
for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i)
AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i]));
for (unsigned i = 0, e = N->getPredicateCalls().size(); i != e; ++i) {
const TreePredicateCall &Pred = N->getPredicateCalls()[i];
SmallVector<unsigned, 4> Operands;
if (Pred.Fn.usesOperands()) {
TreePattern *TP = Pred.Fn.getOrigPatFragRecord();
for (unsigned i = 0; i < TP->getNumArgs(); ++i) {
std::string Name =
("pred:" + Twine(Pred.Scope) + ":" + TP->getArgName(i)).str();
Operands.push_back(getNamedArgumentSlot(Name));
}
}
AddMatcher(new CheckPredicateMatcher(Pred.Fn, Operands));
}
for (unsigned i = 0, e = ResultsToTypeCheck.size(); i != e; ++i)
AddMatcher(new CheckTypeMatcher(N->getSimpleType(ResultsToTypeCheck[i]),

View File

@ -210,13 +210,13 @@ struct OperandsSignature {
// Handle imm operands specially.
if (!Op->isLeaf() && Op->getOperator()->getName() == "imm") {
unsigned PredNo = 0;
if (!Op->getPredicateFns().empty()) {
TreePredicateFn PredFn = Op->getPredicateFns()[0];
if (!Op->getPredicateCalls().empty()) {
TreePredicateFn PredFn = Op->getPredicateCalls()[0].Fn;
// If there is more than one predicate weighing in on this operand
// then we don't handle it. This doesn't typically happen for
// immediates anyway.
if (Op->getPredicateFns().size() > 1 ||
!PredFn.isImmediatePattern())
if (Op->getPredicateCalls().size() > 1 ||
!PredFn.isImmediatePattern() || PredFn.usesOperands())
return false;
// Ignore any instruction with 'FastIselShouldIgnore', these are
// not needed and just bloat the fast instruction selector. For
@ -236,7 +236,7 @@ struct OperandsSignature {
// For now, filter out any operand with a predicate.
// For now, filter out any operand with multiple values.
if (!Op->getPredicateFns().empty() || Op->getNumTypes() != 1)
if (!Op->getPredicateCalls().empty() || Op->getNumTypes() != 1)
return false;
if (!Op->isLeaf()) {
@ -529,7 +529,7 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
}
// For now, filter out any instructions with predicates.
if (!InstPatNode->getPredicateFns().empty())
if (!InstPatNode->getPredicateCalls().empty())
continue;
// Check all the operands.

View File

@ -200,7 +200,8 @@ static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
static std::string explainPredicates(const TreePatternNode *N) {
std::string Explanation = "";
StringRef Separator = "";
for (const auto &P : N->getPredicateFns()) {
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
const TreePredicateFn &P = Call.Fn;
Explanation +=
(Separator + P.getOrigPatFragRecord()->getRecord()->getName()).str();
Separator = ", ";
@ -284,7 +285,9 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) {
std::string Separator = "";
bool HasUnsupportedPredicate = false;
for (const auto &Predicate : N->getPredicateFns()) {
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
if (Predicate.isAlwaysTrue())
continue;
@ -3117,7 +3120,8 @@ Record *GlobalISelEmitter::findNodeEquiv(Record *N) const {
const CodeGenInstruction *
GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const {
for (const auto &Predicate : N->getPredicateFns()) {
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
if (!Equiv.isValueUnset("IfSignExtend") && Predicate.isLoad() &&
Predicate.isSignExtLoad())
return &Target.getInstruction(Equiv.getValueAsDef("IfSignExtend"));
@ -3186,7 +3190,8 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
" for result of Src pattern operator");
}
for (const auto &Predicate : Src->getPredicateFns()) {
for (const TreePredicateCall &Call : Src->getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
if (Predicate.isAlwaysTrue())
continue;