1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -mtriple=thumbv8m.main -indvars -S < %s | FileCheck %s --check-prefix=CHECK-V8M
3 ; RUN: opt -mtriple=thumbv8a -indvars -S < %s | FileCheck %s --check-prefix=CHECK-V8A
5 define i32 @remove_loop(i32 %size) #0 {
6 ; CHECK-V8M-LABEL: @remove_loop(
7 ; CHECK-V8M-NEXT: entry:
8 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[SIZE:%.*]], 31
9 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SIZE]], i32 31)
10 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = sub i32 [[TMP0]], [[UMIN]]
11 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 5
12 ; CHECK-V8M-NEXT: [[TMP3:%.*]] = shl nuw i32 [[TMP2]], 5
13 ; CHECK-V8M-NEXT: br label [[WHILE_COND:%.*]]
14 ; CHECK-V8M: while.cond:
15 ; CHECK-V8M-NEXT: br i1 false, label [[WHILE_COND]], label [[WHILE_END:%.*]]
16 ; CHECK-V8M: while.end:
17 ; CHECK-V8M-NEXT: [[TMP4:%.*]] = sub i32 [[SIZE]], [[TMP3]]
18 ; CHECK-V8M-NEXT: ret i32 [[TMP4]]
20 ; CHECK-V8A-LABEL: @remove_loop(
21 ; CHECK-V8A-NEXT: entry:
22 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[SIZE:%.*]], 31
23 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SIZE]], i32 31)
24 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = sub i32 [[TMP0]], [[UMIN]]
25 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 5
26 ; CHECK-V8A-NEXT: [[TMP3:%.*]] = shl nuw i32 [[TMP2]], 5
27 ; CHECK-V8A-NEXT: br label [[WHILE_COND:%.*]]
28 ; CHECK-V8A: while.cond:
29 ; CHECK-V8A-NEXT: br i1 false, label [[WHILE_COND]], label [[WHILE_END:%.*]]
30 ; CHECK-V8A: while.end:
31 ; CHECK-V8A-NEXT: [[TMP4:%.*]] = sub i32 [[SIZE]], [[TMP3]]
32 ; CHECK-V8A-NEXT: ret i32 [[TMP4]]
37 while.cond: ; preds = %while.cond, %entry
38 %size.addr.0 = phi i32 [ %size, %entry ], [ %sub, %while.cond ]
39 %cmp = icmp ugt i32 %size.addr.0, 31
40 %sub = add i32 %size.addr.0, -32
41 br i1 %cmp, label %while.cond, label %while.end
43 while.end: ; preds = %while.cond
44 %size.lcssa = phi i32 [ %size.addr.0, %while.cond ]
48 define void @expandOuterRecurrence(i32 %arg) nounwind #0 {
49 ; CHECK-V8M-LABEL: @expandOuterRecurrence(
50 ; CHECK-V8M-NEXT: entry:
51 ; CHECK-V8M-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
52 ; CHECK-V8M-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
53 ; CHECK-V8M-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
54 ; CHECK-V8M: outer.preheader:
55 ; CHECK-V8M-NEXT: br label [[OUTER:%.*]]
57 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
58 ; CHECK-V8M-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
59 ; CHECK-V8M-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
60 ; CHECK-V8M-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
61 ; CHECK-V8M-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
62 ; CHECK-V8M: inner.ph:
63 ; CHECK-V8M-NEXT: br label [[INNER:%.*]]
65 ; CHECK-V8M-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
66 ; CHECK-V8M: outer.inc.loopexit:
67 ; CHECK-V8M-NEXT: br label [[OUTER_INC]]
68 ; CHECK-V8M: outer.inc:
69 ; CHECK-V8M-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
70 ; CHECK-V8M-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
71 ; CHECK-V8M: exit.loopexit:
72 ; CHECK-V8M-NEXT: br label [[EXIT]]
74 ; CHECK-V8M-NEXT: ret void
76 ; CHECK-V8A-LABEL: @expandOuterRecurrence(
77 ; CHECK-V8A-NEXT: entry:
78 ; CHECK-V8A-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
79 ; CHECK-V8A-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
80 ; CHECK-V8A-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
81 ; CHECK-V8A: outer.preheader:
82 ; CHECK-V8A-NEXT: br label [[OUTER:%.*]]
84 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
85 ; CHECK-V8A-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
86 ; CHECK-V8A-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
87 ; CHECK-V8A-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
88 ; CHECK-V8A-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
89 ; CHECK-V8A: inner.ph:
90 ; CHECK-V8A-NEXT: br label [[INNER:%.*]]
92 ; CHECK-V8A-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
93 ; CHECK-V8A: outer.inc.loopexit:
94 ; CHECK-V8A-NEXT: br label [[OUTER_INC]]
95 ; CHECK-V8A: outer.inc:
96 ; CHECK-V8A-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
97 ; CHECK-V8A-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
98 ; CHECK-V8A: exit.loopexit:
99 ; CHECK-V8A-NEXT: br label [[EXIT]]
101 ; CHECK-V8A-NEXT: ret void
104 %sub1 = sub nsw i32 %arg, 1
105 %cmp1 = icmp slt i32 0, %sub1
106 br i1 %cmp1, label %outer, label %exit
109 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
110 %sub2 = sub nsw i32 %arg, %i
111 %sub3 = sub nsw i32 %sub2, 1
112 %cmp2 = icmp slt i32 0, %sub3
113 br i1 %cmp2, label %inner.ph, label %outer.inc
119 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
120 %j.inc = add nsw i32 %j, 1
121 %cmp3 = icmp slt i32 %j.inc, %sub3
122 br i1 %cmp3, label %inner, label %outer.inc
125 %i.inc = add nsw i32 %i, 1
126 %cmp4 = icmp slt i32 %i.inc, %sub1
127 br i1 %cmp4, label %outer, label %exit
133 define i32 @test1(i32* %array, i32 %length, i32 %n) #0 {
134 ; CHECK-V8M-LABEL: @test1(
135 ; CHECK-V8M-NEXT: loop.preheader:
136 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
137 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
138 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
139 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
140 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
142 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
143 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
144 ; CHECK-V8M-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
146 ; CHECK-V8M-NEXT: call void @prevent_merging()
147 ; CHECK-V8M-NEXT: ret i32 -1
148 ; CHECK-V8M: guarded:
149 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
150 ; CHECK-V8M-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
151 ; CHECK-V8M-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
152 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
153 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
154 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
155 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
157 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
158 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
160 ; CHECK-V8A-LABEL: @test1(
161 ; CHECK-V8A-NEXT: loop.preheader:
162 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
163 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
164 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
165 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
166 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
168 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
169 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
170 ; CHECK-V8A-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
172 ; CHECK-V8A-NEXT: call void @prevent_merging()
173 ; CHECK-V8A-NEXT: ret i32 -1
174 ; CHECK-V8A: guarded:
175 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
176 ; CHECK-V8A-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
177 ; CHECK-V8A-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
178 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
179 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
180 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
181 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
183 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
184 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
186 loop.preheader: ; preds = %entry
189 loop: ; preds = %guarded, %loop.preheader
190 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
191 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
192 %within.bounds = icmp ult i32 %i, %length
193 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
195 deopt: ; preds = %loop
196 call void @prevent_merging()
199 guarded: ; preds = %loop
200 %i.i64 = zext i32 %i to i64
201 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
202 %array.i = load i32, i32* %array.i.ptr, align 4
203 %loop.acc.next = add i32 %loop.acc, %array.i
204 %i.next = add nuw i32 %i, 1
205 %continue = icmp ult i32 %i.next, %n
206 br i1 %continue, label %loop, label %exit
208 exit: ; preds = %guarded, %entry
209 %result = phi i32 [ %loop.acc.next, %guarded ]
213 declare void @maythrow()
215 define i32 @test2(i32* %array, i32 %length, i32 %n) #0 {
216 ; CHECK-V8M-LABEL: @test2(
217 ; CHECK-V8M-NEXT: loop.preheader:
218 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], -1
219 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
220 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
221 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
223 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
224 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
225 ; CHECK-V8M-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
227 ; CHECK-V8M-NEXT: call void @prevent_merging()
228 ; CHECK-V8M-NEXT: ret i32 -1
229 ; CHECK-V8M: guarded:
230 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
231 ; CHECK-V8M-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
232 ; CHECK-V8M-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
233 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
234 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
235 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[N]]
236 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
238 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
239 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
241 ; CHECK-V8A-LABEL: @test2(
242 ; CHECK-V8A-NEXT: loop.preheader:
243 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], -1
244 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
245 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
246 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
248 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
249 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
250 ; CHECK-V8A-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
252 ; CHECK-V8A-NEXT: call void @prevent_merging()
253 ; CHECK-V8A-NEXT: ret i32 -1
254 ; CHECK-V8A: guarded:
255 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
256 ; CHECK-V8A-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
257 ; CHECK-V8A-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
258 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
259 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
260 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[N]]
261 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
263 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
264 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
266 loop.preheader: ; preds = %entry
269 loop: ; preds = %guarded, %loop.preheader
270 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
271 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
272 %within.bounds = icmp ne i32 %i, %length
273 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
275 deopt: ; preds = %loop
276 call void @prevent_merging()
279 guarded: ; preds = %loop
280 %i.i64 = zext i32 %i to i64
281 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
282 %array.i = load i32, i32* %array.i.ptr, align 4
283 %loop.acc.next = add i32 %loop.acc, %array.i
284 %i.next = add nuw i32 %i, 1
285 %continue = icmp ne i32 %i.next, %n
286 br i1 %continue, label %loop, label %exit
288 exit: ; preds = %guarded, %entry
289 %result = phi i32 [ %loop.acc.next, %guarded ]
293 define i32 @two_range_checks(i32* %array.1, i32 %length.1, i32* %array.2, i32 %length.2, i32 %n) #0 {
294 ; CHECK-V8M-LABEL: @two_range_checks(
295 ; CHECK-V8M-NEXT: loop.preheader:
296 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
297 ; CHECK-V8M-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2]], i32 [[LENGTH_1]])
298 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
299 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
300 ; CHECK-V8M-NEXT: [[UMIN2:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN1]], i32 [[TMP0]])
301 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = icmp ne i32 [[UMIN]], [[UMIN2]]
302 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
304 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
305 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
306 ; CHECK-V8M-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
308 ; CHECK-V8M-NEXT: call void @prevent_merging()
309 ; CHECK-V8M-NEXT: ret i32 -1
310 ; CHECK-V8M: guarded:
311 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
312 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
313 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
314 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
315 ; CHECK-V8M-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
316 ; CHECK-V8M-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
317 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
318 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
319 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
320 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
322 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
323 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
325 ; CHECK-V8A-LABEL: @two_range_checks(
326 ; CHECK-V8A-NEXT: loop.preheader:
327 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
328 ; CHECK-V8A-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2]], i32 [[LENGTH_1]])
329 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
330 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
331 ; CHECK-V8A-NEXT: [[UMIN2:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN1]], i32 [[TMP0]])
332 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = icmp ne i32 [[UMIN]], [[UMIN2]]
333 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
335 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
336 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
337 ; CHECK-V8A-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
339 ; CHECK-V8A-NEXT: call void @prevent_merging()
340 ; CHECK-V8A-NEXT: ret i32 -1
341 ; CHECK-V8A: guarded:
342 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
343 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
344 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
345 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
346 ; CHECK-V8A-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
347 ; CHECK-V8A-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
348 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
349 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
350 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
351 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
353 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
354 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
356 loop.preheader: ; preds = %entry
359 loop: ; preds = %guarded, %loop.preheader
360 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
361 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
362 %within.bounds.1 = icmp ult i32 %i, %length.1
363 %within.bounds.2 = icmp ult i32 %i, %length.2
364 %within.bounds = and i1 %within.bounds.1, %within.bounds.2
365 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
367 deopt: ; preds = %loop
368 call void @prevent_merging()
371 guarded: ; preds = %loop
372 %i.i64 = zext i32 %i to i64
373 %array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
374 %array.1.i = load i32, i32* %array.1.i.ptr, align 4
375 %loop.acc.1 = add i32 %loop.acc, %array.1.i
376 %array.2.i.ptr = getelementptr inbounds i32, i32* %array.2, i64 %i.i64
377 %array.2.i = load i32, i32* %array.2.i.ptr, align 4
378 %loop.acc.next = add i32 %loop.acc.1, %array.2.i
379 %i.next = add nuw i32 %i, 1
380 %continue = icmp ult i32 %i.next, %n
381 br i1 %continue, label %loop, label %exit
383 exit: ; preds = %guarded, %entry
384 %result = phi i32 [ %loop.acc.next, %guarded ]
388 define i32 @three_range_checks(i32* %array.1, i32 %length.1, i32* %array.2, i32 %length.2, i32* %array.3, i32 %length.3, i32 %n) #0 {
389 ; CHECK-V8M-LABEL: @three_range_checks(
390 ; CHECK-V8M-NEXT: loop.preheader:
391 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_3:%.*]], i32 [[LENGTH_2:%.*]])
392 ; CHECK-V8M-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[LENGTH_1:%.*]])
393 ; CHECK-V8M-NEXT: [[UMIN2:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_3]], i32 [[LENGTH_2]])
394 ; CHECK-V8M-NEXT: [[UMIN3:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN2]], i32 [[LENGTH_1]])
395 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
396 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
397 ; CHECK-V8M-NEXT: [[UMIN4:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN3]], i32 [[TMP0]])
398 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = icmp ne i32 [[UMIN1]], [[UMIN4]]
399 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
401 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
402 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
403 ; CHECK-V8M-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
405 ; CHECK-V8M-NEXT: call void @prevent_merging()
406 ; CHECK-V8M-NEXT: ret i32 -1
407 ; CHECK-V8M: guarded:
408 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
409 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
410 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
411 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
412 ; CHECK-V8M-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
413 ; CHECK-V8M-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
414 ; CHECK-V8M-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
415 ; CHECK-V8M-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
416 ; CHECK-V8M-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
417 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_2]], [[ARRAY_3_I]]
418 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
419 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
420 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
422 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
423 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
425 ; CHECK-V8A-LABEL: @three_range_checks(
426 ; CHECK-V8A-NEXT: loop.preheader:
427 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_3:%.*]], i32 [[LENGTH_2:%.*]])
428 ; CHECK-V8A-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[LENGTH_1:%.*]])
429 ; CHECK-V8A-NEXT: [[UMIN2:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_3]], i32 [[LENGTH_2]])
430 ; CHECK-V8A-NEXT: [[UMIN3:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN2]], i32 [[LENGTH_1]])
431 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
432 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
433 ; CHECK-V8A-NEXT: [[UMIN4:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN3]], i32 [[TMP0]])
434 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = icmp ne i32 [[UMIN1]], [[UMIN4]]
435 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
437 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
438 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
439 ; CHECK-V8A-NEXT: br i1 [[TMP1]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
441 ; CHECK-V8A-NEXT: call void @prevent_merging()
442 ; CHECK-V8A-NEXT: ret i32 -1
443 ; CHECK-V8A: guarded:
444 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
445 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
446 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
447 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
448 ; CHECK-V8A-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_2:%.*]], i64 [[I_I64]]
449 ; CHECK-V8A-NEXT: [[ARRAY_2_I:%.*]] = load i32, i32* [[ARRAY_2_I_PTR]], align 4
450 ; CHECK-V8A-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
451 ; CHECK-V8A-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
452 ; CHECK-V8A-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
453 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_2]], [[ARRAY_3_I]]
454 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
455 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
456 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
458 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
459 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
461 loop.preheader: ; preds = %entry
464 loop: ; preds = %guarded, %loop.preheader
465 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
466 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
467 %within.bounds.1 = icmp ult i32 %i, %length.1
468 %within.bounds.2 = icmp ult i32 %i, %length.2
469 %within.bounds.3 = icmp ult i32 %i, %length.3
470 %within.bounds.1.and.2 = and i1 %within.bounds.1, %within.bounds.2
471 %within.bounds = and i1 %within.bounds.1.and.2, %within.bounds.3
472 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
474 deopt: ; preds = %loop
475 call void @prevent_merging()
478 guarded: ; preds = %loop
479 %i.i64 = zext i32 %i to i64
480 %array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
481 %array.1.i = load i32, i32* %array.1.i.ptr, align 4
482 %loop.acc.1 = add i32 %loop.acc, %array.1.i
483 %array.2.i.ptr = getelementptr inbounds i32, i32* %array.2, i64 %i.i64
484 %array.2.i = load i32, i32* %array.2.i.ptr, align 4
485 %loop.acc.2 = add i32 %loop.acc.1, %array.2.i
486 %array.3.i.ptr = getelementptr inbounds i32, i32* %array.3, i64 %i.i64
487 %array.3.i = load i32, i32* %array.3.i.ptr, align 4
488 %loop.acc.next = add i32 %loop.acc.2, %array.3.i
489 %i.next = add nuw i32 %i, 1
490 %continue = icmp ult i32 %i.next, %n
491 br i1 %continue, label %loop, label %exit
493 exit: ; preds = %guarded, %entry
494 %result = phi i32 [ %loop.acc.next, %guarded ]
498 ; Analogous to the above, but with two distinct branches (on different conditions)
499 define i32 @distinct_checks(i32* %array.1, i32 %length.1, i32* %array.2, i32 %length.2, i32* %array.3, i32 %length.3, i32 %n) #0 {
500 ; CHECK-V8M-LABEL: @distinct_checks(
501 ; CHECK-V8M-NEXT: loop.preheader:
502 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
503 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
504 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
505 ; CHECK-V8M-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[TMP0]])
506 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH_1]], [[UMIN1]]
507 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH_2]], [[UMIN1]]
508 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
510 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
511 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
512 ; CHECK-V8M-NEXT: br i1 [[TMP1]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
514 ; CHECK-V8M-NEXT: call void @prevent_merging()
515 ; CHECK-V8M-NEXT: ret i32 -1
516 ; CHECK-V8M: guarded:
517 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
518 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
519 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
520 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
521 ; CHECK-V8M-NEXT: br i1 [[TMP2]], label [[GUARDED1]], label [[DEOPT2:%.*]], !prof !0
523 ; CHECK-V8M-NEXT: call void @prevent_merging()
524 ; CHECK-V8M-NEXT: ret i32 -1
525 ; CHECK-V8M: guarded1:
526 ; CHECK-V8M-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
527 ; CHECK-V8M-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
528 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
529 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
530 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
531 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
533 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
534 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
536 ; CHECK-V8A-LABEL: @distinct_checks(
537 ; CHECK-V8A-NEXT: loop.preheader:
538 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
539 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
540 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
541 ; CHECK-V8A-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[TMP0]])
542 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH_1]], [[UMIN1]]
543 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH_2]], [[UMIN1]]
544 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
546 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
547 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
548 ; CHECK-V8A-NEXT: br i1 [[TMP1]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
550 ; CHECK-V8A-NEXT: call void @prevent_merging()
551 ; CHECK-V8A-NEXT: ret i32 -1
552 ; CHECK-V8A: guarded:
553 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
554 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
555 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
556 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
557 ; CHECK-V8A-NEXT: br i1 [[TMP2]], label [[GUARDED1]], label [[DEOPT2:%.*]], !prof !0
559 ; CHECK-V8A-NEXT: call void @prevent_merging()
560 ; CHECK-V8A-NEXT: ret i32 -1
561 ; CHECK-V8A: guarded1:
562 ; CHECK-V8A-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
563 ; CHECK-V8A-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
564 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
565 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
566 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
567 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
569 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
570 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
572 loop.preheader: ; preds = %entry
575 loop: ; preds = %guarded4, %loop.preheader
576 %loop.acc = phi i32 [ %loop.acc.next, %guarded1 ], [ 0, %loop.preheader ]
577 %i = phi i32 [ %i.next, %guarded1 ], [ 0, %loop.preheader ]
578 %within.bounds.1 = icmp ult i32 %i, %length.1
579 br i1 %within.bounds.1, label %guarded, label %deopt, !prof !0
581 deopt: ; preds = %loop
582 call void @prevent_merging()
585 guarded: ; preds = %loop
586 %i.i64 = zext i32 %i to i64
587 %array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
588 %array.1.i = load i32, i32* %array.1.i.ptr, align 4
589 %loop.acc.1 = add i32 %loop.acc, %array.1.i
590 %within.bounds.2 = icmp ult i32 %i, %length.2
591 br i1 %within.bounds.2, label %guarded1, label %deopt2, !prof !0
593 deopt2: ; preds = %guarded
594 call void @prevent_merging()
597 guarded1: ; preds = %guarded1
598 %array.3.i.ptr = getelementptr inbounds i32, i32* %array.3, i64 %i.i64
599 %array.3.i = load i32, i32* %array.3.i.ptr, align 4
600 %loop.acc.next = add i32 %loop.acc.1, %array.3.i
601 %i.next = add nuw i32 %i, 1
602 %continue = icmp ult i32 %i.next, %n
603 br i1 %continue, label %loop, label %exit
606 %result = phi i32 [ %loop.acc.next, %guarded1 ]
610 define i32 @duplicate_checks(i32* %array.1, i32* %array.2, i32* %array.3, i32 %length, i32 %n) #0 {
611 ; CHECK-V8M-LABEL: @duplicate_checks(
612 ; CHECK-V8M-NEXT: loop.preheader:
613 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
614 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
615 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
616 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
617 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
619 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
620 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
621 ; CHECK-V8M-NEXT: br i1 [[TMP1]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
623 ; CHECK-V8M-NEXT: call void @prevent_merging()
624 ; CHECK-V8M-NEXT: ret i32 -1
625 ; CHECK-V8M: guarded:
626 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
627 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
628 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
629 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
630 ; CHECK-V8M-NEXT: br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof !0
632 ; CHECK-V8M-NEXT: call void @prevent_merging()
633 ; CHECK-V8M-NEXT: ret i32 -1
634 ; CHECK-V8M: guarded1:
635 ; CHECK-V8M-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
636 ; CHECK-V8M-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
637 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
638 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
639 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
640 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
642 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
643 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
645 ; CHECK-V8A-LABEL: @duplicate_checks(
646 ; CHECK-V8A-NEXT: loop.preheader:
647 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
648 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
649 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH:%.*]], i32 [[TMP0]])
650 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
651 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
653 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
654 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
655 ; CHECK-V8A-NEXT: br i1 [[TMP1]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
657 ; CHECK-V8A-NEXT: call void @prevent_merging()
658 ; CHECK-V8A-NEXT: ret i32 -1
659 ; CHECK-V8A: guarded:
660 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
661 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_1:%.*]], i64 [[I_I64]]
662 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, i32* [[ARRAY_1_I_PTR]], align 4
663 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
664 ; CHECK-V8A-NEXT: br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof !0
666 ; CHECK-V8A-NEXT: call void @prevent_merging()
667 ; CHECK-V8A-NEXT: ret i32 -1
668 ; CHECK-V8A: guarded1:
669 ; CHECK-V8A-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY_3:%.*]], i64 [[I_I64]]
670 ; CHECK-V8A-NEXT: [[ARRAY_3_I:%.*]] = load i32, i32* [[ARRAY_3_I_PTR]], align 4
671 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
672 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
673 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
674 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
676 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
677 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
679 loop.preheader: ; preds = %entry
682 loop: ; preds = %guarded4, %loop.preheader
683 %loop.acc = phi i32 [ %loop.acc.next, %guarded1 ], [ 0, %loop.preheader ]
684 %i = phi i32 [ %i.next, %guarded1 ], [ 0, %loop.preheader ]
685 %within.bounds.1 = icmp ult i32 %i, %length
686 br i1 %within.bounds.1, label %guarded, label %deopt, !prof !0
688 deopt: ; preds = %loop
689 call void @prevent_merging()
692 guarded: ; preds = %loop
693 %i.i64 = zext i32 %i to i64
694 %array.1.i.ptr = getelementptr inbounds i32, i32* %array.1, i64 %i.i64
695 %array.1.i = load i32, i32* %array.1.i.ptr, align 4
696 %loop.acc.1 = add i32 %loop.acc, %array.1.i
697 %within.bounds.2 = icmp ult i32 %i, %length
698 br i1 %within.bounds.2, label %guarded1, label %deopt2, !prof !0
700 deopt2: ; preds = %guarded
701 call void @prevent_merging()
704 guarded1: ; preds = %guarded1
705 %array.3.i.ptr = getelementptr inbounds i32, i32* %array.3, i64 %i.i64
706 %array.3.i = load i32, i32* %array.3.i.ptr, align 4
707 %loop.acc.next = add i32 %loop.acc.1, %array.3.i
708 %i.next = add nuw i32 %i, 1
709 %continue = icmp ult i32 %i.next, %n
710 br i1 %continue, label %loop, label %exit
713 %result = phi i32 [ %loop.acc.next, %guarded1 ]
717 ; Demonstrate that this approach works with IVs of different steps, and types
718 ; This version uses a manually lftred exit condition to work around an issue described
719 ; in detail on next test.
720 define i32 @different_ivs(i32* %array, i32 %length, i32 %n) #0 {
721 ; CHECK-V8M-LABEL: @different_ivs(
722 ; CHECK-V8M-NEXT: loop.preheader:
723 ; CHECK-V8M-NEXT: [[N64:%.*]] = zext i32 [[N:%.*]] to i64
724 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[N64]], i64 1)
725 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add nsw i64 [[UMAX]], -1
726 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = zext i32 [[LENGTH:%.*]] to i64
727 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP0]], i64 [[TMP1]])
728 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = zext i32 [[LENGTH]] to i64
729 ; CHECK-V8M-NEXT: [[TMP3:%.*]] = icmp ne i64 [[TMP2]], [[UMIN]]
730 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
732 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
733 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
734 ; CHECK-V8M-NEXT: br i1 [[TMP3]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
736 ; CHECK-V8M-NEXT: call void @prevent_merging()
737 ; CHECK-V8M-NEXT: ret i32 -1
738 ; CHECK-V8M: guarded:
739 ; CHECK-V8M-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I]]
740 ; CHECK-V8M-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
741 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
742 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
743 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i64 [[I_NEXT]], [[N64]]
744 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
746 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
747 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
749 ; CHECK-V8A-LABEL: @different_ivs(
750 ; CHECK-V8A-NEXT: loop.preheader:
751 ; CHECK-V8A-NEXT: [[N64:%.*]] = zext i32 [[N:%.*]] to i64
752 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[N64]], i64 1)
753 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add nsw i64 [[UMAX]], -1
754 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = zext i32 [[LENGTH:%.*]] to i64
755 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP0]], i64 [[TMP1]])
756 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = zext i32 [[LENGTH]] to i64
757 ; CHECK-V8A-NEXT: [[TMP3:%.*]] = icmp ne i64 [[TMP2]], [[UMIN]]
758 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
760 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
761 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
762 ; CHECK-V8A-NEXT: br i1 [[TMP3]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
764 ; CHECK-V8A-NEXT: call void @prevent_merging()
765 ; CHECK-V8A-NEXT: ret i32 -1
766 ; CHECK-V8A: guarded:
767 ; CHECK-V8A-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I]]
768 ; CHECK-V8A-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
769 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
770 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
771 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i64 [[I_NEXT]], [[N64]]
772 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
774 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
775 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
778 %j.start = sub nuw nsw i32 %length, 1
779 %n64 = zext i32 %n to i64
783 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
784 %i = phi i64 [ %i.next, %guarded ], [ 0, %loop.preheader ]
785 %j = phi i32 [ %j.next, %guarded ], [ %j.start, %loop.preheader ]
786 %within.bounds = icmp ne i32 %j, -1
787 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
790 call void @prevent_merging()
794 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i
795 %array.i = load i32, i32* %array.i.ptr, align 4
796 %loop.acc.next = add i32 %loop.acc, %array.i
797 %i.next = add nuw i64 %i, 1
798 %j.next = sub nuw i32 %j, 1
799 %continue = icmp ult i64 %i.next, %n64
800 br i1 %continue, label %loop, label %exit
803 %result = phi i32 [ %loop.acc.next, %guarded ]
807 declare void @prevent_merging()
810 !0 = !{!"branch_weights", i32 1048576, i32 1}
811 !1 = !{i32 1, i32 -2147483648}
812 !2 = !{i32 0, i32 50}
814 attributes #0 = { minsize optsize }