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
4
5define 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]]
19;
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]]
33;
34entry:
35  br label %while.cond
36
37while.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
42
43while.end:                                        ; preds = %while.cond
44  %size.lcssa = phi i32 [ %size.addr.0, %while.cond ]
45  ret i32 %size.lcssa
46}
47
48define 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
75;
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
102;
103entry:
104  %sub1 = sub nsw i32 %arg, 1
105  %cmp1 = icmp slt i32 0, %sub1
106  br i1 %cmp1, label %outer, label %exit
107
108outer:
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
114
115inner.ph:
116  br label %inner
117
118inner:
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
123
124outer.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
128
129exit:
130  ret void
131}
132
133define 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]]
159;
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]]
185;
186loop.preheader:                                   ; preds = %entry
187  br label %loop
188
189loop:                                             ; 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
194
195deopt:                                            ; preds = %loop
196  call void @prevent_merging()
197  ret i32 -1
198
199guarded:                                          ; 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
207
208exit:                                             ; preds = %guarded, %entry
209  %result = phi i32 [ %loop.acc.next, %guarded ]
210  ret i32 %result
211}
212
213declare void @maythrow()
214
215define 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]]
240;
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]]
265;
266loop.preheader:                                   ; preds = %entry
267  br label %loop
268
269loop:                                             ; 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
274
275deopt:                                            ; preds = %loop
276  call void @prevent_merging()
277  ret i32 -1
278
279guarded:                                          ; 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
287
288exit:                                             ; preds = %guarded, %entry
289  %result = phi i32 [ %loop.acc.next, %guarded ]
290  ret i32 %result
291}
292
293define 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]]
324;
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]]
355;
356loop.preheader:                                   ; preds = %entry
357  br label %loop
358
359loop:                                             ; 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
366
367deopt:                                            ; preds = %loop
368  call void @prevent_merging()
369  ret i32 -1
370
371guarded:                                          ; 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
382
383exit:                                             ; preds = %guarded, %entry
384  %result = phi i32 [ %loop.acc.next, %guarded ]
385  ret i32 %result
386}
387
388define 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]]
424;
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]]
460;
461loop.preheader:                                   ; preds = %entry
462  br label %loop
463
464loop:                                             ; 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
473
474deopt:                                            ; preds = %loop
475  call void @prevent_merging()
476  ret i32 -1
477
478guarded:                                          ; 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
492
493exit:                                             ; preds = %guarded, %entry
494  %result = phi i32 [ %loop.acc.next, %guarded ]
495  ret i32 %result
496}
497
498; Analogous to the above, but with two distinct branches (on different conditions)
499define 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]]
535;
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]]
571;
572loop.preheader:                                   ; preds = %entry
573  br label %loop
574
575loop:                                             ; 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
580
581deopt:                                            ; preds = %loop
582  call void @prevent_merging()
583  ret i32 -1
584
585guarded:                                          ; 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
592
593deopt2:                                           ; preds = %guarded
594  call void @prevent_merging()
595  ret i32 -1
596
597guarded1:                                         ; 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
604
605exit:
606  %result = phi i32 [ %loop.acc.next, %guarded1 ]
607  ret i32 %result
608}
609
610define 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]]
644;
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]]
678;
679loop.preheader:                                   ; preds = %entry
680  br label %loop
681
682loop:                                             ; 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
687
688deopt:                                            ; preds = %loop
689  call void @prevent_merging()
690  ret i32 -1
691
692guarded:                                          ; 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
699
700deopt2:                                           ; preds = %guarded
701  call void @prevent_merging()
702  ret i32 -1
703
704guarded1:                                         ; 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
711
712exit:
713  %result = phi i32 [ %loop.acc.next, %guarded1 ]
714  ret i32 %result
715}
716
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.
720define 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]]
748;
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]]
776;
777loop.preheader:
778  %j.start = sub nuw nsw i32 %length, 1
779  %n64 = zext i32 %n to i64
780  br label %loop
781
782loop:
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
788
789deopt:
790  call void @prevent_merging()
791  ret i32 -1
792
793guarded:
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
801
802exit:
803  %result = phi i32 [ %loop.acc.next, %guarded ]
804  ret i32 %result
805}
806
807declare void @prevent_merging()
808declare void @call()
809
810!0 = !{!"branch_weights", i32 1048576, i32 1}
811!1 = !{i32 1, i32 -2147483648}
812!2 = !{i32 0, i32 50}
813
814attributes #0 = { minsize optsize }
815