1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -mtriple=thumbv8m.main -passes=indvars -S < %s | FileCheck %s --check-prefix=CHECK-V8M
3 ; RUN: opt -mtriple=thumbv8a -passes=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(ptr %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: [[TMP1:%.*]] = freeze i32 [[TMP0]]
139 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[LENGTH:%.*]])
140 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
141 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
143 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
144 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
145 ; CHECK-V8M-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]]
147 ; CHECK-V8M-NEXT: call void @prevent_merging()
148 ; CHECK-V8M-NEXT: ret i32 -1
149 ; CHECK-V8M: guarded:
150 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
151 ; CHECK-V8M-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
152 ; CHECK-V8M-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
153 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
154 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
155 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
156 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
158 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
159 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
161 ; CHECK-V8A-LABEL: @test1(
162 ; CHECK-V8A-NEXT: loop.preheader:
163 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
164 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
165 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
166 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[LENGTH:%.*]])
167 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
168 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
170 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
171 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
172 ; CHECK-V8A-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]]
174 ; CHECK-V8A-NEXT: call void @prevent_merging()
175 ; CHECK-V8A-NEXT: ret i32 -1
176 ; CHECK-V8A: guarded:
177 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
178 ; CHECK-V8A-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
179 ; CHECK-V8A-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
180 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
181 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
182 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
183 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
185 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
186 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
188 loop.preheader: ; preds = %entry
191 loop: ; preds = %guarded, %loop.preheader
192 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
193 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
194 %within.bounds = icmp ult i32 %i, %length
195 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
197 deopt: ; preds = %loop
198 call void @prevent_merging()
201 guarded: ; preds = %loop
202 %i.i64 = zext i32 %i to i64
203 %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
204 %array.i = load i32, ptr %array.i.ptr, align 4
205 %loop.acc.next = add i32 %loop.acc, %array.i
206 %i.next = add nuw i32 %i, 1
207 %continue = icmp ult i32 %i.next, %n
208 br i1 %continue, label %loop, label %exit
210 exit: ; preds = %guarded, %entry
211 %result = phi i32 [ %loop.acc.next, %guarded ]
215 declare void @maythrow()
217 define i32 @test2(ptr %array, i32 %length, i32 %n) #0 {
218 ; CHECK-V8M-LABEL: @test2(
219 ; CHECK-V8M-NEXT: loop.preheader:
220 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], -1
221 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
222 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[LENGTH:%.*]])
223 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
224 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
226 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
227 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
228 ; CHECK-V8M-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
230 ; CHECK-V8M-NEXT: call void @prevent_merging()
231 ; CHECK-V8M-NEXT: ret i32 -1
232 ; CHECK-V8M: guarded:
233 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
234 ; CHECK-V8M-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
235 ; CHECK-V8M-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
236 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
237 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
238 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[N]]
239 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
241 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
242 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
244 ; CHECK-V8A-LABEL: @test2(
245 ; CHECK-V8A-NEXT: loop.preheader:
246 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], -1
247 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
248 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[LENGTH:%.*]])
249 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
250 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
252 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
253 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
254 ; CHECK-V8A-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
256 ; CHECK-V8A-NEXT: call void @prevent_merging()
257 ; CHECK-V8A-NEXT: ret i32 -1
258 ; CHECK-V8A: guarded:
259 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
260 ; CHECK-V8A-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
261 ; CHECK-V8A-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
262 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
263 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
264 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[N]]
265 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
267 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
268 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
270 loop.preheader: ; preds = %entry
273 loop: ; preds = %guarded, %loop.preheader
274 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
275 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
276 %within.bounds = icmp ne i32 %i, %length
277 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
279 deopt: ; preds = %loop
280 call void @prevent_merging()
283 guarded: ; preds = %loop
284 %i.i64 = zext i32 %i to i64
285 %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
286 %array.i = load i32, ptr %array.i.ptr, align 4
287 %loop.acc.next = add i32 %loop.acc, %array.i
288 %i.next = add nuw i32 %i, 1
289 %continue = icmp ne i32 %i.next, %n
290 br i1 %continue, label %loop, label %exit
292 exit: ; preds = %guarded, %entry
293 %result = phi i32 [ %loop.acc.next, %guarded ]
297 define i32 @two_range_checks(ptr %array.1, i32 %length.1, ptr %array.2, i32 %length.2, i32 %n) #0 {
298 ; CHECK-V8M-LABEL: @two_range_checks(
299 ; CHECK-V8M-NEXT: loop.preheader:
300 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
301 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
302 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
303 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
304 ; CHECK-V8M-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[UMIN]])
305 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = icmp ne i32 [[UMIN]], [[UMIN1]]
306 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
308 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
309 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
310 ; CHECK-V8M-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
312 ; CHECK-V8M-NEXT: call void @prevent_merging()
313 ; CHECK-V8M-NEXT: ret i32 -1
314 ; CHECK-V8M: guarded:
315 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
316 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
317 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
318 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
319 ; CHECK-V8M-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
320 ; CHECK-V8M-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
321 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
322 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
323 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
324 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
326 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
327 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
329 ; CHECK-V8A-LABEL: @two_range_checks(
330 ; CHECK-V8A-NEXT: loop.preheader:
331 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_2:%.*]], i32 [[LENGTH_1:%.*]])
332 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
333 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
334 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
335 ; CHECK-V8A-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[UMIN]])
336 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = icmp ne i32 [[UMIN]], [[UMIN1]]
337 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
339 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
340 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
341 ; CHECK-V8A-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
343 ; CHECK-V8A-NEXT: call void @prevent_merging()
344 ; CHECK-V8A-NEXT: ret i32 -1
345 ; CHECK-V8A: guarded:
346 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
347 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
348 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
349 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
350 ; CHECK-V8A-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
351 ; CHECK-V8A-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
352 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
353 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
354 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
355 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
357 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
358 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
360 loop.preheader: ; preds = %entry
363 loop: ; preds = %guarded, %loop.preheader
364 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
365 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
366 %within.bounds.1 = icmp ult i32 %i, %length.1
367 %within.bounds.2 = icmp ult i32 %i, %length.2
368 %within.bounds = and i1 %within.bounds.1, %within.bounds.2
369 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
371 deopt: ; preds = %loop
372 call void @prevent_merging()
375 guarded: ; preds = %loop
376 %i.i64 = zext i32 %i to i64
377 %array.1.i.ptr = getelementptr inbounds i32, ptr %array.1, i64 %i.i64
378 %array.1.i = load i32, ptr %array.1.i.ptr, align 4
379 %loop.acc.1 = add i32 %loop.acc, %array.1.i
380 %array.2.i.ptr = getelementptr inbounds i32, ptr %array.2, i64 %i.i64
381 %array.2.i = load i32, ptr %array.2.i.ptr, align 4
382 %loop.acc.next = add i32 %loop.acc.1, %array.2.i
383 %i.next = add nuw i32 %i, 1
384 %continue = icmp ult i32 %i.next, %n
385 br i1 %continue, label %loop, label %exit
387 exit: ; preds = %guarded, %entry
388 %result = phi i32 [ %loop.acc.next, %guarded ]
392 define i32 @three_range_checks(ptr %array.1, i32 %length.1, ptr %array.2, i32 %length.2, ptr %array.3, i32 %length.3, i32 %n) #0 {
393 ; CHECK-V8M-LABEL: @three_range_checks(
394 ; CHECK-V8M-NEXT: loop.preheader:
395 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_3:%.*]], i32 [[LENGTH_2:%.*]])
396 ; CHECK-V8M-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[LENGTH_1:%.*]])
397 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
398 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
399 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
400 ; CHECK-V8M-NEXT: [[UMIN2:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[UMIN1]])
401 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = icmp ne i32 [[UMIN1]], [[UMIN2]]
402 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
404 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
405 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
406 ; CHECK-V8M-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
408 ; CHECK-V8M-NEXT: call void @prevent_merging()
409 ; CHECK-V8M-NEXT: ret i32 -1
410 ; CHECK-V8M: guarded:
411 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
412 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
413 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
414 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
415 ; CHECK-V8M-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
416 ; CHECK-V8M-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
417 ; CHECK-V8M-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
418 ; CHECK-V8M-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
419 ; CHECK-V8M-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[ARRAY_3_I_PTR]], align 4
420 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_2]], [[ARRAY_3_I]]
421 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
422 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
423 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
425 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
426 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
428 ; CHECK-V8A-LABEL: @three_range_checks(
429 ; CHECK-V8A-NEXT: loop.preheader:
430 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[LENGTH_3:%.*]], i32 [[LENGTH_2:%.*]])
431 ; CHECK-V8A-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[LENGTH_1:%.*]])
432 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
433 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
434 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
435 ; CHECK-V8A-NEXT: [[UMIN2:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[UMIN1]])
436 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = icmp ne i32 [[UMIN1]], [[UMIN2]]
437 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
439 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
440 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
441 ; CHECK-V8A-NEXT: br i1 [[TMP2]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
443 ; CHECK-V8A-NEXT: call void @prevent_merging()
444 ; CHECK-V8A-NEXT: ret i32 -1
445 ; CHECK-V8A: guarded:
446 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
447 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
448 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
449 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
450 ; CHECK-V8A-NEXT: [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
451 ; CHECK-V8A-NEXT: [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
452 ; CHECK-V8A-NEXT: [[LOOP_ACC_2:%.*]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
453 ; CHECK-V8A-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
454 ; CHECK-V8A-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[ARRAY_3_I_PTR]], align 4
455 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_2]], [[ARRAY_3_I]]
456 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
457 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
458 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
460 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
461 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
463 loop.preheader: ; preds = %entry
466 loop: ; preds = %guarded, %loop.preheader
467 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
468 %i = phi i32 [ %i.next, %guarded ], [ 0, %loop.preheader ]
469 %within.bounds.1 = icmp ult i32 %i, %length.1
470 %within.bounds.2 = icmp ult i32 %i, %length.2
471 %within.bounds.3 = icmp ult i32 %i, %length.3
472 %within.bounds.1.and.2 = and i1 %within.bounds.1, %within.bounds.2
473 %within.bounds = and i1 %within.bounds.1.and.2, %within.bounds.3
474 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
476 deopt: ; preds = %loop
477 call void @prevent_merging()
480 guarded: ; preds = %loop
481 %i.i64 = zext i32 %i to i64
482 %array.1.i.ptr = getelementptr inbounds i32, ptr %array.1, i64 %i.i64
483 %array.1.i = load i32, ptr %array.1.i.ptr, align 4
484 %loop.acc.1 = add i32 %loop.acc, %array.1.i
485 %array.2.i.ptr = getelementptr inbounds i32, ptr %array.2, i64 %i.i64
486 %array.2.i = load i32, ptr %array.2.i.ptr, align 4
487 %loop.acc.2 = add i32 %loop.acc.1, %array.2.i
488 %array.3.i.ptr = getelementptr inbounds i32, ptr %array.3, i64 %i.i64
489 %array.3.i = load i32, ptr %array.3.i.ptr, align 4
490 %loop.acc.next = add i32 %loop.acc.2, %array.3.i
491 %i.next = add nuw i32 %i, 1
492 %continue = icmp ult i32 %i.next, %n
493 br i1 %continue, label %loop, label %exit
495 exit: ; preds = %guarded, %entry
496 %result = phi i32 [ %loop.acc.next, %guarded ]
500 ; Analogous to the above, but with two distinct branches (on different conditions)
501 define i32 @distinct_checks(ptr %array.1, i32 %length.1, ptr %array.2, i32 %length.2, ptr %array.3, i32 %length.3, i32 %n) #0 {
502 ; CHECK-V8M-LABEL: @distinct_checks(
503 ; CHECK-V8M-NEXT: loop.preheader:
504 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
505 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
506 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
507 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = freeze i32 [[LENGTH_2:%.*]]
508 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[TMP2]])
509 ; CHECK-V8M-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[LENGTH_1:%.*]])
510 ; CHECK-V8M-NEXT: [[TMP3:%.*]] = icmp ne i32 [[LENGTH_1]], [[UMIN1]]
511 ; CHECK-V8M-NEXT: [[TMP4:%.*]] = icmp ne i32 [[LENGTH_2]], [[UMIN1]]
512 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
514 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
515 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
516 ; CHECK-V8M-NEXT: br i1 [[TMP3]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
518 ; CHECK-V8M-NEXT: call void @prevent_merging()
519 ; CHECK-V8M-NEXT: ret i32 -1
520 ; CHECK-V8M: guarded:
521 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
522 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
523 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
524 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
525 ; CHECK-V8M-NEXT: br i1 [[TMP4]], label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
527 ; CHECK-V8M-NEXT: call void @prevent_merging()
528 ; CHECK-V8M-NEXT: ret i32 -1
529 ; CHECK-V8M: guarded1:
530 ; CHECK-V8M-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
531 ; CHECK-V8M-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[ARRAY_3_I_PTR]], align 4
532 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
533 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
534 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
535 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
537 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
538 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
540 ; CHECK-V8A-LABEL: @distinct_checks(
541 ; CHECK-V8A-NEXT: loop.preheader:
542 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
543 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
544 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
545 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = freeze i32 [[LENGTH_2:%.*]]
546 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[TMP2]])
547 ; CHECK-V8A-NEXT: [[UMIN1:%.*]] = call i32 @llvm.umin.i32(i32 [[UMIN]], i32 [[LENGTH_1:%.*]])
548 ; CHECK-V8A-NEXT: [[TMP3:%.*]] = icmp ne i32 [[LENGTH_1]], [[UMIN1]]
549 ; CHECK-V8A-NEXT: [[TMP4:%.*]] = icmp ne i32 [[LENGTH_2]], [[UMIN1]]
550 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
552 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
553 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
554 ; CHECK-V8A-NEXT: br i1 [[TMP3]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
556 ; CHECK-V8A-NEXT: call void @prevent_merging()
557 ; CHECK-V8A-NEXT: ret i32 -1
558 ; CHECK-V8A: guarded:
559 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
560 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
561 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
562 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
563 ; CHECK-V8A-NEXT: br i1 [[TMP4]], label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
565 ; CHECK-V8A-NEXT: call void @prevent_merging()
566 ; CHECK-V8A-NEXT: ret i32 -1
567 ; CHECK-V8A: guarded1:
568 ; CHECK-V8A-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
569 ; CHECK-V8A-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[ARRAY_3_I_PTR]], align 4
570 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
571 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
572 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
573 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
575 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
576 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
578 loop.preheader: ; preds = %entry
581 loop: ; preds = %guarded4, %loop.preheader
582 %loop.acc = phi i32 [ %loop.acc.next, %guarded1 ], [ 0, %loop.preheader ]
583 %i = phi i32 [ %i.next, %guarded1 ], [ 0, %loop.preheader ]
584 %within.bounds.1 = icmp ult i32 %i, %length.1
585 br i1 %within.bounds.1, label %guarded, label %deopt, !prof !0
587 deopt: ; preds = %loop
588 call void @prevent_merging()
591 guarded: ; preds = %loop
592 %i.i64 = zext i32 %i to i64
593 %array.1.i.ptr = getelementptr inbounds i32, ptr %array.1, i64 %i.i64
594 %array.1.i = load i32, ptr %array.1.i.ptr, align 4
595 %loop.acc.1 = add i32 %loop.acc, %array.1.i
596 %within.bounds.2 = icmp ult i32 %i, %length.2
597 br i1 %within.bounds.2, label %guarded1, label %deopt2, !prof !0
599 deopt2: ; preds = %guarded
600 call void @prevent_merging()
603 guarded1: ; preds = %guarded1
604 %array.3.i.ptr = getelementptr inbounds i32, ptr %array.3, i64 %i.i64
605 %array.3.i = load i32, ptr %array.3.i.ptr, align 4
606 %loop.acc.next = add i32 %loop.acc.1, %array.3.i
607 %i.next = add nuw i32 %i, 1
608 %continue = icmp ult i32 %i.next, %n
609 br i1 %continue, label %loop, label %exit
612 %result = phi i32 [ %loop.acc.next, %guarded1 ]
616 define i32 @duplicate_checks(ptr %array.1, ptr %array.2, ptr %array.3, i32 %length, i32 %n) #0 {
617 ; CHECK-V8M-LABEL: @duplicate_checks(
618 ; CHECK-V8M-NEXT: loop.preheader:
619 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
620 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
621 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
622 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[LENGTH:%.*]])
623 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
624 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
626 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
627 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
628 ; CHECK-V8M-NEXT: br i1 [[TMP2]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
630 ; CHECK-V8M-NEXT: call void @prevent_merging()
631 ; CHECK-V8M-NEXT: ret i32 -1
632 ; CHECK-V8M: guarded:
633 ; CHECK-V8M-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
634 ; CHECK-V8M-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
635 ; CHECK-V8M-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
636 ; CHECK-V8M-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
637 ; CHECK-V8M-NEXT: br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
639 ; CHECK-V8M-NEXT: call void @prevent_merging()
640 ; CHECK-V8M-NEXT: ret i32 -1
641 ; CHECK-V8M: guarded1:
642 ; CHECK-V8M-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
643 ; CHECK-V8M-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[ARRAY_3_I_PTR]], align 4
644 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
645 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
646 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
647 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
649 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
650 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
652 ; CHECK-V8A-LABEL: @duplicate_checks(
653 ; CHECK-V8A-NEXT: loop.preheader:
654 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[N:%.*]], i32 1)
655 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add i32 [[UMAX]], -1
656 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i32 [[TMP0]]
657 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 [[LENGTH:%.*]])
658 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = icmp ne i32 [[LENGTH]], [[UMIN]]
659 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
661 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED1:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
662 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[GUARDED1]] ], [ 0, [[LOOP_PREHEADER]] ]
663 ; CHECK-V8A-NEXT: br i1 [[TMP2]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
665 ; CHECK-V8A-NEXT: call void @prevent_merging()
666 ; CHECK-V8A-NEXT: ret i32 -1
667 ; CHECK-V8A: guarded:
668 ; CHECK-V8A-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
669 ; CHECK-V8A-NEXT: [[ARRAY_1_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_1:%.*]], i64 [[I_I64]]
670 ; CHECK-V8A-NEXT: [[ARRAY_1_I:%.*]] = load i32, ptr [[ARRAY_1_I_PTR]], align 4
671 ; CHECK-V8A-NEXT: [[LOOP_ACC_1:%.*]] = add i32 [[LOOP_ACC]], [[ARRAY_1_I]]
672 ; CHECK-V8A-NEXT: br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
674 ; CHECK-V8A-NEXT: call void @prevent_merging()
675 ; CHECK-V8A-NEXT: ret i32 -1
676 ; CHECK-V8A: guarded1:
677 ; CHECK-V8A-NEXT: [[ARRAY_3_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_3:%.*]], i64 [[I_I64]]
678 ; CHECK-V8A-NEXT: [[ARRAY_3_I:%.*]] = load i32, ptr [[ARRAY_3_I_PTR]], align 4
679 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_3_I]]
680 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
681 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
682 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
684 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
685 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
687 loop.preheader: ; preds = %entry
690 loop: ; preds = %guarded4, %loop.preheader
691 %loop.acc = phi i32 [ %loop.acc.next, %guarded1 ], [ 0, %loop.preheader ]
692 %i = phi i32 [ %i.next, %guarded1 ], [ 0, %loop.preheader ]
693 %within.bounds.1 = icmp ult i32 %i, %length
694 br i1 %within.bounds.1, label %guarded, label %deopt, !prof !0
696 deopt: ; preds = %loop
697 call void @prevent_merging()
700 guarded: ; preds = %loop
701 %i.i64 = zext i32 %i to i64
702 %array.1.i.ptr = getelementptr inbounds i32, ptr %array.1, i64 %i.i64
703 %array.1.i = load i32, ptr %array.1.i.ptr, align 4
704 %loop.acc.1 = add i32 %loop.acc, %array.1.i
705 %within.bounds.2 = icmp ult i32 %i, %length
706 br i1 %within.bounds.2, label %guarded1, label %deopt2, !prof !0
708 deopt2: ; preds = %guarded
709 call void @prevent_merging()
712 guarded1: ; preds = %guarded1
713 %array.3.i.ptr = getelementptr inbounds i32, ptr %array.3, i64 %i.i64
714 %array.3.i = load i32, ptr %array.3.i.ptr, align 4
715 %loop.acc.next = add i32 %loop.acc.1, %array.3.i
716 %i.next = add nuw i32 %i, 1
717 %continue = icmp ult i32 %i.next, %n
718 br i1 %continue, label %loop, label %exit
721 %result = phi i32 [ %loop.acc.next, %guarded1 ]
725 ; Demonstrate that this approach works with IVs of different steps, and types
726 ; This version uses a manually lftred exit condition to work around an issue described
727 ; in detail on next test.
728 define i32 @different_ivs(ptr %array, i32 %length, i32 %n) #0 {
729 ; CHECK-V8M-LABEL: @different_ivs(
730 ; CHECK-V8M-NEXT: loop.preheader:
731 ; CHECK-V8M-NEXT: [[N64:%.*]] = zext i32 [[N:%.*]] to i64
732 ; CHECK-V8M-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[N64]], i64 1)
733 ; CHECK-V8M-NEXT: [[TMP0:%.*]] = add nsw i64 [[UMAX]], -1
734 ; CHECK-V8M-NEXT: [[TMP1:%.*]] = freeze i64 [[TMP0]]
735 ; CHECK-V8M-NEXT: [[TMP2:%.*]] = zext i32 [[LENGTH:%.*]] to i64
736 ; CHECK-V8M-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP1]], i64 [[TMP2]])
737 ; CHECK-V8M-NEXT: [[TMP3:%.*]] = zext i32 [[LENGTH]] to i64
738 ; CHECK-V8M-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], [[UMIN]]
739 ; CHECK-V8M-NEXT: br label [[LOOP:%.*]]
741 ; CHECK-V8M-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
742 ; CHECK-V8M-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
743 ; CHECK-V8M-NEXT: br i1 [[TMP4]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
745 ; CHECK-V8M-NEXT: call void @prevent_merging()
746 ; CHECK-V8M-NEXT: ret i32 -1
747 ; CHECK-V8M: guarded:
748 ; CHECK-V8M-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I]]
749 ; CHECK-V8M-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
750 ; CHECK-V8M-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
751 ; CHECK-V8M-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
752 ; CHECK-V8M-NEXT: [[CONTINUE:%.*]] = icmp ult i64 [[I_NEXT]], [[N64]]
753 ; CHECK-V8M-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
755 ; CHECK-V8M-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
756 ; CHECK-V8M-NEXT: ret i32 [[RESULT]]
758 ; CHECK-V8A-LABEL: @different_ivs(
759 ; CHECK-V8A-NEXT: loop.preheader:
760 ; CHECK-V8A-NEXT: [[N64:%.*]] = zext i32 [[N:%.*]] to i64
761 ; CHECK-V8A-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[N64]], i64 1)
762 ; CHECK-V8A-NEXT: [[TMP0:%.*]] = add nsw i64 [[UMAX]], -1
763 ; CHECK-V8A-NEXT: [[TMP1:%.*]] = freeze i64 [[TMP0]]
764 ; CHECK-V8A-NEXT: [[TMP2:%.*]] = zext i32 [[LENGTH:%.*]] to i64
765 ; CHECK-V8A-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP1]], i64 [[TMP2]])
766 ; CHECK-V8A-NEXT: [[TMP3:%.*]] = zext i32 [[LENGTH]] to i64
767 ; CHECK-V8A-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], [[UMIN]]
768 ; CHECK-V8A-NEXT: br label [[LOOP:%.*]]
770 ; CHECK-V8A-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[GUARDED:%.*]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
771 ; CHECK-V8A-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[GUARDED]] ], [ 0, [[LOOP_PREHEADER]] ]
772 ; CHECK-V8A-NEXT: br i1 [[TMP4]], label [[GUARDED]], label [[DEOPT:%.*]], !prof [[PROF0]]
774 ; CHECK-V8A-NEXT: call void @prevent_merging()
775 ; CHECK-V8A-NEXT: ret i32 -1
776 ; CHECK-V8A: guarded:
777 ; CHECK-V8A-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I]]
778 ; CHECK-V8A-NEXT: [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
779 ; CHECK-V8A-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
780 ; CHECK-V8A-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
781 ; CHECK-V8A-NEXT: [[CONTINUE:%.*]] = icmp ult i64 [[I_NEXT]], [[N64]]
782 ; CHECK-V8A-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
784 ; CHECK-V8A-NEXT: [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
785 ; CHECK-V8A-NEXT: ret i32 [[RESULT]]
788 %j.start = sub nuw nsw i32 %length, 1
789 %n64 = zext i32 %n to i64
793 %loop.acc = phi i32 [ %loop.acc.next, %guarded ], [ 0, %loop.preheader ]
794 %i = phi i64 [ %i.next, %guarded ], [ 0, %loop.preheader ]
795 %j = phi i32 [ %j.next, %guarded ], [ %j.start, %loop.preheader ]
796 %within.bounds = icmp ne i32 %j, -1
797 br i1 %within.bounds, label %guarded, label %deopt, !prof !0
800 call void @prevent_merging()
804 %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i
805 %array.i = load i32, ptr %array.i.ptr, align 4
806 %loop.acc.next = add i32 %loop.acc, %array.i
807 %i.next = add nuw i64 %i, 1
808 %j.next = sub nuw i32 %j, 1
809 %continue = icmp ult i64 %i.next, %n64
810 br i1 %continue, label %loop, label %exit
813 %result = phi i32 [ %loop.acc.next, %guarded ]
817 declare void @prevent_merging()
820 !0 = !{!"branch_weights", i32 1048576, i32 1}
821 !1 = !{i32 1, i32 -2147483648}
822 !2 = !{i32 0, i32 50}
824 attributes #0 = { minsize optsize }