1; RUN: opt -S -passes=loop-vectorize -force-vector-width=8 -force-vector-interleave=1 < %s | FileCheck %s -check-prefix=VF8
2; RUN: opt -S -passes=loop-vectorize -force-vector-width=1 -force-vector-interleave=4 < %s | FileCheck %s -check-prefix=VF1
3
4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5
6; Given a loop with an induction variable which is being
7; truncated/extended using casts that had been proven to
8; be redundant under a runtime test, we want to make sure
9; that these casts, do not get vectorized/scalarized/widened.
10; This is the case for inductions whose SCEV expression is
11; of the form "ExtTrunc(%phi) + %step", where "ExtTrunc"
12; can be a result of the IR sequences we check below.
13;
14; See also pr30654.
15;
16
17; Case1: Check the following induction pattern:
18;
19;  %p.09 = phi i32 [ 0, %for.body.lr.ph ], [ %add, %for.body ]
20;  %sext = shl i32 %p.09, 24
21;  %conv = ashr exact i32 %sext, 24
22;  %add = add nsw i32 %conv, %step
23;
24; This is the case in the following code:
25;
26; void doit1(int n, int step) {
27;   int i;
28;   char p = 0;
29;   for (i = 0; i < n; i++) {
30;      a[i] = p;
31;      p = p + step;
32;   }
33; }
34;
35; The "ExtTrunc" IR sequence here is:
36;  "%sext = shl i32 %p.09, 24"
37;  "%conv = ashr exact i32 %sext, 24"
38; We check that it does not appear in the vector loop body, whether
39; we vectorize or scalarize the induction.
40; In the case of widened induction, this means that the induction phi
41; is directly used, without shl/ashr on the way.
42
43; VF8-LABEL: @doit1
44; VF8: vector.body:
45; VF8: %vec.ind = phi <8 x i32>
46; VF8: store <8 x i32> %vec.ind
47; VF8: middle.block:
48
49; VF1-LABEL: @doit1
50; VF1: vector.body:
51; VF1-NOT: %{{.*}} = shl i32
52; VF1: middle.block:
53
54@a = common local_unnamed_addr global [250 x i32] zeroinitializer, align 16
55
56define void @doit1(i32 %n, i32 %step) {
57entry:
58  %cmp7 = icmp sgt i32 %n, 0
59  br i1 %cmp7, label %for.body.lr.ph, label %for.end
60
61for.body.lr.ph:
62  %wide.trip.count = zext i32 %n to i64
63  br label %for.body
64
65for.body:
66  %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
67  %p.09 = phi i32 [ 0, %for.body.lr.ph ], [ %add, %for.body ]
68  %sext = shl i32 %p.09, 24
69  %conv = ashr exact i32 %sext, 24
70  %arrayidx = getelementptr inbounds [250 x i32], [250 x i32]* @a, i64 0, i64 %indvars.iv
71  store i32 %conv, i32* %arrayidx, align 4
72  %add = add nsw i32 %conv, %step
73  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
74  %exitcond = icmp eq i64 %indvars.iv.next, %wide.trip.count
75  br i1 %exitcond, label %for.end.loopexit, label %for.body
76
77for.end.loopexit:
78  br label %for.end
79
80for.end:
81  ret void
82}
83
84
85; Case2: Another variant of the above pattern is where the induction variable
86; is used only for address compuation (i.e. it is a GEP index) and therefore
87; the induction is not vectorized but rather only the step is widened.
88;
89; This is the case in the following code, where the induction variable 'w_ix'
90; is only used to access the array 'in':
91;
92; void doit2(int *in, int *out, size_t size, size_t step)
93; {
94;    int w_ix = 0;
95;    for (size_t offset = 0; offset < size; ++offset)
96;     {
97;        int w = in[w_ix];
98;        out[offset] = w;
99;        w_ix += step;
100;     }
101; }
102;
103; The "ExtTrunc" IR sequence here is similar to the previous case:
104;  "%sext = shl i64 %w_ix.012, 32
105;  %idxprom = ashr exact i64 %sext, 32"
106; We check that it does not appear in the vector loop body, whether
107; we widen or scalarize the induction.
108; In the case of widened induction, this means that the induction phi
109; is directly used, without shl/ashr on the way.
110
111; VF8-LABEL: @doit2
112; VF8: vector.body:
113; VF8-NEXT:  [[INDEX:%.+]] = phi i64 [ 0, %vector.ph ]
114; VF8-NEXT:  [[I0:%.+]] = add i64 [[INDEX]], 0
115; VF8-NEXT:  [[OFFSET_IDX:%.+]] = mul i64 [[INDEX]], %step
116; VF8-NEXT:  [[MUL0:%.+]] = mul i64 0, %step
117; VF8-NEXT:  [[ADD:%.+]] = add i64 [[OFFSET_IDX]], [[MUL0]]
118; VF8:       getelementptr inbounds i32, i32* %in, i64 [[ADD]]
119; VF8: middle.block:
120
121; VF1-LABEL: @doit2
122; VF1: vector.body:
123; VF1-NOT: %{{.*}} = shl i64
124; VF1: middle.block:
125;
126
127define void @doit2(i32* nocapture readonly %in, i32* nocapture %out, i64 %size, i64 %step)  {
128entry:
129  %cmp9 = icmp eq i64 %size, 0
130  br i1 %cmp9, label %for.cond.cleanup, label %for.body.lr.ph
131
132for.body.lr.ph:
133  br label %for.body
134
135for.cond.cleanup.loopexit:
136  br label %for.cond.cleanup
137
138for.cond.cleanup:
139  ret void
140
141for.body:
142  %w_ix.011 = phi i64 [ 0, %for.body.lr.ph ], [ %add, %for.body ]
143  %offset.010 = phi i64 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
144  %sext = shl i64 %w_ix.011, 32
145  %idxprom = ashr exact i64 %sext, 32
146  %arrayidx = getelementptr inbounds i32, i32* %in, i64 %idxprom
147  %0 = load i32, i32* %arrayidx, align 4
148  %arrayidx1 = getelementptr inbounds i32, i32* %out, i64 %offset.010
149  store i32 %0, i32* %arrayidx1, align 4
150  %add = add i64 %idxprom, %step
151  %inc = add nuw i64 %offset.010, 1
152  %exitcond = icmp eq i64 %inc, %size
153  br i1 %exitcond, label %for.cond.cleanup.loopexit, label %for.body
154}
155
156; Case3: Lastly, check also the following induction pattern:
157;
158;  %p.09 = phi i32 [ %val0, %scalar.ph ], [ %add, %for.body ]
159;  %conv = and i32 %p.09, 255
160;  %add = add nsw i32 %conv, %step
161;
162; This is the case in the following code:
163;
164; int a[N];
165; void doit3(int n, int step) {
166;   int i;
167;   unsigned char p = 0;
168;   for (i = 0; i < n; i++) {
169;      a[i] = p;
170;      p = p + step;
171;   }
172; }
173;
174; The "ExtTrunc" IR sequence here is:
175;  "%conv = and i32 %p.09, 255".
176; We check that it does not appear in the vector loop body, whether
177; we vectorize or scalarize the induction.
178
179; VF8-LABEL: @doit3
180; VF8: vector.body:
181; VF8: %vec.ind = phi <8 x i32>
182; VF8: store <8 x i32> %vec.ind
183; VF8: middle.block:
184
185; VF1-LABEL: @doit3
186; VF1: vector.body:
187; VF1-NOT: %{{.*}} = and i32
188; VF1: middle.block:
189
190define void @doit3(i32 %n, i32 %step) {
191entry:
192  %cmp7 = icmp sgt i32 %n, 0
193  br i1 %cmp7, label %for.body.lr.ph, label %for.end
194
195for.body.lr.ph:
196  %wide.trip.count = zext i32 %n to i64
197  br label %for.body
198
199for.body:
200  %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
201  %p.09 = phi i32 [ 0, %for.body.lr.ph ], [ %add, %for.body ]
202  %conv = and i32 %p.09, 255
203  %arrayidx = getelementptr inbounds [250 x i32], [250 x i32]* @a, i64 0, i64 %indvars.iv
204  store i32 %conv, i32* %arrayidx, align 4
205  %add = add nsw i32 %conv, %step
206  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
207  %exitcond = icmp eq i64 %indvars.iv.next, %wide.trip.count
208  br i1 %exitcond, label %for.end.loopexit, label %for.body
209
210for.end.loopexit:
211  br label %for.end
212
213for.end:
214  ret void
215}
216
217; VF8-LABEL: @test_conv_in_latch_block
218; VF8: vector.body:
219; VF8-NEXT: %index = phi i64
220; VF8-NEXT: %vec.ind = phi <8 x i32>
221; VF8: store <8 x i32> %vec.ind
222; VF8: middle.block:
223;
224define void @test_conv_in_latch_block(i32 %n, i32 %step, i32* noalias %A, i32* noalias %B) {
225entry:
226  %wide.trip.count = zext i32 %n to i64
227  br label %loop
228
229loop:
230  %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
231  %p.09 = phi i32 [ 0, %entry ], [ %add, %latch ]
232  %B.gep = getelementptr inbounds i32, i32* %B, i64 %iv
233  %l = load i32, i32* %B.gep
234  %c = icmp eq i32 %l, 0
235  br i1 %c, label %then, label %latch
236
237then:
238  %A.gep = getelementptr inbounds i32, i32* %A, i64 %iv
239  store i32 0, i32* %A.gep
240  br label %latch
241
242latch:
243  %sext = shl i32 %p.09, 24
244  %conv = ashr exact i32 %sext, 24
245  %add = add nsw i32 %conv, %step
246  store i32 %conv, i32* %B.gep, align 4
247  %iv.next = add nuw nsw i64 %iv, 1
248  %exitcond = icmp eq i64 %iv.next, %wide.trip.count
249  br i1 %exitcond, label %exit, label %loop
250
251exit:
252  ret void
253}
254