summaryrefslogtreecommitdiff
path: root/lib/Analysis/LoopAccessAnalysis.cpp
diff options
context:
space:
mode:
authorMichael Kuperstein <mkuper@google.com>2017-02-03 19:09:45 +0000
committerMichael Kuperstein <mkuper@google.com>2017-02-03 19:09:45 +0000
commitdce4987e9b54c8d4bc74722963668b55b7383e4c (patch)
tree5901593701ef1e959af5a81c8739838f75de580f /lib/Analysis/LoopAccessAnalysis.cpp
parent30af5932fd43a53158bfa1cb6a3e4b1630d8064c (diff)
[SLP] Use SCEV to sort memory accesses.
This generalizes memory access sorting to use differences between SCEVs, instead of relying on constant offsets. That allows us to properly do SLP vectorization of non-sequentially ordered loads within loops bodies. Differential Revision: https://reviews.llvm.org/D29425 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294027 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/LoopAccessAnalysis.cpp')
-rw-r--r--lib/Analysis/LoopAccessAnalysis.cpp51
1 files changed, 34 insertions, 17 deletions
diff --git a/lib/Analysis/LoopAccessAnalysis.cpp b/lib/Analysis/LoopAccessAnalysis.cpp
index e8f52eda3c4..4e076f5f004 100644
--- a/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1058,30 +1058,47 @@ static unsigned getAddressSpaceOperand(Value *I) {
return -1;
}
-/// Saves the memory accesses after sorting it into vector argument 'Sorted'.
void llvm::sortMemAccesses(ArrayRef<Value *> VL, const DataLayout &DL,
ScalarEvolution &SE,
SmallVectorImpl<Value *> &Sorted) {
- SmallVector<std::pair<int, Value *>, 4> OffValPairs;
+ SmallVector<std::pair<int64_t, Value *>, 4> OffValPairs;
+ OffValPairs.reserve(VL.size());
+ Sorted.reserve(VL.size());
+
+ // Walk over the pointers, and map each of them to an offset relative to
+ // first pointer in the array.
+ Value *Ptr0 = getPointerOperand(VL[0]);
+ const SCEV *Scev0 = SE.getSCEV(Ptr0);
+ Value *Obj0 = GetUnderlyingObject(Ptr0, DL);
+
for (auto *Val : VL) {
- // Compute the constant offset from the base pointer of each memory accesses
- // and insert into the vector of key,value pair which needs to be sorted.
Value *Ptr = getPointerOperand(Val);
- unsigned AS = getAddressSpaceOperand(Val);
- unsigned PtrBitWidth = DL.getPointerSizeInBits(AS);
- Type *Ty = cast<PointerType>(Ptr->getType())->getElementType();
- APInt Size(PtrBitWidth, DL.getTypeStoreSize(Ty));
-
- // FIXME: Currently the offsets are assumed to be constant.However this not
- // always true as offsets can be variables also and we would need to
- // consider the difference of the variable offsets.
- APInt Offset(PtrBitWidth, 0);
- Ptr->stripAndAccumulateInBoundsConstantOffsets(DL, Offset);
- OffValPairs.push_back(std::make_pair(Offset.getSExtValue(), Val));
+
+ // If a pointer refers to a different underlying object, bail - the
+ // pointers are by definition incomparable.
+ Value *CurrObj = GetUnderlyingObject(Ptr, DL);
+ if (CurrObj != Obj0) {
+ Sorted.append(VL.begin(), VL.end());
+ return;
+ }
+
+ const SCEVConstant *Diff =
+ dyn_cast<SCEVConstant>(SE.getMinusSCEV(SE.getSCEV(Ptr), Scev0));
+
+ // The pointers may not have a constant offset from each other, or SCEV
+ // may just not be smart enough to figure out they do. Regardless,
+ // there's nothing we can do.
+ if (!Diff) {
+ Sorted.append(VL.begin(), VL.end());
+ return;
+ }
+
+ OffValPairs.emplace_back(Diff->getAPInt().getSExtValue(), Val);
}
+
std::sort(OffValPairs.begin(), OffValPairs.end(),
- [](const std::pair<int, Value *> &Left,
- const std::pair<int, Value *> &Right) {
+ [](const std::pair<int64_t, Value *> &Left,
+ const std::pair<int64_t, Value *> &Right) {
return Left.first < Right.first;
});