Skip to content

Commit 4ee9f88

Browse files
author
Aleksander Popov
committed
[NFC][IRCE] Add unit test to show room for improvement
Add tests for compound loop bounds where IRCE is possible if (K > 0 && M > 0) for (i = 0; i < min(K, M); i++) {...} if (K > 0 && M > 0) for (i = min(K, M); i >= 0; i--) {...}
1 parent 4428b01 commit 4ee9f88

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
2+
; RUN: opt -passes=irce < %s -S | FileCheck %s
3+
4+
; if (K > 0 && M > 0)
5+
; for (i = 0; i < min(K, M); i++) {...}
6+
;
7+
; TODO: Loop bounds are safe according to loop guards. IRCE is allowed.
8+
define void @incrementing_loop(ptr %arr, ptr %len_ptr, i32 %K, i32 %M) {
9+
; CHECK-LABEL: define void @incrementing_loop(
10+
; CHECK-SAME: ptr [[ARR:%.*]], ptr [[LEN_PTR:%.*]], i32 [[K:%.*]], i32 [[M:%.*]]) {
11+
; CHECK-NEXT: entry:
12+
; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_PTR]], align 4, !range [[RNG0:![0-9]+]]
13+
; CHECK-NEXT: [[CHECK0:%.*]] = icmp sgt i32 [[K]], 0
14+
; CHECK-NEXT: [[CHECK1:%.*]] = icmp sgt i32 [[M]], 0
15+
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CHECK0]], [[CHECK1]]
16+
; CHECK-NEXT: br i1 [[AND]], label [[PREHEADER:%.*]], label [[EXIT:%.*]]
17+
; CHECK: preheader:
18+
; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[K]], i32 [[M]])
19+
; CHECK-NEXT: br label [[LOOP:%.*]]
20+
; CHECK: loop:
21+
; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ]
22+
; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], 1
23+
; CHECK-NEXT: [[GUARD:%.*]] = icmp slt i32 [[IDX]], [[LEN]]
24+
; CHECK-NEXT: br i1 [[GUARD]], label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
25+
; CHECK: in.bounds:
26+
; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]]
27+
; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4
28+
; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], [[SMIN]]
29+
; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
30+
; CHECK: out.of.bounds:
31+
; CHECK-NEXT: ret void
32+
; CHECK: exit.loopexit:
33+
; CHECK-NEXT: br label [[EXIT]]
34+
; CHECK: exit:
35+
; CHECK-NEXT: ret void
36+
;
37+
entry:
38+
%len = load i32, ptr %len_ptr, !range !0
39+
%check0 = icmp sgt i32 %K, 0
40+
%check1 = icmp sgt i32 %M, 0
41+
%and = and i1 %check0, %check1
42+
br i1 %and, label %preheader, label %exit
43+
44+
preheader:
45+
%smin = call i32 @llvm.smin.i32(i32 %K, i32 %M)
46+
br label %loop
47+
48+
loop:
49+
%idx = phi i32 [ 0, %preheader ], [ %idx.next, %in.bounds ]
50+
%idx.next = add i32 %idx, 1
51+
%guard = icmp slt i32 %idx, %len
52+
br i1 %guard, label %in.bounds, label %out.of.bounds
53+
54+
in.bounds:
55+
%addr = getelementptr i32, ptr %arr, i32 %idx
56+
store i32 0, ptr %addr
57+
%next = icmp slt i32 %idx.next, %smin
58+
br i1 %next, label %loop, label %exit
59+
60+
out.of.bounds:
61+
ret void
62+
63+
exit:
64+
ret void
65+
}
66+
67+
; if (K > 0 && M > 0)
68+
; for (i = min(K, M); i >= 0; i--) {...}
69+
;
70+
; TODO: Loop bounds are safe according to loop guards. IRCE is allowed.
71+
define void @decrementing_loop(ptr %arr, ptr %len_ptr, i32 %K, i32 %M) {
72+
; CHECK-LABEL: define void @decrementing_loop(
73+
; CHECK-SAME: ptr [[ARR:%.*]], ptr [[LEN_PTR:%.*]], i32 [[K:%.*]], i32 [[M:%.*]]) {
74+
; CHECK-NEXT: entry:
75+
; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_PTR]], align 4, !range [[RNG0]]
76+
; CHECK-NEXT: [[CHECK0:%.*]] = icmp sgt i32 [[K]], 0
77+
; CHECK-NEXT: [[CHECK1:%.*]] = icmp sgt i32 [[M]], 0
78+
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CHECK0]], [[CHECK1]]
79+
; CHECK-NEXT: br i1 [[AND]], label [[PREHEADER:%.*]], label [[EXIT:%.*]]
80+
; CHECK: preheader:
81+
; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[K]], i32 [[M]])
82+
; CHECK-NEXT: br label [[LOOP:%.*]]
83+
; CHECK: loop:
84+
; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[SMIN]], [[PREHEADER]] ], [ [[IDX_DEC:%.*]], [[IN_BOUNDS:%.*]] ]
85+
; CHECK-NEXT: [[IDX_DEC]] = sub i32 [[IDX]], 1
86+
; CHECK-NEXT: [[GUARD:%.*]] = icmp slt i32 [[IDX]], [[LEN]]
87+
; CHECK-NEXT: br i1 [[GUARD]], label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
88+
; CHECK: in.bounds:
89+
; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]]
90+
; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4
91+
; CHECK-NEXT: [[NEXT:%.*]] = icmp sgt i32 [[IDX_DEC]], -1
92+
; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
93+
; CHECK: out.of.bounds:
94+
; CHECK-NEXT: ret void
95+
; CHECK: exit.loopexit:
96+
; CHECK-NEXT: br label [[EXIT]]
97+
; CHECK: exit:
98+
; CHECK-NEXT: ret void
99+
;
100+
entry:
101+
%len = load i32, ptr %len_ptr, !range !0
102+
%check0 = icmp sgt i32 %K, 0
103+
%check1 = icmp sgt i32 %M, 0
104+
%and = and i1 %check0, %check1
105+
br i1 %and, label %preheader, label %exit
106+
107+
preheader:
108+
%smin = call i32 @llvm.smin.i32(i32 %K, i32 %M)
109+
br label %loop
110+
111+
loop:
112+
%idx = phi i32 [ %smin, %preheader ] , [ %idx.dec, %in.bounds ]
113+
%idx.dec = sub i32 %idx, 1
114+
%guard = icmp slt i32 %idx, %len
115+
br i1 %guard, label %in.bounds, label %out.of.bounds
116+
117+
in.bounds:
118+
%addr = getelementptr i32, ptr %arr, i32 %idx
119+
store i32 0, ptr %addr
120+
%next = icmp sgt i32 %idx.dec, -1
121+
br i1 %next, label %loop, label %exit
122+
123+
out.of.bounds:
124+
ret void
125+
126+
exit:
127+
ret void
128+
}
129+
130+
declare i32 @llvm.smin.i32(i32, i32)
131+
132+
!0 = !{i32 0, i32 2147483647}

0 commit comments

Comments
 (0)