Corrected load folding check. We need to start from the root of the sub-dag

being matched and ensure there isn't a non-direct path to the load (i.e. a
path that goes out of the sub-dag.)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30958 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2006-10-14 08:33:25 +00:00
parent bddc5d04d7
commit 27e1fe9dab

View File

@ -134,7 +134,7 @@ namespace {
virtual void EmitFunctionEntryCode(Function &Fn, MachineFunction &MF);
virtual bool CanBeFoldedBy(SDNode *N, SDNode *U);
virtual bool CanBeFoldedBy(SDNode *N, SDNode *U, SDNode *Root);
// Include the pieces autogenerated from the target description.
#include "X86GenDAGISel.inc"
@ -227,52 +227,54 @@ static SDNode *findFlagUse(SDNode *N) {
return NULL;
}
static void findNonImmUse(SDNode* Use, SDNode* Def, SDNode *Ignore, bool &found,
static void findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
SDNode *Root, SDNode *Skip, bool &found,
std::set<SDNode *> &Visited) {
if (found ||
Use->getNodeId() > Def->getNodeId() ||
!Visited.insert(Use).second)
return;
for (unsigned i = 0, e = Use->getNumOperands(); i != e; ++i) {
for (unsigned i = 0, e = Use->getNumOperands(); !found && i != e; ++i) {
SDNode *N = Use->getOperand(i).Val;
if (N == Ignore)
if (N == Skip)
continue;
if (N != Def) {
findNonImmUse(N, Def, Ignore, found, Visited);
} else {
if (N == Def) {
if (Use == ImmedUse)
continue; // Immediate use is ok.
if (Use == Root) {
assert(Use->getOpcode() == ISD::STORE ||
Use->getOpcode() == X86ISD::CMP);
continue;
}
found = true;
break;
}
findNonImmUse(N, Def, ImmedUse, Root, Skip, found, Visited);
}
}
static inline bool isNonImmUse(SDNode* Use, SDNode* Def, SDNode *Ignore=NULL) {
/// isNonImmUse - Start searching from Root up the DAG to check is Def can
/// be reached. Return true if that's the case. However, ignore direct uses
/// by ImmedUse (which would be U in the example illustrated in
/// CanBeFoldedBy) and by Root (which can happen in the store case).
/// FIXME: to be really generic, we should allow direct use by any node
/// that is being folded. But realisticly since we only fold loads which
/// have one non-chain use, we only need to watch out for load/op/store
/// and load/op/cmp case where the root (store / cmp) may reach the load via
/// its chain operand.
static inline bool isNonImmUse(SDNode *Root, SDNode *Def, SDNode *ImmedUse,
SDNode *Skip = NULL) {
std::set<SDNode *> Visited;
bool found = false;
for (unsigned i = 0, e = Use->getNumOperands(); i != e; ++i) {
SDNode *N = Use->getOperand(i).Val;
if (N != Def && N != Ignore) {
findNonImmUse(N, Def, Ignore, found, Visited);
if (found) break;
}
}
if (!found && Ignore) {
// We must be checking for reachability between Def and a flag use. Go down
// recursively if Use also produces a flag.
MVT::ValueType VT = Use->getValueType(Use->getNumValues()-1);
if (VT == MVT::Flag && !Use->use_empty()) {
SDNode *FU = findFlagUse(Use);
if (FU)
return !isNonImmUse(FU, Def, Use);
}
}
findNonImmUse(Root, Def, ImmedUse, Root, Skip, found, Visited);
return found;
}
bool X86DAGToDAGISel::CanBeFoldedBy(SDNode *N, SDNode *U) {
bool X86DAGToDAGISel::CanBeFoldedBy(SDNode *N, SDNode *U, SDNode *Root) {
if (FastISel) return false;
// If U use can somehow reach N through another path then U can't fold N or
// it will create a cycle. e.g. In the following diagram, U can reach N
// through X. If N is folded into into U, then X is both a predecessor and
@ -285,32 +287,43 @@ bool X86DAGToDAGISel::CanBeFoldedBy(SDNode *N, SDNode *U) {
// / [X]
// | ^
// [U]--------|
if (!FastISel && !isNonImmUse(U, N)) {
// If U produces a flag, then it gets (even more) interesting. Since it
// would have been "glued" together with its flag use, we need to check if
// it might reach N:
//
// [ N ]
// ^ ^
// | |
// [U] \--
// ^ [TF]
// | |
// \ /
// [FU]
//
// If FU (flag use) indirectly reach N (the load), and U fold N (call it
// NU), then TF is a predecessor of FU and a successor of NU. But since
// NU and FU are flagged together, this effectively creates a cycle.
MVT::ValueType VT = U->getValueType(U->getNumValues()-1);
if (VT == MVT::Flag && !U->use_empty()) {
SDNode *FU = findFlagUse(U);
if (FU)
return !isNonImmUse(FU, N, U);
if (isNonImmUse(Root, N, U))
return false;
// If U produces a flag, then it gets (even more) interesting. Since it
// would have been "glued" together with its flag use, we need to check if
// it might reach N:
//
// [ N ]
// ^ ^
// | |
// [U] \--
// ^ [TF]
// | ^
// | |
// \ /
// [FU]
//
// If FU (flag use) indirectly reach N (the load), and U fold N (call it
// NU), then TF is a predecessor of FU and a successor of NU. But since
// NU and FU are flagged together, this effectively creates a cycle.
bool HasFlagUse = false;
MVT::ValueType VT = Root->getValueType(Root->getNumValues()-1);
while ((VT == MVT::Flag && !Root->use_empty())) {
SDNode *FU = findFlagUse(Root);
if (FU == NULL)
break;
else {
Root = FU;
HasFlagUse = true;
}
return true;
VT = Root->getValueType(Root->getNumValues()-1);
}
return false;
if (HasFlagUse)
return !isNonImmUse(Root, N, Root, U);
return true;
}
/// MoveBelowTokenFactor - Replace TokenFactor operand with load's chain operand
@ -909,7 +922,7 @@ bool X86DAGToDAGISel::TryFoldLoad(SDOperand P, SDOperand N,
SDOperand &Index, SDOperand &Disp) {
if (ISD::isNON_EXTLoad(N.Val) &&
N.hasOneUse() &&
CanBeFoldedBy(N.Val, P.Val))
CanBeFoldedBy(N.Val, P.Val, P.Val))
return SelectAddr(N.getOperand(1), Base, Scale, Index, Disp);
return false;
}