1; RUN: opt < %s -passes="loop-vectorize" -force-vector-interleave=1 -force-vector-width=4 -S | FileCheck %s
2
3target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
4
5; This test checks that we can vectorize loop with reduction variable
6; stored in an invariant address.
7;
8; int sum = 0;
9; for(i=0..N) {
10;   sum += src[i];
11;   dst[42] = sum;
12; }
13; CHECK-LABEL: @reduc_store
14; CHECK:       vector.body:
15; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH:%.*]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY:%.*]] ]
16; CHECK-NEXT:    [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP4:%.*]], [[VECTOR_BODY]] ]
17; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
18; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[TMP0]]
19; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i32 0
20; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i32* [[TMP2]] to <4 x i32>*
21; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i32>, <4 x i32>* [[TMP3]], align 4, !alias.scope !0
22; CHECK-NEXT:    [[TMP4]] = add <4 x i32> [[VEC_PHI]], [[WIDE_LOAD]]
23; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
24; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[INDEX_NEXT]], 1000
25; CHECK-NEXT:    br i1 [[TMP5]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]]
26; CHECK:       middle.block:
27; CHECK-NEXT:    [[TMP6:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP4]])
28; CHECK-NEXT:    store i32 [[TMP6]], i32* [[GEP_DST:%.*]], align 4
29; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 1000, 1000
30; CHECK-NEXT:    br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH:%.*]]
31define void @reduc_store(i32* %dst, i32* readonly %src) {
32entry:
33  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
34  store i32 0, i32* %gep.dst, align 4
35  br label %for.body
36
37for.body:
38  %sum = phi i32 [ 0, %entry ], [ %add, %for.body ]
39  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
40  %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv
41  %0 = load i32, i32* %gep.src, align 4
42  %add = add nsw i32 %sum, %0
43  store i32 %add, i32* %gep.dst, align 4
44  %iv.next = add nuw nsw i64 %iv, 1
45  %exitcond = icmp eq i64 %iv.next, 1000
46  br i1 %exitcond, label %exit, label %for.body
47
48exit:
49  ret void
50}
51
52; Same as above but with floating point numbers instead.
53;
54; float sum = 0;
55; for(i=0..N) {
56;   sum += src[i];
57;   dst[42] = sum;
58; }
59; CHECK-LABEL: @reduc_store_fadd_fast
60; CHECK: vector.body:
61; CHECK: phi <4 x float>
62; CHECK: load <4 x float>
63; CHECK: fadd fast <4 x float>
64; CHECK-NOT: store float %{{[0-9]+}}, float* %gep.dst
65; CHECK: middle.block:
66; CHECK-NEXT: [[TMP:%.*]] = call fast float @llvm.vector.reduce.fadd.v4f32
67; CHECK-NEXT: store float %{{[0-9]+}}, float* %gep.dst
68define void @reduc_store_fadd_fast(float* %dst, float* readonly %src) {
69entry:
70  %gep.dst = getelementptr inbounds float, float* %dst, i64 42
71  store float 0.000000e+00, float* %gep.dst, align 4
72  br label %for.body
73
74for.body:
75  %sum = phi float [ 0.000000e+00, %entry ], [ %add, %for.body ]
76  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
77  %gep.src = getelementptr inbounds float, float* %src, i64 %iv
78  %0 = load float, float* %gep.src, align 4
79  %add = fadd fast float %sum, %0
80  store float %add, float* %gep.dst, align 4
81  %iv.next = add nuw nsw i64 %iv, 1
82  %exitcond = icmp eq i64 %iv.next, 1000
83  br i1 %exitcond, label %exit, label %for.body
84
85exit:
86  ret void
87}
88
89; Check that if we have a read from an invariant address, we do not vectorize.
90;
91; int sum = 0;
92; for(i=0..N) {
93;   sum += src[i];
94;   dst.2[i] = dst[42];
95;   dst[42] = sum;
96; }
97; CHECK-LABEL: @reduc_store_load
98; CHECK-NOT: vector.body
99define void @reduc_store_load(i32* %dst, i32* readonly %src, i32* noalias %dst.2) {
100entry:
101  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
102  store i32 0, i32* %gep.dst, align 4
103  br label %for.body
104
105for.body:
106  %sum = phi i32 [ 0, %entry ], [ %add, %for.body ]
107  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
108  %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv
109  %0 = load i32, i32* %gep.src, align 4
110  %add = add nsw i32 %sum, %0
111  %lv = load i32, i32* %gep.dst
112  %gep.dst.2  = getelementptr inbounds i32, i32* %dst.2, i64 %iv
113  store i32 %lv, i32* %gep.dst.2, align 4
114  store i32 %add, i32* %gep.dst, align 4
115  %iv.next = add nuw nsw i64 %iv, 1
116  %exitcond = icmp eq i64 %iv.next, 1000
117  br i1 %exitcond, label %exit, label %for.body
118
119exit:
120  ret void
121}
122
123; Final value is not guaranteed to be stored in an invariant address.
124; We don't vectorize in that case.
125;
126; int sum = 0;
127; for(i=0..N) {
128;   int diff = y[i] - x[i];
129;   if (diff > 0) {
130;     sum = += diff;
131;     *t = sum;
132;   }
133; }
134; CHECK-LABEL: @reduc_cond_store
135; CHECK-NOT: vector.body
136define void @reduc_cond_store(i32* %t, i32* readonly %x, i32* readonly %y) {
137entry:
138  store i32 0, i32* %t, align 4
139  br label %for.body
140
141for.body:
142  %sum = phi i32 [ 0, %entry ], [ %sum.2, %if.end ]
143  %iv = phi i64 [ 0, %entry ], [ %iv.next, %if.end ]
144  %gep.y = getelementptr inbounds i32, i32* %y, i64 %iv
145  %0 = load i32, i32* %gep.y, align 4
146  %gep.x = getelementptr inbounds i32, i32* %x, i64 %iv
147  %1 = load i32, i32* %gep.x, align 4
148  %diff = sub nsw i32 %0, %1
149  %cmp2 = icmp sgt i32 %diff, 0
150  br i1 %cmp2, label %if.then, label %if.end
151
152if.then:
153  %sum.1 = add nsw i32 %diff, %sum
154  store i32 %sum.1, i32* %t, align 4
155  br label %if.end
156
157if.end:
158  %sum.2 = phi i32 [ %sum.1, %if.then ], [ %0, %for.body ]
159  %iv.next = add nuw nsw i64 %iv, 1
160  %exitcond = icmp eq i64 %iv.next, 1000
161  br i1 %exitcond, label %for.end, label %for.body
162
163for.end:
164  ret void
165}
166
167; Check that we can vectorize code with several stores to an invariant address
168; with condition that final reduction value is stored too.
169;
170;  int sum = 0;
171;  for(int i=0; i < 1000; i+=2) {
172;    sum += src[i];
173;    dst[42] = sum;
174;    sum += src[i+1];
175;    dst[42] = sum;
176;  }
177; CHECK-LABEL: @reduc_store_inside_unrolled
178; CHECK:       vector.body:
179; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH:%.*]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY:%.*]] ]
180; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 2, i64 4, i64 6>, [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ]
181; CHECK-NEXT:    [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP34:%.*]], [[VECTOR_BODY]] ]
182; CHECK-NEXT:    [[OFFSET_IDX:%.*]] = mul i64 [[INDEX]], 2
183; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[OFFSET_IDX]], 0
184; CHECK-NEXT:    [[TMP1:%.*]] = add i64 [[OFFSET_IDX]], 2
185; CHECK-NEXT:    [[TMP2:%.*]] = add i64 [[OFFSET_IDX]], 4
186; CHECK-NEXT:    [[TMP3:%.*]] = add i64 [[OFFSET_IDX]], 6
187; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[TMP0]]
188; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP1]]
189; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP2]]
190; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP3]]
191; CHECK-NEXT:    [[TMP8:%.*]] = load i32, i32* [[TMP4]], align 4, !alias.scope !11
192; CHECK-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP5]], align 4, !alias.scope !11
193; CHECK-NEXT:    [[TMP10:%.*]] = load i32, i32* [[TMP6]], align 4, !alias.scope !11
194; CHECK-NEXT:    [[TMP11:%.*]] = load i32, i32* [[TMP7]], align 4, !alias.scope !11
195; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <4 x i32> poison, i32 [[TMP8]], i32 0
196; CHECK-NEXT:    [[TMP13:%.*]] = insertelement <4 x i32> [[TMP12]], i32 [[TMP9]], i32 1
197; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <4 x i32> [[TMP13]], i32 [[TMP10]], i32 2
198; CHECK-NEXT:    [[TMP15:%.*]] = insertelement <4 x i32> [[TMP14]], i32 [[TMP11]], i32 3
199; CHECK-NEXT:    [[TMP16:%.*]] = add <4 x i32> [[TMP15]], [[VEC_PHI]]
200; CHECK-NEXT:    [[TMP17:%.*]] = or <4 x i64> [[VEC_IND]], <i64 1, i64 1, i64 1, i64 1>
201; CHECK-NEXT:    [[TMP18:%.*]] = extractelement <4 x i64> [[TMP17]], i32 0
202; CHECK-NEXT:    [[TMP19:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP18]]
203; CHECK-NEXT:    [[TMP20:%.*]] = extractelement <4 x i64> [[TMP17]], i32 1
204; CHECK-NEXT:    [[TMP21:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP20]]
205; CHECK-NEXT:    [[TMP22:%.*]] = extractelement <4 x i64> [[TMP17]], i32 2
206; CHECK-NEXT:    [[TMP23:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP22]]
207; CHECK-NEXT:    [[TMP24:%.*]] = extractelement <4 x i64> [[TMP17]], i32 3
208; CHECK-NEXT:    [[TMP25:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i64 [[TMP24]]
209; CHECK-NEXT:    [[TMP26:%.*]] = load i32, i32* [[TMP19]], align 4, !alias.scope !11
210; CHECK-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP21]], align 4, !alias.scope !11
211; CHECK-NEXT:    [[TMP28:%.*]] = load i32, i32* [[TMP23]], align 4, !alias.scope !11
212; CHECK-NEXT:    [[TMP29:%.*]] = load i32, i32* [[TMP25]], align 4, !alias.scope !11
213; CHECK-NEXT:    [[TMP30:%.*]] = insertelement <4 x i32> poison, i32 [[TMP26]], i32 0
214; CHECK-NEXT:    [[TMP31:%.*]] = insertelement <4 x i32> [[TMP30]], i32 [[TMP27]], i32 1
215; CHECK-NEXT:    [[TMP32:%.*]] = insertelement <4 x i32> [[TMP31]], i32 [[TMP28]], i32 2
216; CHECK-NEXT:    [[TMP33:%.*]] = insertelement <4 x i32> [[TMP32]], i32 [[TMP29]], i32 3
217; CHECK-NEXT:    [[TMP34]] = add <4 x i32> [[TMP33]], [[TMP16]]
218; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
219; CHECK-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], <i64 8, i64 8, i64 8, i64 8>
220; CHECK-NEXT:    [[TMP35:%.*]] = icmp eq i64 [[INDEX_NEXT]], 500
221; CHECK-NEXT:    br i1 [[TMP35]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP14:![0-9]+]]
222; CHECK:       middle.block:
223; CHECK-NEXT:    [[TMP36:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP34]])
224; CHECK-NEXT:    store i32 [[TMP36]], i32* [[GEP_DST:%.*]], align 4
225; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 500, 500
226; CHECK-NEXT:    br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH:%.*]]
227define void @reduc_store_inside_unrolled(i32* %dst, i32* readonly %src) {
228entry:
229  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
230  br label %for.body
231
232for.body:
233  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
234  %sum = phi i32 [ 0, %entry ], [ %sum.2, %for.body ]
235  %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv
236  %0 = load i32, i32* %gep.src, align 4
237  %sum.1 = add nsw i32 %0, %sum
238  store i32 %sum.1, i32* %gep.dst, align 4
239  %1 = or i64 %iv, 1
240  %gep.src.1 = getelementptr inbounds i32, i32* %src, i64 %1
241  %2 = load i32, i32* %gep.src.1, align 4
242  %sum.2 = add nsw i32 %2, %sum.1
243  store i32 %sum.2, i32* %gep.dst, align 4
244  %iv.next = add nuw nsw i64 %iv, 2
245  %cmp = icmp slt i64 %iv.next, 1000
246  br i1 %cmp, label %for.body, label %exit
247
248exit:
249  ret void
250}
251
252; Check that we cannot vectorize code if stored value is not the final reduction
253; value
254;
255;  int sum = 0;
256;  for(int i=0; i < 1000; i++) {
257;    sum += src[i];
258;    dst[42] = sum + 1;
259;  }
260; CHECK-LABEL: @reduc_store_not_final_value
261; CHECK-NOT: vector.body:
262define void @reduc_store_not_final_value(i32* %dst, i32* readonly %src) {
263entry:
264  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
265  store i32 0, i32* %gep.dst, align 4
266  br label %for.body
267
268for.body:
269  %sum = phi i32 [ 0, %entry ], [ %add, %for.body ]
270  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
271  %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv
272  %0 = load i32, i32* %gep.src, align 4
273  %add = add nsw i32 %sum, %0
274  %sum_plus_one = add i32 %add, 1
275  store i32 %sum_plus_one, i32* %gep.dst, align 4
276  %iv.next = add nuw nsw i64 %iv, 1
277  %exitcond = icmp eq i64 %iv.next, 1000
278  br i1 %exitcond, label %exit, label %for.body
279
280exit:
281  ret void
282}
283
284; We cannot vectorize if two (or more) invariant stores exist in a loop.
285;
286;  int sum = 0;
287;  for(int i=0; i < 1000; i+=2) {
288;    sum += src[i];
289;    dst[42] = sum;
290;    sum += src[i+1];
291;    other_dst[42] = sum;
292;  }
293; CHECK-LABEL: @reduc_double_invariant_store
294; CHECK-NOT: vector.body:
295define void @reduc_double_invariant_store(i32* %dst, i32* %other_dst, i32* readonly %src) {
296entry:
297  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
298  %gep.other_dst = getelementptr inbounds i32, i32* %other_dst, i64 42
299  br label %for.body
300
301for.body:
302  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
303  %sum = phi i32 [ 0, %entry ], [ %sum.2, %for.body ]
304  %arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv
305  %0 = load i32, i32* %arrayidx, align 4
306  %sum.1 = add nsw i32 %0, %sum
307  store i32 %sum.1, i32* %gep.dst, align 4
308  %1 = or i64 %iv, 1
309  %arrayidx4 = getelementptr inbounds i32, i32* %src, i64 %1
310  %2 = load i32, i32* %arrayidx4, align 4
311  %sum.2 = add nsw i32 %2, %sum.1
312  store i32 %sum.2, i32* %gep.other_dst, align 4
313  %iv.next = add nuw nsw i64 %iv, 2
314  %cmp = icmp slt i64 %iv.next, 1000
315  br i1 %cmp, label %for.body, label %exit
316
317exit:
318  ret void
319}
320
321;  int sum = 0;
322;  for(int i=0; i < 1000; i+=2) {
323;    sum += src[i];
324;    if (src[i+1] > 0)
325;      dst[42] = sum;
326;    sum += src[i+1];
327;    dst[42] = sum;
328;  }
329; CHECK-LABEL: @reduc_store_middle_store_predicated
330; CHECK: vector.body:
331; CHECK-NOT: store i32 %{{[0-9]+}}, i32* %gep.dst
332; CHECK: middle.block:
333; CHECK-NEXT: [[TMP:%.*]] = call i32 @llvm.vector.reduce.add.v4i32
334; CHECK-NEXT: store i32 [[TMP]], i32* %gep.dst
335; CHECK: ret void
336define void @reduc_store_middle_store_predicated(i32* %dst, i32* readonly %src) {
337entry:
338  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
339  br label %for.body
340
341for.body:                                         ; preds = %latch, %entry
342  %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
343  %sum = phi i32 [ 0, %entry ], [ %sum.2, %latch ]
344  %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv
345  %0 = load i32, i32* %gep.src, align 4
346  %sum.1 = add nsw i32 %0, %sum
347  %cmp = icmp sgt i32 %0, 0
348  br i1 %cmp, label %predicated, label %latch
349
350predicated:                                       ; preds = %for.body
351  store i32 %sum.1, i32* %gep.dst, align 4
352  br label %latch
353
354latch:                                            ; preds = %predicated, %for.body
355  %1 = or i64 %iv, 1
356  %gep.src.1 = getelementptr inbounds i32, i32* %src, i64 %1
357  %2 = load i32, i32* %gep.src.1, align 4
358  %sum.2 = add nsw i32 %2, %sum.1
359  store i32 %sum.2, i32* %gep.dst, align 4
360  %iv.next = add nuw nsw i64 %iv, 2
361  %cmp.1 = icmp slt i64 %iv.next, 1000
362  br i1 %cmp.1, label %for.body, label %exit
363
364exit:                                 ; preds = %latch
365  ret void
366}
367
368;  int sum = 0;
369;  for(int i=0; i < 1000; i+=2) {
370;    sum += src[i];
371;    dst[42] = sum;
372;    sum += src[i+1];
373;    if (src[i+1] > 0)
374;      dst[42] = sum;
375;  }
376; CHECK-LABEL: @reduc_store_final_store_predicated
377; CHECK-NOT: vector.body:
378define void @reduc_store_final_store_predicated(i32* %dst, i32* readonly %src) {
379entry:
380  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
381  br label %for.body
382
383for.body:                                         ; preds = %latch, %entry
384  %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
385  %sum = phi i32 [ 0, %entry ], [ %sum.1, %latch ]
386  %arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv
387  %0 = load i32, i32* %arrayidx, align 4
388  %sum.1 = add nsw i32 %0, %sum
389  store i32 %sum.1, i32* %gep.dst, align 4
390  %1 = or i64 %iv, 1
391  %gep.src.1 = getelementptr inbounds i32, i32* %src, i64 %1
392  %2 = load i32, i32* %gep.src.1, align 4
393  %sum.2 = add nsw i32 %2, %sum.1
394  %cmp1 = icmp sgt i32 %2, 0
395  br i1 %cmp1, label %predicated, label %latch
396
397predicated:                                       ; preds = %for.body
398  store i32 %sum.2, i32* %gep.dst, align 4
399  br label %latch
400
401latch:                                            ; preds = %predicated, %for.body
402  %iv.next = add nuw nsw i64 %iv, 2
403  %cmp = icmp slt i64 %iv.next, 1000
404  br i1 %cmp, label %for.body, label %exit
405
406exit:                                 ; preds = %latch
407  ret void
408}
409
410; Final reduction value is overwritten inside loop
411;
412; for(int i=0; i < 1000; i++) {
413;   sum += src[i];
414;   dst[42] = sum;
415;   dst[42] = 0;
416; }
417; CHECK-LABEL: @reduc_store_final_store_overwritten
418; CHECK-NOT: vector.body:
419define void @reduc_store_final_store_overwritten(i32* %dst, i32* readonly %src) {
420entry:
421  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
422  br label %for.body
423
424for.body:
425  %sum = phi i32 [ 0, %entry ], [ %add, %for.body ]
426  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
427  %gep.src = getelementptr inbounds i32, i32* %src, i64 %iv
428  %0 = load i32, i32* %gep.src, align 4
429  %add = add nsw i32 %sum, %0
430  store i32 %add, i32* %gep.dst, align 4
431  store i32 0, i32* %gep.dst, align 4
432  %iv.next = add nuw nsw i64 %iv, 1
433  %exitcond = icmp eq i64 %iv.next, 1000
434  br i1 %exitcond, label %exit, label %for.body
435
436exit:
437  ret void
438}
439
440; Final value used outside of loop does not prevent vectorization
441;
442; int sum = 0;
443; for(int i=0; i < 1000; i++) {
444;   sum += src[i];
445;   dst[42] = sum;
446; }
447; dst[43] = sum;
448; CHECK-LABEL: @reduc_store_inoutside
449; CHECK: vector.body:
450; CHECK-NOT: store i32 %{{[0-9]+}}, i32* %gep.src
451; CHECK: middle.block:
452; CHECK-NEXT: [[TMP:%.*]] = call i32 @llvm.vector.reduce.add.v4i32
453; CHECK-NEXT: store i32 [[TMP]], i32* %gep.dst
454; CHECK: exit:
455; CHECK: [[PHI:%.*]] = phi i32 [ [[TMP1:%.*]], %for.body ], [ [[TMP2:%.*]], %middle.block ]
456; CHECK: [[ADDR:%.*]] = getelementptr inbounds i32, i32* %dst, i64 43
457; CHECK: store i32 [[PHI]], i32* [[ADDR]]
458; CHECK: ret void
459define void @reduc_store_inoutside(i32* %dst, i32* readonly %src) {
460entry:
461  %gep.dst = getelementptr inbounds i32, i32* %dst, i64 42
462  br label %for.body
463
464for.body:
465  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
466  %sum = phi i32 [ 0, %entry ], [ %sum.1, %for.body ]
467  %arrayidx = getelementptr inbounds i32, i32* %src, i64 %iv
468  %0 = load i32, i32* %arrayidx, align 4
469  %sum.1 = add nsw i32 %0, %sum
470  store i32 %sum.1, i32* %gep.dst, align 4
471  %iv.next = add nuw nsw i64 %iv, 1
472  %exitcond = icmp eq i64 %iv.next, 1000
473  br i1 %exitcond, label %exit, label %for.body
474
475exit:
476  %sum.lcssa = phi i32 [ %sum.1, %for.body ]
477  %gep.dst.1 = getelementptr inbounds i32, i32* %dst, i64 43
478  store i32 %sum.lcssa, i32* %gep.dst.1, align 4
479  ret void
480}
481