[llvm] [LAA] Perform checks for no-wrap separately from getPtrStride. (PR #126971)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 12 13:44:25 PST 2025
================
@@ -813,16 +813,102 @@ static bool hasComputableBounds(PredicatedScalarEvolution &PSE, Value *Ptr,
return AR->isAffine();
}
+/// Try to compute the stride for \p AR. Used by getPtrStride.
+static std::optional<int64_t>
+getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy,
+ Value *Ptr, PredicatedScalarEvolution &PSE) {
+ // The access function must stride over the innermost loop.
+ if (Lp != AR->getLoop()) {
+ LLVM_DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop "
+ << *Ptr << " SCEV: " << *AR << "\n");
+ return std::nullopt;
+ }
+
+ // Check the step is constant.
+ const SCEV *Step = AR->getStepRecurrence(*PSE.getSE());
+
+ // Calculate the pointer stride and check if it is constant.
+ const SCEVConstant *C = dyn_cast<SCEVConstant>(Step);
+ if (!C) {
+ LLVM_DEBUG(dbgs() << "LAA: Bad stride - Not a constant strided " << *Ptr
+ << " SCEV: " << *AR << "\n");
+ return std::nullopt;
+ }
+
+ const auto &DL = Lp->getHeader()->getDataLayout();
+ TypeSize AllocSize = DL.getTypeAllocSize(AccessTy);
+ int64_t Size = AllocSize.getFixedValue();
+ const APInt &APStepVal = C->getAPInt();
+
+ // Huge step value - give up.
+ if (APStepVal.getBitWidth() > 64)
+ return std::nullopt;
+
+ int64_t StepVal = APStepVal.getSExtValue();
+
+ // Strided access.
+ int64_t Stride = StepVal / Size;
+ int64_t Rem = StepVal % Size;
+ if (Rem)
+ return std::nullopt;
+
+ return Stride;
+}
+
+static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR,
+ PredicatedScalarEvolution &PSE, const Loop *L);
+
/// Check whether a pointer address cannot wrap.
static bool isNoWrap(PredicatedScalarEvolution &PSE,
const DenseMap<Value *, const SCEV *> &Strides, Value *Ptr,
- Type *AccessTy, Loop *L, bool Assume) {
- const SCEV *PtrScev = PSE.getSCEV(Ptr);
+ Type *AccessTy, const Loop *L, bool Assume,
+ std::optional<int64_t> Stride = std::nullopt) {
+ const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, Strides, Ptr);
if (PSE.getSE()->isLoopInvariant(PtrScev, L))
return true;
- return getPtrStride(PSE, AccessTy, Ptr, L, Strides, Assume).has_value() ||
- PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW);
+ const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(PtrScev);
+ if (Assume && !AR)
+ AR = PSE.getAsAddRec(Ptr);
+ if (!AR)
+ return false;
+
+ // The address calculation must not wrap. Otherwise, a dependence could be
+ // inverted.
+ if (isNoWrapAddRec(Ptr, AR, PSE, L))
+ return true;
+
+ // An nusw getelementptr that is an AddRec cannot wrap. If it would wrap,
+ // the distance between the previously accessed location and the wrapped
+ // location will be larger than half the pointer index type space. In that
+ // case, the GEP would be poison and any memory access dependent on it would
+ // be immediate UB when executed.
+ if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
+ GEP && GEP->hasNoUnsignedSignedWrap())
+ return true;
+
+ // If the null pointer is undefined, then a access sequence which would
+ // otherwise access it can be assumed not to unsigned wrap. Note that this
+ // assumes the object in memory is aligned to the natural alignment.
+ if (!Stride)
+ Stride = getStrideFromAddRec(AR, L, AccessTy, Ptr, PSE);
+ if (Stride) {
+ unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace();
+ if (!NullPointerIsDefined(L->getHeader()->getParent(), AddrSpace) &&
+ (*Stride == 1 || *Stride == -1))
----------------
artagnon wrote:
No need to dereference?
https://github.com/llvm/llvm-project/pull/126971
More information about the llvm-commits
mailing list