diff options
Diffstat (limited to 'llvm/lib/Analysis/LoopAccessAnalysis.cpp')
-rw-r--r-- | llvm/lib/Analysis/LoopAccessAnalysis.cpp | 198 |
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 |