forked from OSchip/llvm-project
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:
parent
4830fdd21a
commit
445b0b6260
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue