[llvm] [Loads] Support dereference for non-constant offset (PR #149551)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 7 10:04:59 PDT 2025


================
@@ -361,29 +361,29 @@ bool llvm::isDereferenceableAndAlignedInLoop(
     AccessSize = MaxPtrDiff;
     AccessSizeSCEV = PtrDiff;
   } else if (auto *MinAdd = dyn_cast<SCEVAddExpr>(AccessStart)) {
-    if (MinAdd->getNumOperands() != 2)
-      return false;
+    const auto *NewBase = dyn_cast<SCEVUnknown>(SE.getPointerBase(MinAdd));
+    const auto *OffsetSCEV = SE.removePointerBase(MinAdd);
 
-    const auto *Offset = dyn_cast<SCEVConstant>(MinAdd->getOperand(0));
-    const auto *NewBase = dyn_cast<SCEVUnknown>(MinAdd->getOperand(1));
-    if (!Offset || !NewBase)
+    if (!OffsetSCEV || !NewBase)
       return false;
 
-    // The following code below assumes the offset is unsigned, but GEP
-    // offsets are treated as signed so we can end up with a signed value
-    // here too. For example, suppose the initial PHI value is (i8 255),
-    // the offset will be treated as (i8 -1) and sign-extended to (i64 -1).
-    if (Offset->getAPInt().isNegative())
+    if (!SE.isKnownNonNegative(OffsetSCEV))
       return false;
 
     // For the moment, restrict ourselves to the case where the offset is a
     // multiple of the requested alignment and the base is aligned.
     // TODO: generalize if a case found which warrants
-    if (Offset->getAPInt().urem(Alignment.value()) != 0)
+    auto *OffsetSCEVTy = OffsetSCEV->getType();
+    if (!SE.isKnownPredicate(
+            ICmpInst::ICMP_EQ,
+            SE.getURemExpr(OffsetSCEV,
+                           SE.getConstant(OffsetSCEVTy, Alignment.value())),
+            SE.getZero(OffsetSCEVTy)))
       return false;
-
-    AccessSize = MaxPtrDiff + Offset->getAPInt();
-    AccessSizeSCEV = SE.getAddExpr(PtrDiff, Offset);
+    AccessSizeSCEV = SE.getAddExpr(PtrDiff, OffsetSCEV);
+    const auto *Offset = dyn_cast<SCEVConstant>(OffsetSCEV);
+    AccessSize = MaxPtrDiff + (Offset ? Offset->getAPInt()
+                                      : SE.getUnsignedRangeMax(OffsetSCEV));
----------------
annamthomas wrote:

The other approach is using `SE.willNotOverflow` check for the `add` but it hits the limitation that the RHS is not constant. 
Here's the example output:
```
OffsetSCEV: (16 + (4 * %iv.start)<nuw><nsw>)<nuw><nsw>   
PtrDiff: ((4 * %N)<nuw><nsw> + (-4 * %iv.start)<nsw>)
AccessSizeSCEV: (16 + (4 * %N)<nuw><nsw>)<nuw><nsw>
```

PtrDiff is actually `AccessEnd - AccessStart`, so the "base" is already removed. 
Base is `16 + %a`
OffsetSCEV is the expression when `%a` is removed in AccessStart, so it will be some symbolic expression containing AccessStart.

So, the AddExpr: <expr> + <constant> (constant here is 16) is easier to prove as not overflow, but it requires performing the operation and then splitting up the expression into LHS and RHS and trying to prove that operation doesn't overflow on LHS and RHS. Any other ideas?



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


More information about the llvm-commits mailing list