[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
Evan Cheng
evan.cheng at apple.com
Sat Oct 14 01:33:40 PDT 2006
Changes in directory llvm/lib/Target/X86:
X86ISelDAGToDAG.cpp updated: 1.118 -> 1.119
---
Log message:
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.)
---
Diffs of the changes: (+65 -52)
X86ISelDAGToDAG.cpp | 117 ++++++++++++++++++++++++++++------------------------
1 files changed, 65 insertions(+), 52 deletions(-)
Index: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
diff -u llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.118 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.119
--- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.118 Fri Oct 13 16:14:26 2006
+++ llvm/lib/Target/X86/X86ISelDAGToDAG.cpp Sat Oct 14 03:33:25 2006
@@ -134,7 +134,7 @@
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 @@
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 @@
// / [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 @@
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;
}
More information about the llvm-commits
mailing list