1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -loop-vectorize -force-vector-width=2 < %s | FileCheck %s
3target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
4
5define void @bottom_tested(i16* %p, i32 %n) {
6; CHECK-LABEL: @bottom_tested(
7; CHECK-NEXT:  entry:
8; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[N:%.*]], 0
9; CHECK-NEXT:    [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 0
10; CHECK-NEXT:    [[TMP1:%.*]] = add nuw i32 [[SMAX]], 1
11; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[TMP1]], 2
12; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
13; CHECK:       vector.ph:
14; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i32 [[TMP1]], 2
15; CHECK-NEXT:    [[N_VEC:%.*]] = sub i32 [[TMP1]], [[N_MOD_VF]]
16; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
17; CHECK:       vector.body:
18; CHECK-NEXT:    [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
19; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[INDEX]], 0
20; CHECK-NEXT:    [[TMP3:%.*]] = sext i32 [[TMP2]] to i64
21; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[TMP3]]
22; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i16, i16* [[TMP4]], i32 0
23; CHECK-NEXT:    [[TMP6:%.*]] = bitcast i16* [[TMP5]] to <2 x i16>*
24; CHECK-NEXT:    store <2 x i16> zeroinitializer, <2 x i16>* [[TMP6]], align 4
25; CHECK-NEXT:    [[INDEX_NEXT]] = add i32 [[INDEX]], 2
26; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]]
27; CHECK-NEXT:    br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], [[LOOP0:!llvm.loop !.*]]
28; CHECK:       middle.block:
29; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i32 [[TMP1]], [[N_VEC]]
30; CHECK-NEXT:    br i1 [[CMP_N]], label [[IF_END:%.*]], label [[SCALAR_PH]]
31; CHECK:       scalar.ph:
32; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i32 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ]
33; CHECK-NEXT:    br label [[FOR_COND:%.*]]
34; CHECK:       for.cond:
35; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ], [ [[INC:%.*]], [[FOR_COND]] ]
36; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
37; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P]], i64 [[IPROM]]
38; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
39; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
40; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I]], [[N]]
41; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_COND]], label [[IF_END]], [[LOOP2:!llvm.loop !.*]]
42; CHECK:       if.end:
43; CHECK-NEXT:    ret void
44;
45entry:
46  br label %for.cond
47
48for.cond:
49  %i = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
50  %iprom = sext i32 %i to i64
51  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
52  store i16 0, i16* %b, align 4
53  %inc = add nsw i32 %i, 1
54  %cmp = icmp slt i32 %i, %n
55  br i1 %cmp, label %for.cond, label %if.end
56
57if.end:
58  ret void
59}
60
61define void @early_exit(i16* %p, i32 %n) {
62; CHECK-LABEL: @early_exit(
63; CHECK-NEXT:  entry:
64; CHECK-NEXT:    br label [[FOR_COND:%.*]]
65; CHECK:       for.cond:
66; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
67; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I]], [[N:%.*]]
68; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]
69; CHECK:       for.body:
70; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
71; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
72; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
73; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
74; CHECK-NEXT:    br label [[FOR_COND]]
75; CHECK:       if.end:
76; CHECK-NEXT:    ret void
77;
78entry:
79  br label %for.cond
80
81for.cond:
82  %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
83  %cmp = icmp slt i32 %i, %n
84  br i1 %cmp, label %for.body, label %if.end
85
86for.body:
87  %iprom = sext i32 %i to i64
88  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
89  store i16 0, i16* %b, align 4
90  %inc = add nsw i32 %i, 1
91  br label %for.cond
92
93if.end:
94  ret void
95}
96
97
98; multiple exit - no values inside the loop used outside
99define void @multiple_unique_exit(i16* %p, i32 %n) {
100; CHECK-LABEL: @multiple_unique_exit(
101; CHECK-NEXT:  entry:
102; CHECK-NEXT:    br label [[FOR_COND:%.*]]
103; CHECK:       for.cond:
104; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
105; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I]], [[N:%.*]]
106; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]
107; CHECK:       for.body:
108; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
109; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
110; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
111; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
112; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[I]], 2096
113; CHECK-NEXT:    br i1 [[CMP2]], label [[FOR_COND]], label [[IF_END]]
114; CHECK:       if.end:
115; CHECK-NEXT:    ret void
116;
117entry:
118  br label %for.cond
119
120for.cond:
121  %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
122  %cmp = icmp slt i32 %i, %n
123  br i1 %cmp, label %for.body, label %if.end
124
125for.body:
126  %iprom = sext i32 %i to i64
127  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
128  store i16 0, i16* %b, align 4
129  %inc = add nsw i32 %i, 1
130  %cmp2 = icmp slt i32 %i, 2096
131  br i1 %cmp2, label %for.cond, label %if.end
132
133if.end:
134  ret void
135}
136
137; multiple exit - with an lcssa phi
138define i32 @multiple_unique_exit2(i16* %p, i32 %n) {
139; CHECK-LABEL: @multiple_unique_exit2(
140; CHECK-NEXT:  entry:
141; CHECK-NEXT:    br label [[FOR_COND:%.*]]
142; CHECK:       for.cond:
143; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
144; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I]], [[N:%.*]]
145; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]
146; CHECK:       for.body:
147; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
148; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
149; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
150; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
151; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[I]], 2096
152; CHECK-NEXT:    br i1 [[CMP2]], label [[FOR_COND]], label [[IF_END]]
153; CHECK:       if.end:
154; CHECK-NEXT:    [[I_LCSSA:%.*]] = phi i32 [ [[I]], [[FOR_BODY]] ], [ [[I]], [[FOR_COND]] ]
155; CHECK-NEXT:    ret i32 [[I_LCSSA]]
156;
157entry:
158  br label %for.cond
159
160for.cond:
161  %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
162  %cmp = icmp slt i32 %i, %n
163  br i1 %cmp, label %for.body, label %if.end
164
165for.body:
166  %iprom = sext i32 %i to i64
167  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
168  store i16 0, i16* %b, align 4
169  %inc = add nsw i32 %i, 1
170  %cmp2 = icmp slt i32 %i, 2096
171  br i1 %cmp2, label %for.cond, label %if.end
172
173if.end:
174  ret i32 %i
175}
176
177; multiple exit w/a non lcssa phi
178define i32 @multiple_unique_exit3(i16* %p, i32 %n) {
179; CHECK-LABEL: @multiple_unique_exit3(
180; CHECK-NEXT:  entry:
181; CHECK-NEXT:    br label [[FOR_COND:%.*]]
182; CHECK:       for.cond:
183; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
184; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I]], [[N:%.*]]
185; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]
186; CHECK:       for.body:
187; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
188; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
189; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
190; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
191; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[I]], 2096
192; CHECK-NEXT:    br i1 [[CMP2]], label [[FOR_COND]], label [[IF_END]]
193; CHECK:       if.end:
194; CHECK-NEXT:    [[EXIT:%.*]] = phi i32 [ 0, [[FOR_COND]] ], [ 1, [[FOR_BODY]] ]
195; CHECK-NEXT:    ret i32 [[EXIT]]
196;
197entry:
198  br label %for.cond
199
200for.cond:
201  %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
202  %cmp = icmp slt i32 %i, %n
203  br i1 %cmp, label %for.body, label %if.end
204
205for.body:
206  %iprom = sext i32 %i to i64
207  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
208  store i16 0, i16* %b, align 4
209  %inc = add nsw i32 %i, 1
210  %cmp2 = icmp slt i32 %i, 2096
211  br i1 %cmp2, label %for.cond, label %if.end
212
213if.end:
214  %exit = phi i32 [0, %for.cond], [1, %for.body]
215  ret i32 %exit
216}
217
218; multiple exits w/distinct target blocks
219define i32 @multiple_exit_blocks(i16* %p, i32 %n) {
220; CHECK-LABEL: @multiple_exit_blocks(
221; CHECK-NEXT:  entry:
222; CHECK-NEXT:    br label [[FOR_COND:%.*]]
223; CHECK:       for.cond:
224; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
225; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I]], [[N:%.*]]
226; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]
227; CHECK:       for.body:
228; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
229; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
230; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
231; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
232; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[I]], 2096
233; CHECK-NEXT:    br i1 [[CMP2]], label [[FOR_COND]], label [[IF_END2:%.*]]
234; CHECK:       if.end:
235; CHECK-NEXT:    ret i32 0
236; CHECK:       if.end2:
237; CHECK-NEXT:    ret i32 1
238;
239entry:
240  br label %for.cond
241
242for.cond:
243  %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
244  %cmp = icmp slt i32 %i, %n
245  br i1 %cmp, label %for.body, label %if.end
246
247for.body:
248  %iprom = sext i32 %i to i64
249  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
250  store i16 0, i16* %b, align 4
251  %inc = add nsw i32 %i, 1
252  %cmp2 = icmp slt i32 %i, 2096
253  br i1 %cmp2, label %for.cond, label %if.end2
254
255if.end:
256  ret i32 0
257
258if.end2:
259  ret i32 1
260}
261
262; unique exit case but with a switch as two edges between the same pair of
263; blocks is an often missed edge case
264define i32 @multiple_exit_switch(i16* %p, i32 %n) {
265; CHECK-LABEL: @multiple_exit_switch(
266; CHECK-NEXT:  entry:
267; CHECK-NEXT:    br label [[FOR_COND:%.*]]
268; CHECK:       for.cond:
269; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND]] ]
270; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
271; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
272; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
273; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
274; CHECK-NEXT:    switch i32 [[I]], label [[FOR_COND]] [
275; CHECK-NEXT:    i32 2096, label [[IF_END:%.*]]
276; CHECK-NEXT:    i32 2097, label [[IF_END]]
277; CHECK-NEXT:    ]
278; CHECK:       if.end:
279; CHECK-NEXT:    [[I_LCSSA:%.*]] = phi i32 [ [[I]], [[FOR_COND]] ], [ [[I]], [[FOR_COND]] ]
280; CHECK-NEXT:    ret i32 [[I_LCSSA]]
281;
282entry:
283  br label %for.cond
284
285for.cond:
286  %i = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
287  %iprom = sext i32 %i to i64
288  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
289  store i16 0, i16* %b, align 4
290  %inc = add nsw i32 %i, 1
291  switch i32 %i, label %for.cond [
292  i32 2096, label %if.end
293  i32 2097, label %if.end
294  ]
295
296if.end:
297  ret i32 %i
298}
299
300; multiple exit case but with a switch as multiple exiting edges from
301; a single block is a commonly missed edge case
302define i32 @multiple_exit_switch2(i16* %p, i32 %n) {
303; CHECK-LABEL: @multiple_exit_switch2(
304; CHECK-NEXT:  entry:
305; CHECK-NEXT:    br label [[FOR_COND:%.*]]
306; CHECK:       for.cond:
307; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND]] ]
308; CHECK-NEXT:    [[IPROM:%.*]] = sext i32 [[I]] to i64
309; CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds i16, i16* [[P:%.*]], i64 [[IPROM]]
310; CHECK-NEXT:    store i16 0, i16* [[B]], align 4
311; CHECK-NEXT:    [[INC]] = add nsw i32 [[I]], 1
312; CHECK-NEXT:    switch i32 [[I]], label [[FOR_COND]] [
313; CHECK-NEXT:    i32 2096, label [[IF_END:%.*]]
314; CHECK-NEXT:    i32 2097, label [[IF_END2:%.*]]
315; CHECK-NEXT:    ]
316; CHECK:       if.end:
317; CHECK-NEXT:    ret i32 0
318; CHECK:       if.end2:
319; CHECK-NEXT:    ret i32 1
320;
321entry:
322  br label %for.cond
323
324for.cond:
325  %i = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
326  %iprom = sext i32 %i to i64
327  %b = getelementptr inbounds i16, i16* %p, i64 %iprom
328  store i16 0, i16* %b, align 4
329  %inc = add nsw i32 %i, 1
330  switch i32 %i, label %for.cond [
331  i32 2096, label %if.end
332  i32 2097, label %if.end2
333  ]
334
335if.end:
336  ret i32 0
337
338if.end2:
339  ret i32 1
340}
341