[llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Evan Cheng
evan.cheng at apple.com
Tue Nov 7 01:03:30 PST 2006
Changes in directory llvm/lib/CodeGen/SelectionDAG:
DAGCombiner.cpp updated: 1.238 -> 1.239
---
Log message:
Add post-indexed load / store transformations.
---
Diffs of the changes: (+199 -50)
DAGCombiner.cpp | 249 ++++++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 199 insertions(+), 50 deletions(-)
Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.238 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.239
--- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.238 Mon Nov 6 02:14:30 2006
+++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Tue Nov 7 03:03:05 2006
@@ -47,6 +47,11 @@
static Statistic<> NodesCombined ("dagcombiner",
"Number of dag nodes combined");
+ static Statistic<> PreIndexedNodes ("pre_indexed_ops",
+ "Number of pre-indexed nodes created");
+ static Statistic<> PostIndexedNodes ("post_indexed_ops",
+ "Number of post-indexed nodes created");
+
static cl::opt<bool>
CombinerAA("combiner-alias-analysis", cl::Hidden,
cl::desc("Turn on alias analysis during testing"));
@@ -174,13 +179,16 @@
return true;
}
- /// CombineToPreIndexedLoadStore - Try turning a load / store into a
- /// pre-indexed load store when the base pointer is a add or subtract
- /// and it has other uses besides the load / store. When the
- /// transformation is done, the new indexed load / store effectively
- /// folded the add / subtract in and all of its other uses are redirected
- /// to the new load / store.
+ /// CombineToPreIndexedLoadStore - Try turning a load / store and a
+ /// pre-indexed load / store when the base pointer is a add or subtract
+ /// and it has other uses besides the load / store. After the
+ /// transformation, the new indexed load / store has effectively folded
+ /// the add / subtract in and all of its other uses are redirected to the
+ /// new load / store.
bool CombineToPreIndexedLoadStore(SDNode *N) {
+ if (!AfterLegalize)
+ return false;
+
bool isLoad = true;
SDOperand Ptr;
if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
@@ -191,8 +199,7 @@
} else
return false;
- if (AfterLegalize &&
- (Ptr.getOpcode() == ISD::ADD || Ptr.getOpcode() == ISD::SUB) &&
+ if ((Ptr.getOpcode() == ISD::ADD || Ptr.getOpcode() == ISD::SUB) &&
Ptr.Val->use_size() > 1) {
SDOperand BasePtr;
SDOperand Offset;
@@ -203,57 +210,56 @@
// that would create a cycle.
// 2) All uses are load / store ops that use it as base ptr and offset
// is just an addressing mode immediate.
- // 3) If the would-be new base may not to be dead at N. FIXME: The
- // proper check is too expensive (in turns of compile time) to
- // check. Just make sure other uses of the new base are not also
- // themselves use of loads / stores.
-
- bool OffIsAMImm = Offset.getOpcode() == ISD::Constant &&
- TLI.isLegalAddressImmediate(
- cast<ConstantSDNode>(Offset)->getValue());
+ // 3) If the would-be new base may not to be dead at N.
+
+ bool OffIsAMImm = Offset.getOpcode() == ISD::Constant && TLI.
+ isLegalAddressImmediate(cast<ConstantSDNode>(Offset)->getValue());
// Check for #3.
- if (OffIsAMImm && BasePtr.Val->use_size() > 1) {
- for (SDNode::use_iterator I = BasePtr.Val->use_begin(),
- E = BasePtr.Val->use_end(); I != E; ++I) {
- SDNode *Use = *I;
- if (Use == Ptr.Val)
- continue;
- if (Use->getOpcode() == ISD::ADD || Use->getOpcode() == ISD::SUB){
- for (SDNode::use_iterator II = Use->use_begin(),
- EE = Use->use_end(); II != EE; ++II) {
- SDNode *UseUse = *II;
- if (UseUse->getOpcode() == ISD::LOAD &&
- cast<LoadSDNode>(UseUse)->getBasePtr().Val == Use)
- return false;
- else if (UseUse->getOpcode() == ISD::STORE &&
- cast<StoreSDNode>(UseUse)->getBasePtr().Val == Use)
- return false;
- }
+ for (SDNode::use_iterator I = BasePtr.Val->use_begin(),
+ E = BasePtr.Val->use_end(); I != E; ++I) {
+ SDNode *Use = *I;
+ if (Use == Ptr.Val)
+ continue;
+ if (Use->getOpcode() == ISD::CopyToReg)
+ return false;
+ if (OffIsAMImm && (Use->getOpcode() == ISD::ADD ||
+ Use->getOpcode() == ISD::SUB)) {
+ for (SDNode::use_iterator II = Use->use_begin(),
+ EE = Use->use_end(); II != EE; ++II) {
+ SDNode *UseUse = *II;
+ if (UseUse->getOpcode() == ISD::LOAD &&
+ cast<LoadSDNode>(UseUse)->getBasePtr().Val == Use)
+ return false;
+ else if (UseUse->getOpcode() == ISD::STORE &&
+ cast<StoreSDNode>(UseUse)->getBasePtr().Val == Use)
+ return false;
}
}
}
// Now check for #1 and #2.
unsigned NumRealUses = 0;
- for (SDNode::use_iterator I = Ptr.Val->use_begin(),
- E = Ptr.Val->use_end(); I != E; ++I) {
- SDNode *Use = *I;
- if (Use == N)
- continue;
- if (Use->isPredecessor(N))
- return false;
+ if (OffIsAMImm) {
+ for (SDNode::use_iterator I = Ptr.Val->use_begin(),
+ E = Ptr.Val->use_end(); I != E; ++I) {
+ SDNode *Use = *I;
+ if (Use == N)
+ continue;
+ if (Use->isPredecessor(N))
+ return false;
- if (!OffIsAMImm) {
- NumRealUses++;
- } else if (Use->getOpcode() == ISD::LOAD) {
- if (cast<LoadSDNode>(Use)->getBasePtr().Val != Ptr.Val)
+ if (!OffIsAMImm) {
NumRealUses++;
- } else if (Use->getOpcode() == ISD::STORE) {
- if (cast<StoreSDNode>(Use)->getBasePtr().Val != Ptr.Val)
+ } else if (Use->getOpcode() == ISD::LOAD) {
+ if (cast<LoadSDNode>(Use)->getBasePtr().Val != Ptr.Val)
+ NumRealUses++;
+ } else if (Use->getOpcode() == ISD::STORE) {
+ if (cast<StoreSDNode>(Use)->getBasePtr().Val != Ptr.Val)
+ NumRealUses++;
+ } else
NumRealUses++;
- } else
- NumRealUses++;
+ }
}
if (NumRealUses == 0)
return false;
@@ -261,6 +267,7 @@
SDOperand Result = isLoad
? DAG.getIndexedLoad(SDOperand(N,0), BasePtr, Offset, AM)
: DAG.getIndexedStore(SDOperand(N,0), BasePtr, Offset, AM);
+ ++PreIndexedNodes;
++NodesCombined;
DEBUG(std::cerr << "\nReplacing.4 "; N->dump();
std::cerr << "\nWith: "; Result.Val->dump(&DAG);
@@ -294,7 +301,149 @@
return true;
}
}
+ return false;
+ }
+
+ /// CombineToPostIndexedLoadStore - Try combine a load / store with a
+ /// add / sub of the base pointer node into a post-indexed load / store.
+ /// The transformation folded the add / subtract into the new indexed
+ /// load / store effectively and all of its uses are redirected to the
+ /// new load / store.
+ bool CombineToPostIndexedLoadStore(SDNode *N) {
+ if (!AfterLegalize)
+ return false;
+
+ bool isLoad = true;
+ SDOperand Ptr;
+ MVT::ValueType VT;
+ if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ Ptr = LD->getBasePtr();
+ VT = LD->getLoadedVT();
+ } else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ Ptr = ST->getBasePtr();
+ VT = ST->getStoredVT();
+ isLoad = false;
+ } else
+ return false;
+
+ if (Ptr.Val->use_size() > 1) {
+ for (SDNode::use_iterator I = Ptr.Val->use_begin(),
+ E = Ptr.Val->use_end(); I != E; ++I) {
+ SDNode *Op = *I;
+ if (Op == N ||
+ (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB))
+ continue;
+
+ SDOperand BasePtr;
+ SDOperand Offset;
+ ISD::MemOpAddrMode AM = ISD::UNINDEXED;
+ if (TLI.getPostIndexedAddressParts(Op, VT, BasePtr, Offset, AM,DAG) &&
+ BasePtr.Val == Ptr.Val) {
+ // Try turning it into a post-indexed load / store except when
+ // 1) Op must be independent of N, i.e. Op is neither a predecessor
+ // nor a successor of N. Otherwise, if Op is folded that would
+ // create a cycle.
+ // 2) All uses are load / store ops that use it as base ptr and offset
+ // is just an addressing mode immediate.
+ // 3) If the would-be new base may not to be dead at N.
+
+ bool OffIsAMImm = Offset.getOpcode() == ISD::Constant && TLI.
+ isLegalAddressImmediate(cast<ConstantSDNode>(Offset)->getValue());
+
+ // Check for #3.
+ bool TryNext = false;
+ for (SDNode::use_iterator II = BasePtr.Val->use_begin(),
+ EE = BasePtr.Val->use_end(); II != EE; ++II) {
+ SDNode *Use = *II;
+ if (Use == Ptr.Val)
+ continue;
+ if (Use->getOpcode() == ISD::CopyToReg) {
+ TryNext = true;
+ break;
+ }
+
+ if (OffIsAMImm && (Use->getOpcode() == ISD::ADD ||
+ Use->getOpcode() == ISD::SUB)) {
+ for (SDNode::use_iterator III = Use->use_begin(),
+ EEE = Use->use_end(); III != EEE; ++III) {
+ SDNode *UseUse = *III;
+ if (UseUse->getOpcode() == ISD::LOAD &&
+ cast<LoadSDNode>(UseUse)->getBasePtr().Val == Use) {
+ TryNext = true;
+ break;
+ } else if (UseUse->getOpcode() == ISD::STORE &&
+ cast<StoreSDNode>(UseUse)->getBasePtr().Val == Use) {
+
+ TryNext = true;
+ break;
+ }
+ }
+ }
+ }
+ if (TryNext)
+ continue;
+ if (OffIsAMImm) {
+ // Check for #2.
+ unsigned NumRealUses = 0;
+ for (SDNode::use_iterator II = Op->use_begin(), EE = Op->use_end();
+ II != EE; ++II) {
+ SDNode *Use = *II;
+ if (Use->getOpcode() == ISD::LOAD) {
+ if (cast<LoadSDNode>(Use)->getBasePtr().Val != Op)
+ NumRealUses++;
+ } else if (Use->getOpcode() == ISD::STORE) {
+ if (cast<StoreSDNode>(Use)->getBasePtr().Val != Op)
+ NumRealUses++;
+ } else
+ NumRealUses++;
+ }
+ if (NumRealUses == 0)
+ continue;
+ }
+
+ // Check for #1
+ if (!Op->isPredecessor(N) && !N->isPredecessor(Op)) {
+ SDOperand Result = isLoad
+ ? DAG.getIndexedLoad(SDOperand(N,0), BasePtr, Offset, AM)
+ : DAG.getIndexedStore(SDOperand(N,0), BasePtr, Offset, AM);
+ ++PostIndexedNodes;
+ ++NodesCombined;
+ DEBUG(std::cerr << "\nReplacing.5 "; N->dump();
+ std::cerr << "\nWith: "; Result.Val->dump(&DAG);
+ std::cerr << '\n');
+ std::vector<SDNode*> NowDead;
+ if (isLoad) {
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
+ NowDead);
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), Result.getValue(2),
+ NowDead);
+ } else {
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(1),
+ NowDead);
+ }
+
+ // Nodes can end up on the worklist more than once. Make sure we do
+ // not process a node that has been replaced.
+ for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
+ removeFromWorkList(NowDead[i]);
+ // Finally, since the node is now dead, remove it from the graph.
+ DAG.DeleteNode(N);
+
+ // Replace the uses of Use with uses of the updated base value.
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(Op, 0),
+ Result.getValue(isLoad ? 1 : 0),
+ NowDead);
+ removeFromWorkList(Op);
+ for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
+ removeFromWorkList(NowDead[i]);
+ DAG.DeleteNode(Op);
+
+ return true;
+ }
+ }
+ }
+ }
return false;
}
@@ -2877,7 +3026,7 @@
}
// Try transforming N to an indexed load.
- if (CombineToPreIndexedLoadStore(N))
+ if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N))
return SDOperand(N, 0);
return SDOperand();
@@ -2923,7 +3072,7 @@
}
// Try transforming N to an indexed store.
- if (CombineToPreIndexedLoadStore(N))
+ if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N))
return SDOperand(N, 0);
return SDOperand();
More information about the llvm-commits
mailing list