Skip to content

Commit 52ded67

Browse files
authored
[LAA] Always require non-wrapping pointers for runtime checks. (#127543)
Currently we only check if the pointers involved in runtime checks do not wrap if we need to perform dependency checks. If that's not the case, we generate runtime checks, even if the pointers may wrap (see test/Analysis/LoopAccessAnalysis/runtime-checks-may-wrap.ll). If the pointer wraps, then we swap start and end of the runtime check, leading to incorrect checks. An Alive2 proof of what the runtime checks are checking conceptually (on i4 to have it complete in reasonable time) showing the incorrect result should be https://alive2.llvm.org/ce/z/KsHzn8 Depends on #127410 to avoid more regressions. PR: #127543
1 parent f7a10f0 commit 52ded67

8 files changed

+166
-104
lines changed

llvm/lib/Analysis/LoopAccessAnalysis.cpp

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -677,16 +677,17 @@ class AccessAnalysis {
677677
const DenseMap<Value *, const SCEV *> &Strides,
678678
DenseMap<Value *, unsigned> &DepSetId,
679679
Loop *TheLoop, unsigned &RunningDepId,
680-
unsigned ASId, bool ShouldCheckStride, bool Assume);
680+
unsigned ASId, bool Assume);
681681

682682
/// Check whether we can check the pointers at runtime for
683683
/// non-intersection.
684684
///
685685
/// Returns true if we need no check or if we do and we can generate them
686686
/// (i.e. the pointers have computable bounds).
687687
bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, ScalarEvolution *SE,
688-
Loop *TheLoop, const DenseMap<Value *, const SCEV *> &Strides,
689-
Value *&UncomputablePtr, bool ShouldCheckWrap = false);
688+
Loop *TheLoop,
689+
const DenseMap<Value *, const SCEV *> &Strides,
690+
Value *&UncomputablePtr);
690691

691692
/// Goes over all memory accesses, checks whether a RT check is needed
692693
/// and builds sets of dependent accesses.
@@ -1115,13 +1116,11 @@ findForkedPointer(PredicatedScalarEvolution &PSE,
11151116
return {{replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr), false}};
11161117
}
11171118

