aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/LoopAccessAnalysis.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/LoopAccessAnalysis.cpp')
-rw-r--r--llvm/lib/Analysis/LoopAccessAnalysis.cpp198
1 files changed, 107 insertions, 91 deletions
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 997d447..e632fe2 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1124,123 +1124,139 @@ int64_t llvm::getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr,
return Stride;
}
-Optional<int> llvm::getPointersDiff(Value *PtrA, Value *PtrB,
- const DataLayout &DL, ScalarEvolution &SE,
- bool StrictCheck, bool CheckType) {
- assert(PtrA && PtrB && "Expected non-nullptr pointers.");
- // Make sure that A and B are different pointers.
- if (PtrA == PtrB)
- return 0;
-
- // Make sure that PtrA and PtrB have the same type if required
- if (CheckType && PtrA->getType() != PtrB->getType())
- return None;
-
- unsigned ASA = PtrA->getType()->getPointerAddressSpace();
- unsigned ASB = PtrB->getType()->getPointerAddressSpace();
-
- // Check that the address spaces match.
- if (ASA != ASB)
- return None;
- unsigned IdxWidth = DL.getIndexSizeInBits(ASA);
-
- APInt OffsetA(IdxWidth, 0), OffsetB(IdxWidth, 0);
- Value *PtrA1 = PtrA->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetA);
- Value *PtrB1 = PtrB->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetB);
-
- int Val;
- if (PtrA1 == PtrB1) {
- // Retrieve the address space again as pointer stripping now tracks through
- // `addrspacecast`.
- ASA = cast<PointerType>(PtrA1->getType())->getAddressSpace();
- ASB = cast<PointerType>(PtrB1->getType())->getAddressSpace();
- // Check that the address spaces match and that the pointers are valid.
- if (ASA != ASB)
- return None;
-
- IdxWidth = DL.getIndexSizeInBits(ASA);
- OffsetA = OffsetA.sextOrTrunc(IdxWidth);
- OffsetB = OffsetB.sextOrTrunc(IdxWidth);
-
- OffsetB -= OffsetA;
- Val = OffsetB.getSExtValue();
- } else {
- // Otherwise compute the distance with SCEV between the base pointers.
- const SCEV *PtrSCEVA = SE.getSCEV(PtrA);
- const SCEV *PtrSCEVB = SE.getSCEV(PtrB);
- const auto *Diff =
- dyn_cast<SCEVConstant>(SE.getMinusSCEV(PtrSCEVB, PtrSCEVA));
- if (!Diff)
- return None;
- Val = Diff->getAPInt().getSExtValue();
- }
- Type *Ty = cast<PointerType>(PtrA->getType())->getElementType();
- int Size = DL.getTypeStoreSize(Ty);
- int Dist = Val / Size;
-
- // Ensure that the calculated distance matches the type-based one after all
- // the bitcasts removal in the provided pointers.
- if (!StrictCheck || Dist * Size == Val)
- return Dist;
- return None;
-}
-
bool llvm::sortPtrAccesses(ArrayRef<Value *> VL, const DataLayout &DL,
ScalarEvolution &SE,
SmallVectorImpl<unsigned> &SortedIndices) {
assert(llvm::all_of(
VL, [](const Value *V) { return V->getType()->isPointerTy(); }) &&
"Expected list of pointer operands.");
+ SmallVector<std::pair<int64_t, Value *>, 4> OffValPairs;
+ OffValPairs.reserve(VL.size());
+
// Walk over the pointers, and map each of them to an offset relative to
// first pointer in the array.
Value *Ptr0 = VL[0];
+ const SCEV *Scev0 = SE.getSCEV(Ptr0);
+ Value *Obj0 = getUnderlyingObject(Ptr0);
+
+ llvm::SmallSet<int64_t, 4> Offsets;
+ for (auto *Ptr : VL) {
+ // TODO: Outline this code as a special, more time consuming, version of
+ // computeConstantDifference() function.
+ if (Ptr->getType()->getPointerAddressSpace() !=
+ Ptr0->getType()->getPointerAddressSpace())
+ return false;
+ // If a pointer refers to a different underlying object, bail - the
+ // pointers are by definition incomparable.
+ Value *CurrObj = getUnderlyingObject(Ptr);
+ if (CurrObj != Obj0)
+ return false;
- using DistOrdPair = std::pair<int64_t, int>;
- auto Compare = [](const DistOrdPair &L, const DistOrdPair &R) {
- return L.first < R.first;
- };
- std::set<DistOrdPair, decltype(Compare)> Offsets(Compare);
- Offsets.emplace(0, 0);
- int Cnt = 1;
- bool IsConsecutive = true;
- for (auto *Ptr : VL.drop_front()) {
- Optional<int> Diff = getPointersDiff(Ptr0, Ptr, DL, SE);
+ const SCEV *Scev = SE.getSCEV(Ptr);
+ const auto *Diff = dyn_cast<SCEVConstant>(SE.getMinusSCEV(Scev, 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)
return false;
// Check if the pointer with the same offset is found.
- int64_t Offset = *Diff;
- auto Res = Offsets.emplace(Offset, Cnt);
- if (!Res.second)
+ int64_t Offset = Diff->getAPInt().getSExtValue();
+ if (!Offsets.insert(Offset).second)
return false;
- // Consecutive order if the inserted element is the last one.
- IsConsecutive = IsConsecutive && std::next(Res.first) == Offsets.end();
- ++Cnt;
+ OffValPairs.emplace_back(Offset, Ptr);
}
SortedIndices.clear();
- if (!IsConsecutive) {
- // Fill SortedIndices array only if it is non-consecutive.
- SortedIndices.resize(VL.size());
- Cnt = 0;
- for (const std::pair<int64_t, int> &Pair : Offsets) {
- IsConsecutive = IsConsecutive && Cnt == Pair.second;
- SortedIndices[Cnt] = Pair.second;
- ++Cnt;
- }
- }
+ SortedIndices.resize(VL.size());
+ std::iota(SortedIndices.begin(), SortedIndices.end(), 0);
+
+ // Sort the memory accesses and keep the order of their uses in UseOrder.
+ llvm::stable_sort(SortedIndices, [&](unsigned Left, unsigned Right) {
+ return OffValPairs[Left].first < OffValPairs[Right].first;
+ });
+
+ // Check if the order is consecutive already.
+ if (llvm::all_of(SortedIndices, [&SortedIndices](const unsigned I) {
+ return I == SortedIndices[I];
+ }))
+ SortedIndices.clear();
+
return true;
}
+/// Take the address space operand from the Load/Store instruction.
+/// Returns -1 if this is not a valid Load/Store instruction.
+static unsigned getAddressSpaceOperand(Value *I) {
+ if (LoadInst *L = dyn_cast<LoadInst>(I))
+ return L->getPointerAddressSpace();
+ if (StoreInst *S = dyn_cast<StoreInst>(I))
+ return S->getPointerAddressSpace();
+ return -1;
+}
+
/// Returns true if the memory operations \p A and \p B are consecutive.
bool llvm::isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL,
ScalarEvolution &SE, bool CheckType) {
Value *PtrA = getLoadStorePointerOperand(A);
Value *PtrB = getLoadStorePointerOperand(B);
- if (!PtrA || !PtrB)
+ unsigned ASA = getAddressSpaceOperand(A);
+ unsigned ASB = getAddressSpaceOperand(B);
+
+ // Check that the address spaces match and that the pointers are valid.
+ if (!PtrA || !PtrB || (ASA != ASB))
+ return false;
+
+ // Make sure that A and B are different pointers.
+ if (PtrA == PtrB)
+ return false;
+
+ // Make sure that A and B have the same type if required.
+ if (CheckType && PtrA->getType() != PtrB->getType())
return false;
- Optional<int> Diff =
- getPointersDiff(PtrA, PtrB, DL, SE, /*StrictCheck=*/true, CheckType);
- return Diff && *Diff == 1;
+
+ unsigned IdxWidth = DL.getIndexSizeInBits(ASA);
+ Type *Ty = cast<PointerType>(PtrA->getType())->getElementType();
+
+ APInt OffsetA(IdxWidth, 0), OffsetB(IdxWidth, 0);
+ PtrA = PtrA->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetA);
+ PtrB = PtrB->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetB);
+
+ // Retrieve the address space again as pointer stripping now tracks through
+ // `addrspacecast`.
+ ASA = cast<PointerType>(PtrA->getType())->getAddressSpace();
+ ASB = cast<PointerType>(PtrB->getType())->getAddressSpace();
+ // Check that the address spaces match and that the pointers are valid.
+ if (ASA != ASB)
+ return false;
+
+ IdxWidth = DL.getIndexSizeInBits(ASA);
+ OffsetA = OffsetA.sextOrTrunc(IdxWidth);
+ OffsetB = OffsetB.sextOrTrunc(IdxWidth);
+
+ APInt Size(IdxWidth, DL.getTypeStoreSize(Ty));
+
+ // OffsetDelta = OffsetB - OffsetA;
+ const SCEV *OffsetSCEVA = SE.getConstant(OffsetA);
+ const SCEV *OffsetSCEVB = SE.getConstant(OffsetB);
+ const SCEV *OffsetDeltaSCEV = SE.getMinusSCEV(OffsetSCEVB, OffsetSCEVA);
+ const APInt &OffsetDelta = cast<SCEVConstant>(OffsetDeltaSCEV)->getAPInt();
+
+ // Check if they are based on the same pointer. That makes the offsets
+ // sufficient.
+ if (PtrA == PtrB)
+ return OffsetDelta == Size;
+
+ // Compute the necessary base pointer delta to have the necessary final delta
+ // equal to the size.
+ // BaseDelta = Size - OffsetDelta;
+ const SCEV *SizeSCEV = SE.getConstant(Size);
+ const SCEV *BaseDelta = SE.getMinusSCEV(SizeSCEV, OffsetDeltaSCEV);
+
+ // Otherwise compute the distance with SCEV between the base pointers.
+ const SCEV *PtrSCEVA = SE.getSCEV(PtrA);
+ const SCEV *PtrSCEVB = SE.getSCEV(PtrB);
+ const SCEV *X = SE.getAddExpr(PtrSCEVA, BaseDelta);
+ return X == PtrSCEVB;
}
MemoryDepChecker::VectorizationSafetyStatus