[llvm] [Loads] Support dereference for non-constant offset (PR #149551)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 10 05:00:36 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:
Unfortunately, it doesn't. I tried isKnownPredicateAt with Loop's predecessor's terminator as CtxI as well (in case assumes help).
```
define void @deref_assumption_loop_access_start_variable(i8 %v, ptr noundef %P, i64 range(i64 0, 2000) %N, ptr noalias %b, ptr noalias %c, i64 range(i64 0, 2000) %iv.start) nofree nosync {
entry:
%a = getelementptr i8, ptr %P, i64 16
%cmp = icmp slt i64 %iv.start, %N
call void @llvm.assume(i1 %cmp)
%mul = mul i64 %N, 4
%add = add i64 %mul, 16
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %P, i64 %add) ]
br label %loop
...
```
NewBase is %P. AccessStart is `(16 + (4 * %iv.start)<nuw><nsw> + %P). Note the nuw/nsw flags on the "4 * %iv.start". This is present because of the range on iv.start.
>From the above we should get that the offset computation itself does not wrap: should be known from the range on %iv.start.
i.e. (16 + (4 * %iv.start)<nuw><nsw>)<nuw>
Isn't that enough for `AccessStart` `uge` `NewBase`. But something is missing in the logic because we don't identify the range of this arithmetic operation given the range of iv.start is `(0, 2000)`
https://github.com/llvm/llvm-project/pull/149551
More information about the llvm-commits
mailing list