1118-
bool AccessAnalysis::createCheckForAccess(RuntimePointerChecking &RtCheck,
1119-
MemAccessInfo Access, Type *AccessTy,
1120-
const DenseMap<Value *, const SCEV *> &StridesMap,
1121-
DenseMap<Value *, unsigned> &DepSetId,
1122-
Loop *TheLoop, unsigned &RunningDepId,
1123-
unsigned ASId, bool ShouldCheckWrap,
1124-
bool Assume) {
1119+
bool AccessAnalysis::createCheckForAccess(
1120+
RuntimePointerChecking &RtCheck, MemAccessInfo Access, Type *AccessTy,
1121+
const DenseMap<Value *, const SCEV *> &StridesMap,
1122+
DenseMap<Value *, unsigned> &DepSetId, Loop *TheLoop,
1123+
unsigned &RunningDepId, unsigned ASId, bool Assume) {
11251124
Value *Ptr = Access.getPointer();
11261125

11271126
SmallVector<PointerIntPair<const SCEV *, 1, bool>> TranslatedPtrs =
@@ -1152,8 +1151,7 @@ bool AccessAnalysis::createCheckForAccess(RuntimePointerChecking &RtCheck,
11521151

11531152
// When we run after a failing dependency check we have to make sure
11541153
// we don't have wrapping pointers.
1155-
if (ShouldCheckWrap &&
1156-
!isNoWrap(PSE, AR, TranslatedPtrs.size() == 1 ? Ptr : nullptr, AccessTy,
1154+
if (!isNoWrap(PSE, AR, TranslatedPtrs.size() == 1 ? Ptr : nullptr, AccessTy,
11571155
TheLoop, Assume)) {
11581156
return false;
11591157
}
@@ -1182,10 +1180,10 @@ bool AccessAnalysis::createCheckForAccess(RuntimePointerChecking &RtCheck,
11821180
return true;
11831181
}
11841182

1185-
bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck,
1186-
ScalarEvolution *SE, Loop *TheLoop,
1187-
const DenseMap<Value *, const SCEV *> &StridesMap,
1188-
Value *&UncomputablePtr, bool ShouldCheckWrap) {
1183+
bool AccessAnalysis::canCheckPtrAtRT(
1184+
RuntimePointerChecking &RtCheck, ScalarEvolution *SE, Loop *TheLoop,
1185+
const DenseMap<Value *, const SCEV *> &StridesMap,
1186+
Value *&UncomputablePtr) {
11891187
// Find pointers with computable bounds. We are going to use this information
11901188
// to place a runtime bound check.
11911189
bool CanDoRT = true;
@@ -1245,7 +1243,7 @@ bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck,
12451243
for (const auto &AccessTy : Accesses[Access]) {
12461244
if (!createCheckForAccess(RtCheck, Access, AccessTy, StridesMap,
12471245
DepSetId, TheLoop, RunningDepId, ASId,
1248-
ShouldCheckWrap, false)) {
1246+
false)) {
12491247
LLVM_DEBUG(dbgs() << "LAA: Can't find bounds for ptr:"
12501248
<< *Access.getPointer() << '\n');
12511249
Retries.emplace_back(Access, AccessTy);
@@ -1275,7 +1273,7 @@ bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck,
12751273
for (const auto &[Access, AccessTy] : Retries) {
12761274
if (!createCheckForAccess(RtCheck, Access, AccessTy, StridesMap,
12771275
DepSetId, TheLoop, RunningDepId, ASId,
1278-
ShouldCheckWrap, /*Assume=*/true)) {
1276+
/*Assume=*/true)) {
12791277
CanDoAliasSetRT = false;
12801278
UncomputablePtr = Access.getPointer();
12811279
break;
@@ -2643,9 +2641,8 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI,
26432641
// Find pointers with computable bounds. We are going to use this information
26442642
// to place a runtime bound check.
26452643
Value *UncomputablePtr = nullptr;
2646-
bool CanDoRTIfNeeded =
2647-
Accesses.canCheckPtrAtRT(*PtrRtChecking, PSE->getSE(), TheLoop,
2648-
SymbolicStrides, UncomputablePtr, false);
2644+
bool CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(
2645+
*PtrRtChecking, PSE->getSE(), TheLoop, SymbolicStrides, UncomputablePtr);
26492646
if (!CanDoRTIfNeeded) {
26502647
const auto *I = dyn_cast_or_null<Instruction>(UncomputablePtr);
26512648
recordAnalysis("CantIdentifyArrayBounds", I)
@@ -2676,7 +2673,7 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI,
26762673
auto *SE = PSE->getSE();
26772674
UncomputablePtr = nullptr;
26782675
CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(
2679-
*PtrRtChecking, SE, TheLoop, SymbolicStrides, UncomputablePtr, true);
2676+
*PtrRtChecking, SE, TheLoop, SymbolicStrides, UncomputablePtr);
26802677

26812678
// Check that we found the bounds for the pointer.
26822679
if (!CanDoRTIfNeeded) {

llvm/test/Analysis/LoopAccessAnalysis/nusw-predicates.ll

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ define void @int_and_pointer_predicate(ptr %v, i32 %N) {
1515
; CHECK-EMPTY:
1616
; CHECK-NEXT: Run-time memory checks:
1717
; CHECK-NEXT: Grouped accesses:
18+
; CHECK-NEXT: Group [[GRP1:0x[0-9a-f]+]]:
19+
; CHECK-NEXT: (Low: %v High: (2 + %v))
20+
; CHECK-NEXT: Member: %v
21+
; CHECK-NEXT: Group [[GRP2:0x[0-9a-f]+]]:
22+
; CHECK-NEXT: (Low: %v High: (6 + (4 * (trunc i32 %N to i16)) + %v))
23+
; CHECK-NEXT: Member: {%v,+,4}<%loop>
1824
; CHECK-EMPTY:
1925
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
2026
; CHECK-NEXT: SCEV assumptions:
@@ -57,36 +63,36 @@ define void @int_and_multiple_pointer_predicates(ptr %v, ptr %w, i32 %N) {
5763
; CHECK-EMPTY:
5864
; CHECK-NEXT: Run-time memory checks:
5965
; CHECK-NEXT: Check 0:
60-
; CHECK-NEXT: Comparing group ([[GRP1:0x[0-9a-f]+]]):
66+
; CHECK-NEXT: Comparing group ([[GRP3:0x[0-9a-f]+]]):
6167
; CHECK-NEXT: ptr %v
62-
; CHECK-NEXT: Against group ([[GRP2:0x[0-9a-f]+]]):
68+
; CHECK-NEXT: Against group ([[GRP4:0x[0-9a-f]+]]):
6369
; CHECK-NEXT: ptr %w
6470
; CHECK-NEXT: Check 1:
65-
; CHECK-NEXT: Comparing group ([[GRP1]]):
71+
; CHECK-NEXT: Comparing group ([[GRP3]]):
6672
; CHECK-NEXT: ptr %v
67-
; CHECK-NEXT: Against group ([[GRP3:0x[0-9a-f]+]]):
73+
; CHECK-NEXT: Against group ([[GRP5:0x[0-9a-f]+]]):
6874
; CHECK-NEXT: %gep.w = getelementptr { i16, i16 }, ptr %w, i16 %iv.i16
6975
; CHECK-NEXT: Check 2:
70-
; CHECK-NEXT: Comparing group ([[GRP4:0x[0-9a-f]+]]):
76+
; CHECK-NEXT: Comparing group ([[GRP6:0x[0-9a-f]+]]):
7177
; CHECK-NEXT: %gep.v = getelementptr { i16, i16 }, ptr %v, i16 %iv.i16
72-
; CHECK-NEXT: Against group ([[GRP2]]):
78+
; CHECK-NEXT: Against group ([[GRP4]]):
7379
; CHECK-NEXT: ptr %w
7480
; CHECK-NEXT: Check 3:
75-
; CHECK-NEXT: Comparing group ([[GRP4]]):
81+
; CHECK-NEXT: Comparing group ([[GRP6]]):
7682
; CHECK-NEXT: %gep.v = getelementptr { i16, i16 }, ptr %v, i16 %iv.i16
77-
; CHECK-NEXT: Against group ([[GRP3]]):
83+
; CHECK-NEXT: Against group ([[GRP5]]):
7884
; CHECK-NEXT: %gep.w = getelementptr { i16, i16 }, ptr %w, i16 %iv.i16
7985
; CHECK-NEXT: Grouped accesses:
80-
; CHECK-NEXT: Group [[GRP1]]:
86+
; CHECK-NEXT: Group [[GRP3]]:
8187
; CHECK-NEXT: (Low: %v High: (2 + %v))
8288
; CHECK-NEXT: Member: %v
83-
; CHECK-NEXT: Group [[GRP4]]:
89+
; CHECK-NEXT: Group [[GRP6]]:
8490
; CHECK-NEXT: (Low: %v High: (6 + (4 * (trunc i32 %N to i16)) + %v))
8591
; CHECK-NEXT: Member: {%v,+,4}<%loop>
86-
; CHECK-NEXT: Group [[GRP2]]:
92+
; CHECK-NEXT: Group [[GRP4]]:
8793
; CHECK-NEXT: (Low: %w High: (2 + %w))
8894
; CHECK-NEXT: Member: %w
89-
; CHECK-NEXT: Group [[GRP3]]:
95+
; CHECK-NEXT: Group [[GRP5]]:
9096
; CHECK-NEXT: (Low: %w High: (6 + (4 * (trunc i32 %N to i16)) + %w))
9197
; CHECK-NEXT: Member: {%w,+,4}<%loop>
9298
; CHECK-EMPTY:

llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ exit:
163163
define void @dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs_may_wrap_1(ptr %a, ptr %b, ptr %c, i64 %offset, i64 %n) {
164164
; CHECK-LABEL: 'dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs_may_wrap_1'
165165
; CHECK-NEXT: loop:
166-
; CHECK-NEXT: Report: cannot check memory dependencies at runtime
166+
; CHECK-NEXT: Report: cannot identify array bounds
167167
; CHECK-NEXT: Dependences:
168168
; CHECK-NEXT: Run-time memory checks:
169169
; CHECK-NEXT: Grouped accesses:
@@ -204,7 +204,7 @@ exit:
204204
define void @dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs_may_wrap_2(ptr %a, ptr %b, ptr %c, i64 %offset, i64 %n) {
205205
; CHECK-LABEL: 'dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs_may_wrap_2'
206206
; CHECK-NEXT: loop:
207-
; CHECK-NEXT: Report: cannot check memory dependencies at runtime
207+
; CHECK-NEXT: Report: cannot identify array bounds
208208
; CHECK-NEXT: Dependences:
209209
; CHECK-NEXT: Run-time memory checks:
210210
; CHECK-NEXT: Grouped accesses:

llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis.ll

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,27 @@ define void @dependency_check_and_runtime_checks_needed_gepb_not_inbounds_iv2_st
7272
; CHECK-NEXT: Comparing group ([[GRP4:0x[0-9a-f]+]]):
7373
; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
7474
; CHECK-NEXT: Against group ([[GRP5:0x[0-9a-f]+]]):
75-
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
75+
; CHECK-NEXT: %gep.b = getelementptr i8, ptr %b, i64 %iv2
7676
; CHECK-NEXT: Check 1:
7777
; CHECK-NEXT: Comparing group ([[GRP4]]):
7878
; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
7979
; CHECK-NEXT: Against group ([[GRP6:0x[0-9a-f]+]]):
80-
; CHECK-NEXT: %gep.b = getelementptr i8, ptr %b, i64 %iv2
80+
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
8181
; CHECK-NEXT: Check 2:
8282
; CHECK-NEXT: Comparing group ([[GRP5]]):
83-
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
84-
; CHECK-NEXT: Against group ([[GRP6]]):
8583
; CHECK-NEXT: %gep.b = getelementptr i8, ptr %b, i64 %iv2
84+
; CHECK-NEXT: Against group ([[GRP6]]):
85+
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
8686
; CHECK-NEXT: Grouped accesses:
8787
; CHECK-NEXT: Group [[GRP4]]:
8888
; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a))
8989
; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
9090
; CHECK-NEXT: Group [[GRP5]]:
91-
; CHECK-NEXT: (Low: ((4 * %offset) + %a) High: ((4 * %offset) + (4 * %n) + %a))
92-
; CHECK-NEXT: Member: {((4 * %offset) + %a),+,4}<%loop>
93-
; CHECK-NEXT: Group [[GRP6]]:
9491
; CHECK-NEXT: (Low: %b High: (-1 + (5 * %n) + %b))
9592
; CHECK-NEXT: Member: {%b,+,5}<%loop>
93+
; CHECK-NEXT: Group [[GRP6]]:
94+
; CHECK-NEXT: (Low: ((4 * %offset) + %a) High: ((4 * %offset) + (4 * %n) + %a))
95+
; CHECK-NEXT: Member: {((4 * %offset) + %a),+,4}<%loop>
9696
; CHECK-EMPTY:
9797
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
9898
; CHECK-NEXT: SCEV assumptions:
@@ -265,27 +265,27 @@ define void @dependency_check_and_runtime_checks_needed_gepb_may_wrap(ptr %a, pt
265265
; CHECK-NEXT: Comparing group ([[GRP13:0x[0-9a-f]+]]):
266266
; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
267267
; CHECK-NEXT: Against group ([[GRP14:0x[0-9a-f]+]]):
268-
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
268+
; CHECK-NEXT: %gep.b = getelementptr float, ptr %b, i64 %iv2
269269
; CHECK-NEXT: Check 1:
270270
; CHECK-NEXT: Comparing group ([[GRP13]]):
271271
; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
272272
; CHECK-NEXT: Against group ([[GRP15:0x[0-9a-f]+]]):
273-
; CHECK-NEXT: %gep.b = getelementptr float, ptr %b, i64 %iv2
273+
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
274274
; CHECK-NEXT: Check 2:
275275
; CHECK-NEXT: Comparing group ([[GRP14]]):
276-
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
277-
; CHECK-NEXT: Against group ([[GRP15]]):
278276
; CHECK-NEXT: %gep.b = getelementptr float, ptr %b, i64 %iv2
277+
; CHECK-NEXT: Against group ([[GRP15]]):
278+
; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
279279
; CHECK-NEXT: Grouped accesses:
280280
; CHECK-NEXT: Group [[GRP13]]:
281281
; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a))
282282
; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
283283
; CHECK-NEXT: Group [[GRP14]]:
284-
; CHECK-NEXT: (Low: ((4 * %offset) + %a) High: ((4 * %offset) + (4 * %n) + %a))
285-
; CHECK-NEXT: Member: {((4 * %offset) + %a),+,4}<%loop>
286-
; CHECK-NEXT: Group [[GRP15]]:
287284
; CHECK-NEXT: (Low: %b High: (-4 + (8 * %n) + %b))
288285
; CHECK-NEXT: Member: {%b,+,8}<%loop>
286+
; CHECK-NEXT: Group [[GRP15]]:
287+
; CHECK-NEXT: (Low: ((4 * %offset) + %a) High: ((4 * %offset) + (4 * %n) + %a))
288+
; CHECK-NEXT: Member: {((4 * %offset) + %a),+,4}<%loop>
289289
; CHECK-EMPTY:
290290
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
291291
; CHECK-NEXT: SCEV assumptions:

llvm/test/Analysis/LoopAccessAnalysis/runtime-checks-may-wrap.ll

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,21 @@ define void @geps_may_wrap(ptr %a, ptr %b, i64 %N) {
1111
; CHECK-NEXT: Run-time memory checks:
1212
; CHECK-NEXT: Check 0:
1313
; CHECK-NEXT: Comparing group ([[GRP1:0x[0-9a-f]+]]):
14-
; CHECK-NEXT: %gep.iv = getelementptr i32, ptr %a, i64 %iv
15-
; CHECK-NEXT: Against group ([[GRP2:0x[0-9a-f]+]]):
1614
; CHECK-NEXT: ptr %b
15+
; CHECK-NEXT: Against group ([[GRP2:0x[0-9a-f]+]]):
16+
; CHECK-NEXT: %gep.iv = getelementptr i32, ptr %a, i64 %iv
1717
; CHECK-NEXT: Grouped accesses:
1818
; CHECK-NEXT: Group [[GRP1]]:
19-
; CHECK-NEXT: (Low: %a High: (16 + (12 * (trunc i128 ((zext i64 %N to i128) /u 3) to i16)) + %a))
20-
; CHECK-NEXT: Member: {%a,+,12}<%loop>
21-
; CHECK-NEXT: Group [[GRP2]]:
2219
; CHECK-NEXT: (Low: %b High: (4 + %b))
2320
; CHECK-NEXT: Member: %b
21+
; CHECK-NEXT: Group [[GRP2]]:
22+
; CHECK-NEXT: (Low: %a High: (16 + (12 * (trunc i128 ((zext i64 %N to i128) /u 3) to i16)) + %a))
23+
; CHECK-NEXT: Member: {%a,+,12}<%loop>
2424
; CHECK-EMPTY:
2525
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
2626
; CHECK-NEXT: SCEV assumptions:
2727
; CHECK-NEXT: {0,+,3}<%loop> Added Flags: <nusw>
28+
; CHECK-NEXT: {%a,+,12}<%loop> Added Flags: <nusw>
2829
; CHECK-EMPTY:
2930
; CHECK-NEXT: Expressions re-written:
3031
;

0 commit comments

Comments
 (0)