Merging r261039:
[oota-llvm.git] / test / CodeGen / X86 / MergeConsecutiveStores.ll
1 ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+avx < %s | FileCheck %s
2 ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+avx -addr-sink-using-gep=1 < %s | FileCheck %s
3
4 %struct.A = type { i8, i8, i8, i8, i8, i8, i8, i8 }
5 %struct.B = type { i32, i32, i32, i32, i32, i32, i32, i32 }
6
7 ; CHECK-LABEL: merge_const_store:
8 ; save 1,2,3 ... as one big integer.
9 ; CHECK: movabsq $578437695752307201
10 ; CHECK: ret
11 define void @merge_const_store(i32 %count, %struct.A* nocapture %p) nounwind uwtable noinline ssp {
12   %1 = icmp sgt i32 %count, 0
13   br i1 %1, label %.lr.ph, label %._crit_edge
14 .lr.ph:
15   %i.02 = phi i32 [ %10, %.lr.ph ], [ 0, %0 ]
16   %.01 = phi %struct.A* [ %11, %.lr.ph ], [ %p, %0 ]
17   %2 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 0
18   store i8 1, i8* %2, align 1
19   %3 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 1
20   store i8 2, i8* %3, align 1
21   %4 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 2
22   store i8 3, i8* %4, align 1
23   %5 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 3
24   store i8 4, i8* %5, align 1
25   %6 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 4
26   store i8 5, i8* %6, align 1
27   %7 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 5
28   store i8 6, i8* %7, align 1
29   %8 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 6
30   store i8 7, i8* %8, align 1
31   %9 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 7
32   store i8 8, i8* %9, align 1
33   %10 = add nsw i32 %i.02, 1
34   %11 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 1
35   %exitcond = icmp eq i32 %10, %count
36   br i1 %exitcond, label %._crit_edge, label %.lr.ph
37 ._crit_edge:
38   ret void
39 }
40
41 ; No vectors because we use noimplicitfloat
42 ; CHECK-LABEL: merge_const_store_no_vec:
43 ; CHECK-NOT: vmovups
44 ; CHECK: ret
45 define void @merge_const_store_no_vec(i32 %count, %struct.B* nocapture %p) noimplicitfloat{
46   %1 = icmp sgt i32 %count, 0
47   br i1 %1, label %.lr.ph, label %._crit_edge
48 .lr.ph:
49   %i.02 = phi i32 [ %10, %.lr.ph ], [ 0, %0 ]
50   %.01 = phi %struct.B* [ %11, %.lr.ph ], [ %p, %0 ]
51   %2 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 0
52   store i32 0, i32* %2, align 4
53   %3 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 1
54   store i32 0, i32* %3, align 4
55   %4 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 2
56   store i32 0, i32* %4, align 4
57   %5 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 3
58   store i32 0, i32* %5, align 4
59   %6 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 4
60   store i32 0, i32* %6, align 4
61   %7 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 5
62   store i32 0, i32* %7, align 4
63   %8 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 6
64   store i32 0, i32* %8, align 4
65   %9 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 7
66   store i32 0, i32* %9, align 4
67   %10 = add nsw i32 %i.02, 1
68   %11 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 1
69   %exitcond = icmp eq i32 %10, %count
70   br i1 %exitcond, label %._crit_edge, label %.lr.ph
71 ._crit_edge:
72   ret void
73 }
74
75 ; Move the constants using a single vector store.
76 ; CHECK-LABEL: merge_const_store_vec:
77 ; CHECK: vmovups
78 ; CHECK: ret
79 define void @merge_const_store_vec(i32 %count, %struct.B* nocapture %p) nounwind uwtable noinline ssp {
80   %1 = icmp sgt i32 %count, 0
81   br i1 %1, label %.lr.ph, label %._crit_edge
82 .lr.ph:
83   %i.02 = phi i32 [ %10, %.lr.ph ], [ 0, %0 ]
84   %.01 = phi %struct.B* [ %11, %.lr.ph ], [ %p, %0 ]
85   %2 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 0
86   store i32 0, i32* %2, align 4
87   %3 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 1
88   store i32 0, i32* %3, align 4
89   %4 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 2
90   store i32 0, i32* %4, align 4
91   %5 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 3
92   store i32 0, i32* %5, align 4
93   %6 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 4
94   store i32 0, i32* %6, align 4
95   %7 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 5
96   store i32 0, i32* %7, align 4
97   %8 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 6
98   store i32 0, i32* %8, align 4
99   %9 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 7
100   store i32 0, i32* %9, align 4
101   %10 = add nsw i32 %i.02, 1
102   %11 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 1
103   %exitcond = icmp eq i32 %10, %count
104   br i1 %exitcond, label %._crit_edge, label %.lr.ph
105 ._crit_edge:
106   ret void
107 }
108
109 ; Move the first 4 constants as a single vector. Move the rest as scalars.
110 ; CHECK-LABEL: merge_nonconst_store:
111 ; CHECK: movl $67305985
112 ; CHECK: movb
113 ; CHECK: movb
114 ; CHECK: movb
115 ; CHECK: movb
116 ; CHECK: ret
117 define void @merge_nonconst_store(i32 %count, i8 %zz, %struct.A* nocapture %p) nounwind uwtable noinline ssp {
118   %1 = icmp sgt i32 %count, 0
119   br i1 %1, label %.lr.ph, label %._crit_edge
120 .lr.ph:
121   %i.02 = phi i32 [ %10, %.lr.ph ], [ 0, %0 ]
122   %.01 = phi %struct.A* [ %11, %.lr.ph ], [ %p, %0 ]
123   %2 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 0
124   store i8 1, i8* %2, align 1
125   %3 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 1
126   store i8 2, i8* %3, align 1
127   %4 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 2
128   store i8 3, i8* %4, align 1
129   %5 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 3
130   store i8 4, i8* %5, align 1
131   %6 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 4
132   store i8 %zz, i8* %6, align 1                     ;  <----------- Not a const;
133   %7 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 5
134   store i8 6, i8* %7, align 1
135   %8 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 6
136   store i8 7, i8* %8, align 1
137   %9 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 7
138   store i8 8, i8* %9, align 1
139   %10 = add nsw i32 %i.02, 1
140   %11 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 1
141   %exitcond = icmp eq i32 %10, %count
142   br i1 %exitcond, label %._crit_edge, label %.lr.ph
143 ._crit_edge:
144   ret void
145 }
146
147
148 ; CHECK-LABEL: merge_loads_i16:
149 ;  load:
150 ; CHECK: movw
151 ;  store:
152 ; CHECK: movw
153 ; CHECK: ret
154 define void @merge_loads_i16(i32 %count, %struct.A* noalias nocapture %q, %struct.A* noalias nocapture %p) nounwind uwtable noinline ssp {
155   %1 = icmp sgt i32 %count, 0
156   br i1 %1, label %.lr.ph, label %._crit_edge
157
158 .lr.ph:                                           ; preds = %0
159   %2 = getelementptr inbounds %struct.A, %struct.A* %q, i64 0, i32 0
160   %3 = getelementptr inbounds %struct.A, %struct.A* %q, i64 0, i32 1
161   br label %4
162
163 ; <label>:4                                       ; preds = %4, %.lr.ph
164   %i.02 = phi i32 [ 0, %.lr.ph ], [ %9, %4 ]
165   %.01 = phi %struct.A* [ %p, %.lr.ph ], [ %10, %4 ]
166   %5 = load i8, i8* %2, align 1
167   %6 = load i8, i8* %3, align 1
168   %7 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 0
169   store i8 %5, i8* %7, align 1
170   %8 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 1
171   store i8 %6, i8* %8, align 1
172   %9 = add nsw i32 %i.02, 1
173   %10 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 1
174   %exitcond = icmp eq i32 %9, %count
175   br i1 %exitcond, label %._crit_edge, label %4
176
177 ._crit_edge:                                      ; preds = %4, %0
178   ret void
179 }
180
181 ; The loads and the stores are interleaved. Can't merge them.
182 ; CHECK-LABEL: no_merge_loads:
183 ; CHECK: movb
184 ; CHECK: movb
185 ; CHECK: movb
186 ; CHECK: movb
187 ; CHECK: ret
188 define void @no_merge_loads(i32 %count, %struct.A* noalias nocapture %q, %struct.A* noalias nocapture %p) nounwind uwtable noinline ssp {
189   %1 = icmp sgt i32 %count, 0
190   br i1 %1, label %.lr.ph, label %._crit_edge
191
192 .lr.ph:                                           ; preds = %0
193   %2 = getelementptr inbounds %struct.A, %struct.A* %q, i64 0, i32 0
194   %3 = getelementptr inbounds %struct.A, %struct.A* %q, i64 0, i32 1
195   br label %a4
196
197 a4:                                       ; preds = %4, %.lr.ph
198   %i.02 = phi i32 [ 0, %.lr.ph ], [ %a9, %a4 ]
199   %.01 = phi %struct.A* [ %p, %.lr.ph ], [ %a10, %a4 ]
200   %a5 = load i8, i8* %2, align 1
201   %a7 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 0
202   store i8 %a5, i8* %a7, align 1
203   %a8 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 0, i32 1
204   %a6 = load i8, i8* %3, align 1
205   store i8 %a6, i8* %a8, align 1
206   %a9 = add nsw i32 %i.02, 1
207   %a10 = getelementptr inbounds %struct.A, %struct.A* %.01, i64 1
208   %exitcond = icmp eq i32 %a9, %count
209   br i1 %exitcond, label %._crit_edge, label %a4
210
211 ._crit_edge:                                      ; preds = %4, %0
212   ret void
213 }
214
215
216 ; CHECK-LABEL: merge_loads_integer:
217 ;  load:
218 ; CHECK: movq
219 ;  store:
220 ; CHECK: movq
221 ; CHECK: ret
222 define void @merge_loads_integer(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
223   %1 = icmp sgt i32 %count, 0
224   br i1 %1, label %.lr.ph, label %._crit_edge
225
226 .lr.ph:                                           ; preds = %0
227   %2 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 0
228   %3 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 1
229   br label %4
230
231 ; <label>:4                                       ; preds = %4, %.lr.ph
232   %i.02 = phi i32 [ 0, %.lr.ph ], [ %9, %4 ]
233   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %10, %4 ]
234   %5 = load i32, i32* %2
235   %6 = load i32, i32* %3
236   %7 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 0
237   store i32 %5, i32* %7
238   %8 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 1
239   store i32 %6, i32* %8
240   %9 = add nsw i32 %i.02, 1
241   %10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 1
242   %exitcond = icmp eq i32 %9, %count
243   br i1 %exitcond, label %._crit_edge, label %4
244
245 ._crit_edge:                                      ; preds = %4, %0
246   ret void
247 }
248
249
250 ; CHECK-LABEL: merge_loads_vector:
251 ;  load:
252 ; CHECK: movups
253 ;  store:
254 ; CHECK: movups
255 ; CHECK: ret
256 define void @merge_loads_vector(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
257   %a1 = icmp sgt i32 %count, 0
258   br i1 %a1, label %.lr.ph, label %._crit_edge
259
260 .lr.ph:                                           ; preds = %0
261   %a2 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 0
262   %a3 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 1
263   %a4 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 2
264   %a5 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 3
265   br label %block4
266
267 block4:                                       ; preds = %4, %.lr.ph
268   %i.02 = phi i32 [ 0, %.lr.ph ], [ %c9, %block4 ]
269   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %c10, %block4 ]
270   %a7 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 0
271   %a8 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 1
272   %a9 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 2
273   %a10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 3
274   %b1 = load i32, i32* %a2
275   %b2 = load i32, i32* %a3
276   %b3 = load i32, i32* %a4
277   %b4 = load i32, i32* %a5
278   store i32 %b1, i32* %a7
279   store i32 %b2, i32* %a8
280   store i32 %b3, i32* %a9
281   store i32 %b4, i32* %a10
282   %c9 = add nsw i32 %i.02, 1
283   %c10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 1
284   %exitcond = icmp eq i32 %c9, %count
285   br i1 %exitcond, label %._crit_edge, label %block4
286
287 ._crit_edge:                                      ; preds = %4, %0
288   ret void
289 }
290
291 ;; On x86, even unaligned copies should be merged to vector ops.
292 ;; TODO: however, this cannot happen at the moment, due to brokenness
293 ;; in MergeConsecutiveStores. See UseAA FIXME in DAGCombiner.cpp
294 ;; visitSTORE.
295
296 ; CHECK-LABEL: merge_loads_no_align:
297 ;  load:
298 ; CHECK-NOT: vmovups ;; TODO
299 ;  store:
300 ; CHECK-NOT: vmovups ;; TODO
301 ; CHECK: ret
302 define void @merge_loads_no_align(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
303   %a1 = icmp sgt i32 %count, 0
304   br i1 %a1, label %.lr.ph, label %._crit_edge
305
306 .lr.ph:                                           ; preds = %0
307   %a2 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 0
308   %a3 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 1
309   %a4 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 2
310   %a5 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 3
311   br label %block4
312
313 block4:                                       ; preds = %4, %.lr.ph
314   %i.02 = phi i32 [ 0, %.lr.ph ], [ %c9, %block4 ]
315   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %c10, %block4 ]
316   %a7 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 0
317   %a8 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 1
318   %a9 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 2
319   %a10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 3
320   %b1 = load i32, i32* %a2, align 1
321   %b2 = load i32, i32* %a3, align 1
322   %b3 = load i32, i32* %a4, align 1
323   %b4 = load i32, i32* %a5, align 1
324   store i32 %b1, i32* %a7, align 1
325   store i32 %b2, i32* %a8, align 1
326   store i32 %b3, i32* %a9, align 1
327   store i32 %b4, i32* %a10, align 1
328   %c9 = add nsw i32 %i.02, 1
329   %c10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 1
330   %exitcond = icmp eq i32 %c9, %count
331   br i1 %exitcond, label %._crit_edge, label %block4
332
333 ._crit_edge:                                      ; preds = %4, %0
334   ret void
335 }
336
337 ; Make sure that we merge the consecutive load/store sequence below and use a
338 ; word (16 bit) instead of a byte copy.
339 ; CHECK-LABEL: MergeLoadStoreBaseIndexOffset:
340 ; CHECK: movw    (%{{.*}},%{{.*}}), [[REG:%[a-z]+]]
341 ; CHECK: movw    [[REG]], (%{{.*}})
342 define void @MergeLoadStoreBaseIndexOffset(i64* %a, i8* %b, i8* %c, i32 %n) {
343   br label %1
344
345 ; <label>:1
346   %.09 = phi i32 [ %n, %0 ], [ %11, %1 ]
347   %.08 = phi i8* [ %b, %0 ], [ %10, %1 ]
348   %.0 = phi i64* [ %a, %0 ], [ %2, %1 ]
349   %2 = getelementptr inbounds i64, i64* %.0, i64 1
350   %3 = load i64, i64* %.0, align 1
351   %4 = getelementptr inbounds i8, i8* %c, i64 %3
352   %5 = load i8, i8* %4, align 1
353   %6 = add i64 %3, 1
354   %7 = getelementptr inbounds i8, i8* %c, i64 %6
355   %8 = load i8, i8* %7, align 1
356   store i8 %5, i8* %.08, align 1
357   %9 = getelementptr inbounds i8, i8* %.08, i64 1
358   store i8 %8, i8* %9, align 1
359   %10 = getelementptr inbounds i8, i8* %.08, i64 2
360   %11 = add nsw i32 %.09, -1
361   %12 = icmp eq i32 %11, 0
362   br i1 %12, label %13, label %1
363
364 ; <label>:13
365   ret void
366 }
367
368 ; Make sure that we merge the consecutive load/store sequence below and use a
369 ; word (16 bit) instead of a byte copy even if there are intermediate sign
370 ; extensions.
371 ; CHECK-LABEL: MergeLoadStoreBaseIndexOffsetSext:
372 ; CHECK: movw    (%{{.*}},%{{.*}}), [[REG:%[a-z]+]]
373 ; CHECK: movw    [[REG]], (%{{.*}})
374 define void @MergeLoadStoreBaseIndexOffsetSext(i8* %a, i8* %b, i8* %c, i32 %n) {
375   br label %1
376
377 ; <label>:1
378   %.09 = phi i32 [ %n, %0 ], [ %12, %1 ]
379   %.08 = phi i8* [ %b, %0 ], [ %11, %1 ]
380   %.0 = phi i8* [ %a, %0 ], [ %2, %1 ]
381   %2 = getelementptr inbounds i8, i8* %.0, i64 1
382   %3 = load i8, i8* %.0, align 1
383   %4 = sext i8 %3 to i64
384   %5 = getelementptr inbounds i8, i8* %c, i64 %4
385   %6 = load i8, i8* %5, align 1
386   %7 = add i64 %4, 1
387   %8 = getelementptr inbounds i8, i8* %c, i64 %7
388   %9 = load i8, i8* %8, align 1
389   store i8 %6, i8* %.08, align 1
390   %10 = getelementptr inbounds i8, i8* %.08, i64 1
391   store i8 %9, i8* %10, align 1
392   %11 = getelementptr inbounds i8, i8* %.08, i64 2
393   %12 = add nsw i32 %.09, -1
394   %13 = icmp eq i32 %12, 0
395   br i1 %13, label %14, label %1
396
397 ; <label>:14
398   ret void
399 }
400
401 ; However, we can only merge ignore sign extensions when they are on all memory
402 ; computations;
403 ; CHECK-LABEL: loadStoreBaseIndexOffsetSextNoSex:
404 ; CHECK-NOT: movw    (%{{.*}},%{{.*}}), [[REG:%[a-z]+]]
405 ; CHECK-NOT: movw    [[REG]], (%{{.*}})
406 define void @loadStoreBaseIndexOffsetSextNoSex(i8* %a, i8* %b, i8* %c, i32 %n) {
407   br label %1
408
409 ; <label>:1
410   %.09 = phi i32 [ %n, %0 ], [ %12, %1 ]
411   %.08 = phi i8* [ %b, %0 ], [ %11, %1 ]
412   %.0 = phi i8* [ %a, %0 ], [ %2, %1 ]
413   %2 = getelementptr inbounds i8, i8* %.0, i64 1
414   %3 = load i8, i8* %.0, align 1
415   %4 = sext i8 %3 to i64
416   %5 = getelementptr inbounds i8, i8* %c, i64 %4
417   %6 = load i8, i8* %5, align 1
418   %7 = add i8 %3, 1
419   %wrap.4 = sext i8 %7 to i64
420   %8 = getelementptr inbounds i8, i8* %c, i64 %wrap.4
421   %9 = load i8, i8* %8, align 1
422   store i8 %6, i8* %.08, align 1
423   %10 = getelementptr inbounds i8, i8* %.08, i64 1
424   store i8 %9, i8* %10, align 1
425   %11 = getelementptr inbounds i8, i8* %.08, i64 2
426   %12 = add nsw i32 %.09, -1
427   %13 = icmp eq i32 %12, 0
428   br i1 %13, label %14, label %1
429
430 ; <label>:14
431   ret void
432 }
433
434 ; PR21711 ( http://llvm.org/bugs/show_bug.cgi?id=21711 )
435 define void @merge_vec_element_store(<8 x float> %v, float* %ptr) {
436   %vecext0 = extractelement <8 x float> %v, i32 0
437   %vecext1 = extractelement <8 x float> %v, i32 1
438   %vecext2 = extractelement <8 x float> %v, i32 2
439   %vecext3 = extractelement <8 x float> %v, i32 3
440   %vecext4 = extractelement <8 x float> %v, i32 4
441   %vecext5 = extractelement <8 x float> %v, i32 5
442   %vecext6 = extractelement <8 x float> %v, i32 6
443   %vecext7 = extractelement <8 x float> %v, i32 7
444   %arrayidx1 = getelementptr inbounds float, float* %ptr, i64 1
445   %arrayidx2 = getelementptr inbounds float, float* %ptr, i64 2
446   %arrayidx3 = getelementptr inbounds float, float* %ptr, i64 3
447   %arrayidx4 = getelementptr inbounds float, float* %ptr, i64 4
448   %arrayidx5 = getelementptr inbounds float, float* %ptr, i64 5
449   %arrayidx6 = getelementptr inbounds float, float* %ptr, i64 6
450   %arrayidx7 = getelementptr inbounds float, float* %ptr, i64 7
451   store float %vecext0, float* %ptr, align 4
452   store float %vecext1, float* %arrayidx1, align 4
453   store float %vecext2, float* %arrayidx2, align 4
454   store float %vecext3, float* %arrayidx3, align 4
455   store float %vecext4, float* %arrayidx4, align 4
456   store float %vecext5, float* %arrayidx5, align 4
457   store float %vecext6, float* %arrayidx6, align 4
458   store float %vecext7, float* %arrayidx7, align 4
459   ret void
460
461 ; CHECK-LABEL: merge_vec_element_store
462 ; CHECK: vmovups
463 ; CHECK-NEXT: vzeroupper
464 ; CHECK-NEXT: retq
465 }
466
467 ; PR21711 - Merge vector stores into wider vector stores.
468 ; These should be merged into 32-byte stores.
469 define void @merge_vec_extract_stores(<8 x float> %v1, <8 x float> %v2, <4 x float>* %ptr) {
470   %idx0 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 3
471   %idx1 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 4
472   %idx2 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 5
473   %idx3 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 6
474   %shuffle0 = shufflevector <8 x float> %v1, <8 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
475   %shuffle1 = shufflevector <8 x float> %v1, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
476   %shuffle2 = shufflevector <8 x float> %v2, <8 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
477   %shuffle3 = shufflevector <8 x float> %v2, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
478   store <4 x float> %shuffle0, <4 x float>* %idx0, align 16
479   store <4 x float> %shuffle1, <4 x float>* %idx1, align 16
480   store <4 x float> %shuffle2, <4 x float>* %idx2, align 16
481   store <4 x float> %shuffle3, <4 x float>* %idx3, align 16
482   ret void
483
484 ; CHECK-LABEL: merge_vec_extract_stores
485 ; CHECK:      vmovups %ymm0, 48(%rdi)
486 ; CHECK-NEXT: vmovups %ymm1, 80(%rdi)
487 ; CHECK-NEXT: vzeroupper
488 ; CHECK-NEXT: retq
489 }
490
491 ; Merging vector stores when sourced from vector loads is not currently handled.
492 define void @merge_vec_stores_from_loads(<4 x float>* %v, <4 x float>* %ptr) {
493   %load_idx0 = getelementptr inbounds <4 x float>, <4 x float>* %v, i64 0
494   %load_idx1 = getelementptr inbounds <4 x float>, <4 x float>* %v, i64 1
495   %v0 = load <4 x float>, <4 x float>* %load_idx0
496   %v1 = load <4 x float>, <4 x float>* %load_idx1
497   %store_idx0 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 0
498   %store_idx1 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 1
499   store <4 x float> %v0, <4 x float>* %store_idx0, align 16
500   store <4 x float> %v1, <4 x float>* %store_idx1, align 16
501   ret void
502
503 ; CHECK-LABEL: merge_vec_stores_from_loads
504 ; CHECK:      vmovaps
505 ; CHECK-NEXT: vmovaps
506 ; CHECK-NEXT: vmovaps
507 ; CHECK-NEXT: vmovaps
508 ; CHECK-NEXT: retq
509 }
510
511 ; Merging vector stores when sourced from a constant vector is not currently handled. 
512 define void @merge_vec_stores_of_constants(<4 x i32>* %ptr) {
513   %idx0 = getelementptr inbounds <4 x i32>, <4 x i32>* %ptr, i64 3
514   %idx1 = getelementptr inbounds <4 x i32>, <4 x i32>* %ptr, i64 4
515   store <4 x i32> <i32 0, i32 0, i32 0, i32 0>, <4 x i32>* %idx0, align 16
516   store <4 x i32> <i32 0, i32 0, i32 0, i32 0>, <4 x i32>* %idx1, align 16
517   ret void
518
519 ; CHECK-LABEL: merge_vec_stores_of_constants
520 ; CHECK:      vxorps
521 ; CHECK-NEXT: vmovaps
522 ; CHECK-NEXT: vmovaps
523 ; CHECK-NEXT: retq
524 }
525
526 ; This is a minimized test based on real code that was failing.
527 ; We could merge stores (and loads) like this...
528
529 define void @merge_vec_element_and_scalar_load([6 x i64]* %array) {
530   %idx0 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 0
531   %idx1 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 1
532   %idx4 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 4
533   %idx5 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 5
534
535   %a0 = load i64, i64* %idx0, align 8
536   store i64 %a0, i64* %idx4, align 8
537
538   %b = bitcast i64* %idx1 to <2 x i64>*
539   %v = load <2 x i64>, <2 x i64>* %b, align 8
540   %a1 = extractelement <2 x i64> %v, i32 0
541   store i64 %a1, i64* %idx5, align 8
542   ret void
543
544 ; CHECK-LABEL: merge_vec_element_and_scalar_load
545 ; CHECK:      movq      (%rdi), %rax
546 ; CHECK-NEXT: movq      %rax, 32(%rdi)
547 ; CHECK-NEXT: movq      8(%rdi), %rax
548 ; CHECK-NEXT: movq      %rax, 40(%rdi)
549 ; CHECK-NEXT: retq
550 }