[llvm] [LAA] Be more careful when evaluating AddRecs at symbolic max BTC. (PR #128061)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 19 09:12:55 PDT 2025
================
@@ -188,9 +188,91 @@ RuntimeCheckingPtrGroup::RuntimeCheckingPtrGroup(
Members.push_back(Index);
}
+/// Returns \p A + \p B, if it is guaranteed not to unsigned wrap. Otherwise
+/// return nullptr.
+static const SCEV *addSCEVOverflow(const SCEV *A, const SCEV *B,
+ ScalarEvolution &SE) {
+ if (!SE.willNotOverflow(Instruction::Add, false, A, B))
+ return nullptr;
+ return SE.getAddExpr(A, B);
+}
+
+/// Returns \p A * \p B, if it is guaranteed not to unsigned wrap. Otherwise
+/// return nullptr.
+static const SCEV *mulSCEVOverflow(const SCEV *A, const SCEV *B,
+ ScalarEvolution &SE) {
+ if (!SE.willNotOverflow(Instruction::Mul, false, A, B))
+ return nullptr;
+ return SE.getMulExpr(A, B);
+}
+
+/// Return true, if evaluating \p AR at \p MaxBTC cannot wrap, because \p AR at
+/// \p MaxBTC is guaranteed inbounds of the accessed object.
+static bool evaluatePtrAddRecAtMaxBTCWillNotWrap(const SCEVAddRecExpr *AR,
+ const SCEV *MaxBTC,
+ const SCEV *EltSize,
+ ScalarEvolution &SE,
+ const DataLayout &DL) {
+ auto *PointerBase = SE.getPointerBase(AR->getStart());
+ auto *StartPtr = dyn_cast<SCEVUnknown>(PointerBase);
+ if (!StartPtr)
+ return false;
+ bool CheckForNonNull, CheckForFreed;
+ uint64_t DerefBytes = StartPtr->getValue()->getPointerDereferenceableBytes(
+ DL, CheckForNonNull, CheckForFreed);
+
+ if (CheckForNonNull || CheckForFreed)
+ return false;
+
+ const SCEV *Step = AR->getStepRecurrence(SE);
+ Type *WiderTy = SE.getWiderType(MaxBTC->getType(), Step->getType());
+ Step = SE.getNoopOrSignExtend(Step, WiderTy);
+ MaxBTC = SE.getNoopOrZeroExtend(MaxBTC, WiderTy);
+
+ // For the computations below, make sure they don't unsigned wrap.
+ if (!SE.isKnownPredicate(CmpInst::ICMP_UGE, AR->getStart(), StartPtr))
+ return false;
+ const SCEV *StartOffset = SE.getNoopOrSignExtend(
+ SE.getMinusSCEV(AR->getStart(), StartPtr), WiderTy);
+
+ const SCEV *OffsetAtLastIter =
+ mulSCEVOverflow(MaxBTC, SE.getAbsExpr(Step, false), SE);
+ if (!OffsetAtLastIter)
+ return false;
+
+ const SCEV *OffsetLastAccessedByte = addSCEVOverflow(
+ OffsetAtLastIter, SE.getNoopOrZeroExtend(EltSize, WiderTy), SE);
----------------
fhahn wrote:
Updated the names, thanks.
> I realise it makes the subsequent calculations simpler, but it does artificially increase the chance of overflow because in reality the pointer for the last accessed byte is (AR->getStart() + (MaxBTC * Step) + EltSize - 1). I'm fine with that, but maybe worth a comment?
We are comparing the result `<= DerefBytes` (i.e. the end of the accessed range is at most DerefBytes), so I think it shouldn't pessimize the results. If we subtract 1, we would check `< DerefBytes` (i.e. the last accessed byte must be inside the dereferenceable bytes)
https://github.com/llvm/llvm-project/pull/128061
More information about the llvm-commits
mailing list