[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / IndVarSimplify / ARM / code-size.ll
blob0d79d325276e770a9fa6236372b6f0b1cedb05f1
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]]
34 entry:
35   br label %while.cond
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 ]
45   ret i32 %size.lcssa
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:%.*]]
56 ; CHECK-V8M:       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:%.*]]
64 ; CHECK-V8M:       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]]
73 ; CHECK-V8M:       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:%.*]]
83 ; CHECK-V8A:       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:%.*]]
91 ; CHECK-V8A:       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]]
100 ; CHECK-V8A:       exit:
101 ; CHECK-V8A-NEXT:    ret void
103 entry:
104   %sub1 = sub nsw i32 %arg, 1
105   %cmp1 = icmp slt i32 0, %sub1
106   br i1 %cmp1, label %outer, label %exit
108 outer:
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
115 inner.ph:
116   br label %inner
118 inner:
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
124 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
129 exit:
130   ret void
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:%.*]]
141 ; CHECK-V8M:       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
145 ; CHECK-V8M:       deopt:
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:%.*]]
156 ; CHECK-V8M:       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:%.*]]
167 ; CHECK-V8A:       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
171 ; CHECK-V8A:       deopt:
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:%.*]]
182 ; CHECK-V8A:       exit:
183 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
184 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
186 loop.preheader:                                   ; preds = %entry
187   br label %loop
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()
197   ret i32 -1
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 ]
210   ret i32 %result
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:%.*]]
222 ; CHECK-V8M:       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
226 ; CHECK-V8M:       deopt:
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:%.*]]
237 ; CHECK-V8M:       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:%.*]]
247 ; CHECK-V8A:       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
251 ; CHECK-V8A:       deopt:
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:%.*]]
262 ; CHECK-V8A:       exit:
263 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
264 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
266 loop.preheader:                                   ; preds = %entry
267   br label %loop
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()
277   ret i32 -1
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 ]
290   ret i32 %result
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:%.*]]
303 ; CHECK-V8M:       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
307 ; CHECK-V8M:       deopt:
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:%.*]]
321 ; CHECK-V8M:       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:%.*]]
334 ; CHECK-V8A:       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
338 ; CHECK-V8A:       deopt:
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:%.*]]
352 ; CHECK-V8A:       exit:
353 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
354 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
356 loop.preheader:                                   ; preds = %entry
357   br label %loop
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()
369   ret i32 -1
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 ]
385   ret i32 %result
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:%.*]]
400 ; CHECK-V8M:       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
404 ; CHECK-V8M:       deopt:
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:%.*]]
421 ; CHECK-V8M:       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:%.*]]
436 ; CHECK-V8A:       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
440 ; CHECK-V8A:       deopt:
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:%.*]]
457 ; CHECK-V8A:       exit:
458 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
459 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
461 loop.preheader:                                   ; preds = %entry
462   br label %loop
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()
476   ret i32 -1
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 ]
495   ret i32 %result
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:%.*]]
509 ; CHECK-V8M:       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
513 ; CHECK-V8M:       deopt:
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
522 ; CHECK-V8M:       deopt2:
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:%.*]]
532 ; CHECK-V8M:       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:%.*]]
545 ; CHECK-V8A:       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
549 ; CHECK-V8A:       deopt:
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
558 ; CHECK-V8A:       deopt2:
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:%.*]]
568 ; CHECK-V8A:       exit:
569 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
570 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
572 loop.preheader:                                   ; preds = %entry
573   br label %loop
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()
583   ret i32 -1
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()
595   ret i32 -1
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
605 exit:
606   %result = phi i32 [ %loop.acc.next, %guarded1 ]
607   ret i32 %result
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:%.*]]
618 ; CHECK-V8M:       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
622 ; CHECK-V8M:       deopt:
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
631 ; CHECK-V8M:       deopt2:
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:%.*]]
641 ; CHECK-V8M:       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:%.*]]
652 ; CHECK-V8A:       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
656 ; CHECK-V8A:       deopt:
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
665 ; CHECK-V8A:       deopt2:
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:%.*]]
675 ; CHECK-V8A:       exit:
676 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED1]] ]
677 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
679 loop.preheader:                                   ; preds = %entry
680   br label %loop
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()
690   ret i32 -1
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()
702   ret i32 -1
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
712 exit:
713   %result = phi i32 [ %loop.acc.next, %guarded1 ]
714   ret i32 %result
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:%.*]]
731 ; CHECK-V8M:       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
735 ; CHECK-V8M:       deopt:
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:%.*]]
745 ; CHECK-V8M:       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:%.*]]
759 ; CHECK-V8A:       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
763 ; CHECK-V8A:       deopt:
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:%.*]]
773 ; CHECK-V8A:       exit:
774 ; CHECK-V8A-NEXT:    [[RESULT:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[GUARDED]] ]
775 ; CHECK-V8A-NEXT:    ret i32 [[RESULT]]
777 loop.preheader:
778   %j.start = sub nuw nsw i32 %length, 1
779   %n64 = zext i32 %n to i64
780   br label %loop
782 loop:
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
789 deopt:
790   call void @prevent_merging()
791   ret i32 -1
793 guarded:
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
802 exit:
803   %result = phi i32 [ %loop.acc.next, %guarded ]
804   ret i32 %result
807 declare void @prevent_merging()
808 declare void @call()
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 }