[llvm] [DependenceAnalysis] Fix incorrect analysis of wrapping AddRec expressions (PR #154982)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 23 01:36:04 PDT 2025
================
@@ -6439,8 +6439,129 @@ void ScalarEvolution::setNoWrapFlags(SCEVAddRecExpr *AddRec,
}
}
-ConstantRange ScalarEvolution::
-getRangeForUnknownRecurrence(const SCEVUnknown *U) {
+std::optional<bool>
+ScalarEvolution::mayAddRecWrap(const SCEVAddRecExpr *AddRec) {
+ Type *Ty = AddRec->getType();
+
+ // Pointer AddRec expressions do not wrap in the arithmetic sense.
+ if (Ty->isPointerTy())
+ return false;
+
+ // Step 1: Check existing no-wrap flags from SCEV construction.
+ if (AddRec->hasNoSelfWrap() || AddRec->hasNoUnsignedWrap() ||
+ AddRec->hasNoSignedWrap()) {
+ LLVM_DEBUG(dbgs() << "\t\tAddRec has no-wrap flags: " << *AddRec << "\n");
+ return false;
+ }
+
+ // Step 2: Try to prove no-wrap using constant range analysis.
+ // Uses the same logic as proveNoWrapViaConstantRanges.
+ if (AddRec->isAffine()) {
+ const Loop *Loop = AddRec->getLoop();
+ const SCEV *BECount = getConstantMaxBackedgeTakenCount(Loop);
+ if (const SCEVConstant *BECountMax = dyn_cast<SCEVConstant>(BECount)) {
+ ConstantRange StepCR = getSignedRange(AddRec->getStepRecurrence(*this));
+ const APInt &BECountAP = BECountMax->getAPInt();
+ unsigned NoOverflowBitWidth =
+ BECountAP.getActiveBits() + StepCR.getMinSignedBits();
+ if (NoOverflowBitWidth <= getTypeSizeInBits(AddRec->getType())) {
+ LLVM_DEBUG(dbgs() << "\t\tConstant range analysis proves no-wrap: "
+ << *AddRec << "\n");
+ return false;
+ }
+ }
+ }
+
+ // Step 3: Try to prove using signed/unsigned range containment.
+ // Uses the range containment checks from proveNoWrapViaConstantRanges.
+ if (AddRec->isAffine()) {
+ using OBO = OverflowingBinaryOperator;
+
+ // Check unsigned wrap.
+ ConstantRange AddRecRange = getUnsignedRange(AddRec);
+ ConstantRange IncRange = getUnsignedRange(AddRec->getStepRecurrence(*this));
+
+ auto NUWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
+ Instruction::Add, IncRange, OBO::NoUnsignedWrap);
+ if (NUWRegion.contains(AddRecRange)) {
+ LLVM_DEBUG(dbgs() << "\t\tUnsigned range analysis proves no-wrap: "
+ << *AddRec << "\n");
+ return false;
+ }
+
+ // Check signed wrap.
+ ConstantRange SignedAddRecRange = getSignedRange(AddRec);
+ ConstantRange SignedIncRange =
+ getSignedRange(AddRec->getStepRecurrence(*this));
+
+ auto NSWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
+ Instruction::Add, SignedIncRange, OBO::NoSignedWrap);
+ if (NSWRegion.contains(SignedAddRecRange)) {
+ LLVM_DEBUG(dbgs() << "\t\tSigned range analysis proves no-wrap: "
+ << *AddRec << "\n");
+ return false;
+ }
+ }
+
+ // Step 4: Try induction-based proving methods.
+ // Call the existing sophisticated analysis methods.
+ SCEV::NoWrapFlags ProvenFlags = proveNoWrapViaConstantRanges(AddRec);
+ if (hasFlags(ProvenFlags, SCEV::FlagNW) ||
+ hasFlags(ProvenFlags, SCEV::FlagNUW) ||
+ hasFlags(ProvenFlags, SCEV::FlagNSW)) {
+ LLVM_DEBUG(dbgs() << "\t\tAdvanced constant range analysis proves no-wrap: "
+ << *AddRec << "\n");
+ return false;
+ }
----------------
nikic wrote:
Steps 2, 3 and 4 seem to be duplicating existing logic that already runs during addrec construction. Does all of this code actually do something useful? If so, why?
https://github.com/llvm/llvm-project/pull/154982
More information about the llvm-commits
mailing list