[llvm] [DependenceAnalysis] Fix incorrect analysis of wrapping AddRec expressions (PR #154982)

Sebastian Pop via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 23 13:15:57 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;
+  }
----------------
sebpop wrote:

I was under the impression that the functions that compute the no-wrap flags were not run systematically on all the scevs as they get built and may not survive some operations. In particular we may have arithmetic such as delinearization that takes a SCEV and splits it into separate SCEVs corresponding to the access functions of subscripts using division and other arithmetic.

> Steps 2, 3 and 4 seem to be duplicating existing logic

So you are saying that it's a bug if the AddRec does not correctly inherit the flags from its construction through arithmetic operations.

Thus, I removed steps 2, 3, and 4 as redundant with the way the flags are attached to AddRecs and propagated through arithmetic operations.

https://github.com/llvm/llvm-project/pull/154982


More information about the llvm-commits mailing list