1; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -irce-allow-unsigned-latch=true -S < %s 2>&1 | FileCheck %s
2
3; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
4; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
5; CHECK: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
6; CHECK: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
7; CHECK-NOT: irce: in function test_05: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
8; CHECK: irce: in function test_06: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
9
10; UGT condition for increasing loop.
11define void @test_01(i32* %arr, i32* %a_len_ptr) #0 {
12
13; CHECK: test_01(
14; CHECK:        entry:
15; CHECK-NEXT:     %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0
16; CHECK-NEXT:     [[COND:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at
17; CHECK-NEXT:     br i1 [[COND]], label %loop.preheader, label %main.pseudo.exit
18; CHECK:        loop:
19; CHECK-NEXT:     %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
20; CHECK-NEXT:     %idx.next = add nuw nsw i32 %idx, 1
21; CHECK-NEXT:     %abc = icmp ult i32 %idx, %exit.mainloop.at
22; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
23; CHECK-NOT:    loop.preloop:
24; CHECK:        loop.postloop:
25; CHECK-NEXT:     %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
26; CHECK-NEXT:     %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1
27; CHECK-NEXT:     %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at
28; CHECK-NEXT:     br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
29
30entry:
31  %len = load i32, i32* %a_len_ptr, !range !0
32  br label %loop
33
34loop:
35  %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
36  %idx.next = add nsw nuw i32 %idx, 1
37  %abc = icmp ult i32 %idx, %len
38  br i1 %abc, label %in.bounds, label %out.of.bounds
39
40in.bounds:
41  %addr = getelementptr i32, i32* %arr, i32 %idx
42  store i32 0, i32* %addr
43  %next = icmp ugt i32 %idx.next, 100
44  br i1 %next, label %exit, label %loop
45
46out.of.bounds:
47  ret void
48
49exit:
50  ret void
51}
52
53; UGT condition for decreasing loop.
54define void @test_02(i32* %arr, i32* %a_len_ptr) #0 {
55
56; CHECK: test_02(
57; CHECK:        entry:
58; CHECK-NEXT:     %len = load i32, i32* %a_len_ptr, !range !0
59; CHECK-NEXT:     [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1
60; CHECK-NEXT:     %umax = select i1 [[COND1]], i32 %len, i32 1
61; CHECK-NEXT:     %exit.preloop.at = add i32 %umax, -1
62; CHECK-NEXT:     [[COND2:%[^ ]+]] = icmp ugt i32 100, %exit.preloop.at
63; CHECK-NEXT:     br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit
64; CHECK:        mainloop:
65; CHECK-NEXT:     br label %loop
66; CHECK:        loop:
67; CHECK-NEXT:     %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ]
68; CHECK-NEXT:     %idx.next = add i32 %idx, -1
69; CHECK-NEXT:     %abc = icmp ult i32 %idx, %len
70; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
71; CHECK-NOT:    loop.postloop:
72; CHECK:        loop.preloop:
73; CHECK-NEXT:     %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ 100, %loop.preloop.preheader ]
74; CHECK-NEXT:     %idx.next.preloop = add i32 %idx.preloop, -1
75; CHECK-NEXT:     %abc.preloop = icmp ult i32 %idx.preloop, %len
76; CHECK-NEXT:     br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit
77
78entry:
79  %len = load i32, i32* %a_len_ptr, !range !0
80  br label %loop
81
82loop:
83  %idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ]
84  %idx.next = add i32 %idx, -1
85  %abc = icmp ult i32 %idx, %len
86  br i1 %abc, label %in.bounds, label %out.of.bounds
87
88in.bounds:
89  %addr = getelementptr i32, i32* %arr, i32 %idx
90  store i32 0, i32* %addr
91  %next = icmp ugt i32 %idx.next, 0
92  br i1 %next, label %loop, label %exit
93
94out.of.bounds:
95  ret void
96
97exit:
98  ret void
99}
100
101; Check SINT_MAX + 1, test is similar to test_01.
102define void @test_03(i32* %arr, i32* %a_len_ptr) #0 {
103
104; CHECK: test_03(
105; CHECK:        entry:
106; CHECK-NEXT:     %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0
107; CHECK-NEXT:     [[COND:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at
108; CHECK-NEXT:     br i1 [[COND]], label %loop.preheader, label %main.pseudo.exit
109; CHECK:        loop:
110; CHECK-NEXT:     %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
111; CHECK-NEXT:     %idx.next = add nuw nsw i32 %idx, 1
112; CHECK-NEXT:     %abc = icmp ult i32 %idx, %exit.mainloop.at
113; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
114; CHECK-NOT:    loop.preloop:
115; CHECK:        loop.postloop:
116; CHECK-NEXT:     %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
117; CHECK-NEXT:     %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1
118; CHECK-NEXT:     %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at
119; CHECK-NEXT:     br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
120
121entry:
122  %len = load i32, i32* %a_len_ptr, !range !0
123  br label %loop
124
125loop:
126  %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
127  %idx.next = add nsw nuw i32 %idx, 1
128  %abc = icmp ult i32 %idx, %len
129  br i1 %abc, label %in.bounds, label %out.of.bounds
130
131in.bounds:
132  %addr = getelementptr i32, i32* %arr, i32 %idx
133  store i32 0, i32* %addr
134  %next = icmp ugt i32 %idx.next, 2147483648
135  br i1 %next, label %exit, label %loop
136
137out.of.bounds:
138  ret void
139
140exit:
141  ret void
142}
143
144; Check SINT_MAX + 1, test is similar to test_02.
145define void @test_04(i32* %arr, i32* %a_len_ptr) #0 {
146
147; CHECK: test_04(
148; CHECK:        entry:
149; CHECK-NEXT:     %len = load i32, i32* %a_len_ptr, !range !0
150; CHECK-NEXT:     [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1
151; CHECK-NEXT:     %umax = select i1 [[COND1]], i32 %len, i32 1
152; CHECK-NEXT:     %exit.preloop.at = add i32 %umax, -1
153; CHECK-NEXT:     [[COND2:%[^ ]+]] = icmp ugt i32 -2147483648, %exit.preloop.at
154; CHECK-NEXT:     br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit
155; CHECK:        mainloop:
156; CHECK-NEXT:     br label %loop
157; CHECK:        loop:
158; CHECK-NEXT:     %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ]
159; CHECK-NEXT:     %idx.next = add i32 %idx, -1
160; CHECK-NEXT:     %abc = icmp ult i32 %idx, %len
161; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
162; CHECK-NOT:    loop.postloop:
163; CHECK:        loop.preloop:
164; CHECK-NEXT:     %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ -2147483648, %loop.preloop.preheader ]
165; CHECK-NEXT:     %idx.next.preloop = add i32 %idx.preloop, -1
166; CHECK-NEXT:     %abc.preloop = icmp ult i32 %idx.preloop, %len
167; CHECK-NEXT:     br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit
168
169entry:
170  %len = load i32, i32* %a_len_ptr, !range !0
171  br label %loop
172
173loop:
174  %idx = phi i32 [ 2147483648, %entry ], [ %idx.next, %in.bounds ]
175  %idx.next = add i32 %idx, -1
176  %abc = icmp ult i32 %idx, %len
177  br i1 %abc, label %in.bounds, label %out.of.bounds
178
179in.bounds:
180  %addr = getelementptr i32, i32* %arr, i32 %idx
181  store i32 0, i32* %addr
182  %next = icmp ugt i32 %idx.next, 0
183  br i1 %next, label %loop, label %exit
184
185out.of.bounds:
186  ret void
187
188exit:
189  ret void
190}
191
192; Increasing loop, UINT_MAX. Negative test: we cannot add 1 to UINT_MAX.
193define void @test_05(i32* %arr, i32* %a_len_ptr) #0 {
194
195; CHECK: test_05(
196; CHECK-NOT:    loop.preloop:
197; CHECK-NOT:    loop.postloop:
198
199entry:
200  %len = load i32, i32* %a_len_ptr, !range !0
201  br label %loop
202
203loop:
204  %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
205  %idx.next = add nsw nuw i32 %idx, 1
206  %abc = icmp ult i32 %idx, %len
207  br i1 %abc, label %in.bounds, label %out.of.bounds
208
209in.bounds:
210  %addr = getelementptr i32, i32* %arr, i32 %idx
211  store i32 0, i32* %addr
212  %next = icmp ugt i32 %idx.next, 4294967295
213  br i1 %next, label %exit, label %loop
214
215out.of.bounds:
216  ret void
217
218exit:
219  ret void
220}
221
222; Decreasing loop, UINT_MAX. Positive test.
223define void @test_06(i32* %arr, i32* %a_len_ptr) #0 {
224
225; CHECK: test_06(
226; CHECK:        mainloop:
227; CHECK-NEXT:     br label %loop
228; CHECK:        loop:
229; CHECK-NEXT:     %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ]
230; CHECK-NEXT:     %idx.next = add nuw i32 %idx, -1
231; CHECK-NEXT:     %abc = icmp ult i32 %idx, %len
232; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
233; CHECK-NOT:    loop.postloop:
234; CHECK:        loop.preloop:
235; CHECK-NEXT:     %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ -1, %loop.preloop.preheader ]
236; CHECK-NEXT:     %idx.next.preloop = add nuw i32 %idx.preloop, -1
237; CHECK-NEXT:     %abc.preloop = icmp ult i32 %idx.preloop, %len
238; CHECK-NEXT:     br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit
239
240entry:
241  %len = load i32, i32* %a_len_ptr, !range !0
242  br label %loop
243
244loop:
245  %idx = phi i32 [ 4294967295, %entry ], [ %idx.next, %in.bounds ]
246  %idx.next = add nuw i32 %idx, -1
247  %abc = icmp ult i32 %idx, %len
248  br i1 %abc, label %in.bounds, label %out.of.bounds
249
250in.bounds:
251  %addr = getelementptr i32, i32* %arr, i32 %idx
252  store i32 0, i32* %addr
253  %next = icmp ugt i32 %idx.next, 0
254  br i1 %next, label %loop, label %exit
255
256out.of.bounds:
257  ret void
258
259exit:
260  ret void
261}
262
263!0 = !{i32 0, i32 50}
264