Skip to content

Commit

Permalink
[Analysis] Teach ScalarEvolution::getRangeRef about more dereferencea…
Browse files Browse the repository at this point in the history
…ble objects (llvm#104778)

Whilst dealing with review comments on

llvm#96752

I discovered that SCEV does not know about the dereferenceable attribute
on function arguments so I have updated getRangeRef to make use of it
by calling getPointerDereferenceableBytes.
  • Loading branch information
david-arm authored and cjdb committed Aug 23, 2024
1 parent 2afdbf3 commit 29b4726
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 14 deletions.
18 changes: 8 additions & 10 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6855,20 +6855,18 @@ const ConstantRange &ScalarEvolution::getRangeRef(
if (U->getType()->isPointerTy() && SignHint == HINT_RANGE_UNSIGNED) {
// Strengthen the range if the underlying IR value is a
// global/alloca/heap allocation using the size of the object.
ObjectSizeOpts Opts;
Opts.RoundToAlign = false;
Opts.NullIsUnknownSize = true;
uint64_t ObjSize;
if ((isa<GlobalVariable>(V) || isa<AllocaInst>(V) ||
isAllocationFn(V, &TLI)) &&
getObjectSize(V, ObjSize, DL, &TLI, Opts) && ObjSize > 1) {
// The highest address the object can start is ObjSize bytes before the
// end (unsigned max value). If this value is not a multiple of the
bool CanBeNull, CanBeFreed;
uint64_t DerefBytes =
V->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
if (DerefBytes > 1) {
// The highest address the object can start is DerefBytes bytes before
// the end (unsigned max value). If this value is not a multiple of the
// alignment, the last possible start value is the next lowest multiple
// of the alignment. Note: The computations below cannot overflow,
// because if they would there's no possible start address for the
// object.
APInt MaxVal = APInt::getMaxValue(BitWidth) - APInt(BitWidth, ObjSize);
APInt MaxVal =
APInt::getMaxValue(BitWidth) - APInt(BitWidth, DerefBytes);
uint64_t Align = U->getValue()->getPointerAlignment(DL).value();
uint64_t Rem = MaxVal.urem(Align);
MaxVal -= APInt(BitWidth, Rem);
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ define void @test_05(i32 %N) {
; CHECK-NEXT: %"alloca point" = bitcast i32 0 to i32
; CHECK-NEXT: --> 0 U: [0,1) S: [0,1)
; CHECK-NEXT: %tmp = getelementptr [1000 x i32], ptr @A, i32 0, i32 %i.0
; CHECK-NEXT: --> {(8 + @A)<nuw><nsw>,+,4}<nw><%bb3> U: [0,-3) S: [-9223372036854775808,9223372036854775805) Exits: (408 + @A) LoopDispositions: { %bb3: Computable }
; CHECK-NEXT: --> {(8 + @A)<nuw><nsw>,+,4}<nw><%bb3> U: [40,-3623) S: [-9223372036854775808,9223372036854775805) Exits: (408 + @A)<nuw> LoopDispositions: { %bb3: Computable }
; CHECK-NEXT: %tmp2 = add i32 %i.0, 1
; CHECK-NEXT: --> {3,+,1}<nuw><nsw><%bb3> U: [3,104) S: [3,104) Exits: 103 LoopDispositions: { %bb3: Computable }
; CHECK-NEXT: %i.0 = phi i32 [ 2, %entry ], [ %tmp2, %bb ]
Expand Down
41 changes: 39 additions & 2 deletions llvm/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,15 @@ define void @f3(ptr %x_addr, ptr %y_addr, ptr %tmp_addr) {
; CHECK-NEXT: %s3.zext = zext i8 %s3 to i16
; CHECK-NEXT: --> (1 + (zext i8 (4 + (32 * %x) + (36 * %y)) to i16))<nuw><nsw> U: [1,254) S: [1,257)
; CHECK-NEXT: %ptr = bitcast ptr @z_addr to ptr
; CHECK-NEXT: --> @z_addr U: [0,-3) S: [-9223372036854775808,9223372036854775805)
; CHECK-NEXT: --> @z_addr U: [4,-19) S: [-9223372036854775808,9223372036854775805)
; CHECK-NEXT: %int0 = ptrtoint ptr %ptr to i32
; CHECK-NEXT: --> (trunc i64 (ptrtoint ptr @z_addr to i64) to i32) U: [0,-3) S: [-2147483648,2147483645)
; CHECK-NEXT: %int5 = add i32 %int0, 5
; CHECK-NEXT: --> (5 + (trunc i64 (ptrtoint ptr @z_addr to i64) to i32)) U: [5,2) S: [-2147483643,-2147483646)
; CHECK-NEXT: %int.zext = zext i32 %int5 to i64
; CHECK-NEXT: --> (1 + (zext i32 (4 + (trunc i64 (ptrtoint ptr @z_addr to i64) to i32)) to i64))<nuw><nsw> U: [1,4294967294) S: [1,4294967297)
; CHECK-NEXT: %ptr_noalign = bitcast ptr @z_addr_noalign to ptr
; CHECK-NEXT: --> @z_addr_noalign U: full-set S: full-set
; CHECK-NEXT: --> @z_addr_noalign U: [1,-16) S: full-set
; CHECK-NEXT: %int0_na = ptrtoint ptr %ptr_noalign to i32
; CHECK-NEXT: --> (trunc i64 (ptrtoint ptr @z_addr_noalign to i64) to i32) U: full-set S: full-set
; CHECK-NEXT: %int5_na = add i32 %int0_na, 5
Expand Down Expand Up @@ -362,3 +362,40 @@ loop:
exit2:
ret i1 false
}


define void @dereferenceable_arg(ptr dereferenceable(128) %len_addr, ptr dereferenceable(128) align(8) %len_addr2, ptr dereferenceable(13) align(1) %len_addr3) {
; CHECK-LABEL: 'dereferenceable_arg'
; CHECK-NEXT: Classifying expressions for: @dereferenceable_arg
; CHECK-NEXT: %ptr = bitcast ptr %len_addr to ptr
; CHECK-NEXT: --> %len_addr U: [1,-128) S: full-set
; CHECK-NEXT: %ptr2 = bitcast ptr %len_addr2 to ptr
; CHECK-NEXT: --> %len_addr2 U: [8,-135) S: [-9223372036854775808,9223372036854775801)
; CHECK-NEXT: %ptr3 = bitcast ptr %len_addr3 to ptr
; CHECK-NEXT: --> %len_addr3 U: [1,-13) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @dereferenceable_arg
;
entry:
%ptr = bitcast ptr %len_addr to ptr
%ptr2 = bitcast ptr %len_addr2 to ptr
%ptr3 = bitcast ptr %len_addr3 to ptr

ret void
}


define void @dereferenceable_or_null_arg(ptr dereferenceable_or_null(128) %len_addr, ptr dereferenceable_or_null(128) align(8) %len_addr2) {
; CHECK-LABEL: 'dereferenceable_or_null_arg'
; CHECK-NEXT: Classifying expressions for: @dereferenceable_or_null_arg
; CHECK-NEXT: %ptr = bitcast ptr %len_addr to ptr
; CHECK-NEXT: --> %len_addr U: [0,-128) S: full-set
; CHECK-NEXT: %ptr2 = bitcast ptr %len_addr2 to ptr
; CHECK-NEXT: --> %len_addr2 U: [0,-135) S: [-9223372036854775808,9223372036854775801)
; CHECK-NEXT: Determining loop execution counts for: @dereferenceable_or_null_arg
;
entry:
%ptr = bitcast ptr %len_addr to ptr
%ptr2 = bitcast ptr %len_addr2 to ptr

ret void
}
2 changes: 1 addition & 1 deletion llvm/test/Transforms/PhaseOrdering/scev-custom-dl.ll
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ define void @test_range_ref1a(i32 %x) {
; CHECK-NEXT: %i.01.0 = phi i32 [ 100, %entry ], [ %tmp4, %bb ]
; CHECK-NEXT: --> {100,+,-1}<nsw><%bb> U: [0,101) S: [0,101) Exits: 0 LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %tmp1 = getelementptr [101 x i32], ptr @array, i32 0, i32 %i.01.0
; CHECK-NEXT: --> {(400 + @array),+,-4}<nw><%bb> U: [0,-3) S: [-2147483648,2147483645) Exits: @array LoopDispositions: { %bb: Computable }
; CHECK-NEXT: --> {(400 + @array)<nuw>,+,-4}<nw><%bb> U: [0,-3) S: [-2147483648,2147483645) Exits: @array LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %tmp4 = add nsw i32 %i.01.0, -1
; CHECK-NEXT: --> {99,+,-1}<nsw><%bb> U: [-1,100) S: [-1,100) Exits: -1 LoopDispositions: { %bb: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_range_ref1a
Expand Down

0 comments on commit 29b4726

Please sign in to comment.