use CHECK-LABEL for more precision
[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 can be merged to vector ops.
292 ; CHECK-LABEL: merge_loads_no_align:
293 ;  load:
294 ; CHECK: vmovups
295 ;  store:
296 ; CHECK: vmovups
297 ; CHECK: ret
298 define void @merge_loads_no_align(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
299   %a1 = icmp sgt i32 %count, 0
300   br i1 %a1, label %.lr.ph, label %._crit_edge
301
302 .lr.ph:                                           ; preds = %0
303   %a2 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 0
304   %a3 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 1
305   %a4 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 2
306   %a5 = getelementptr inbounds %struct.B, %struct.B* %q, i64 0, i32 3
307   br label %block4
308
309 block4:                                       ; preds = %4, %.lr.ph
310   %i.02 = phi i32 [ 0, %.lr.ph ], [ %c9, %block4 ]
311   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %c10, %block4 ]
312   %a7 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 0
313   %a8 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 1
314   %a9 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 2
315   %a10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 0, i32 3
316   %b1 = load i32, i32* %a2, align 1
317   %b2 = load i32, i32* %a3, align 1
318   %b3 = load i32, i32* %a4, align 1
319   %b4 = load i32, i32* %a5, align 1
320   store i32 %b1, i32* %a7, align 1
321   store i32 %b2, i32* %a8, align 1
322   store i32 %b3, i32* %a9, align 1
323   store i32 %b4, i32* %a10, align 1
324   %c9 = add nsw i32 %i.02, 1
325   %c10 = getelementptr inbounds %struct.B, %struct.B* %.01, i64 1
326   %exitcond = icmp eq i32 %c9, %count
327   br i1 %exitcond, label %._crit_edge, label %block4
328
329 ._crit_edge:                                      ; preds = %4, %0
330   ret void
331 }
332
333 ; Make sure that we merge the consecutive load/store sequence below and use a
334 ; word (16 bit) instead of a byte copy.
335 ; CHECK-LABEL: MergeLoadStoreBaseIndexOffset:
336 ; CHECK: movw    (%{{.*}},%{{.*}}), [[REG:%[a-z]+]]
337 ; CHECK: movw    [[REG]], (%{{.*}})
338 define void @MergeLoadStoreBaseIndexOffset(i64* %a, i8* %b, i8* %c, i32 %n) {
339   br label %1
340
341 ; <label>:1
342   %.09 = phi i32 [ %n, %0 ], [ %11, %1 ]
343   %.08 = phi i8* [ %b, %0 ], [ %10, %1 ]
344   %.0 = phi i64* [ %a, %0 ], [ %2, %1 ]
345   %2 = getelementptr inbounds i64, i64* %.0, i64 1
346   %3 = load i64, i64* %.0, align 1
347   %4 = getelementptr inbounds i8, i8* %c, i64 %3
348   %5 = load i8, i8* %4, align 1
349   %6 = add i64 %3, 1
350   %7 = getelementptr inbounds i8, i8* %c, i64 %6
351   %8 = load i8, i8* %7, align 1
352   store i8 %5, i8* %.08, align 1
353   %9 = getelementptr inbounds i8, i8* %.08, i64 1
354   store i8 %8, i8* %9, align 1
355   %10 = getelementptr inbounds i8, i8* %.08, i64 2
356   %11 = add nsw i32 %.09, -1
357   %12 = icmp eq i32 %11, 0
358   br i1 %12, label %13, label %1
359
360 ; <label>:13
361   ret void
362 }
363
364 ; Make sure that we merge the consecutive load/store sequence below and use a
365 ; word (16 bit) instead of a byte copy even if there are intermediate sign
366 ; extensions.
367 ; CHECK-LABEL: MergeLoadStoreBaseIndexOffsetSext:
368 ; CHECK: movw    (%{{.*}},%{{.*}}), [[REG:%[a-z]+]]
369 ; CHECK: movw    [[REG]], (%{{.*}})
370 define void @MergeLoadStoreBaseIndexOffsetSext(i8* %a, i8* %b, i8* %c, i32 %n) {
371   br label %1
372
373 ; <label>:1
374   %.09 = phi i32 [ %n, %0 ], [ %12, %1 ]
375   %.08 = phi i8* [ %b, %0 ], [ %11, %1 ]
376   %.0 = phi i8* [ %a, %0 ], [ %2, %1 ]
377   %2 = getelementptr inbounds i8, i8* %.0, i64 1
378   %3 = load i8, i8* %.0, align 1
379   %4 = sext i8 %3 to i64
380   %5 = getelementptr inbounds i8, i8* %c, i64 %4
381   %6 = load i8, i8* %5, align 1
382   %7 = add i64 %4, 1
383   %8 = getelementptr inbounds i8, i8* %c, i64 %7
384   %9 = load i8, i8* %8, align 1
385   store i8 %6, i8* %.08, align 1
386   %10 = getelementptr inbounds i8, i8* %.08, i64 1
387   store i8 %9, i8* %10, align 1
388   %11 = getelementptr inbounds i8, i8* %.08, i64 2
389   %12 = add nsw i32 %.09, -1
390   %13 = icmp eq i32 %12, 0
391   br i1 %13, label %14, label %1
392
393 ; <label>:14
394   ret void
395 }
396
397 ; However, we can only merge ignore sign extensions when they are on all memory
398 ; computations;
399 ; CHECK-LABEL: loadStoreBaseIndexOffsetSextNoSex:
400 ; CHECK-NOT: movw    (%{{.*}},%{{.*}}), [[REG:%[a-z]+]]
401 ; CHECK-NOT: movw    [[REG]], (%{{.*}})
402 define void @loadStoreBaseIndexOffsetSextNoSex(i8* %a, i8* %b, i8* %c, i32 %n) {
403   br label %1
404
405 ; <label>:1
406   %.09 = phi i32 [ %n, %0 ], [ %12, %1 ]
407   %.08 = phi i8* [ %b, %0 ], [ %11, %1 ]
408   %.0 = phi i8* [ %a, %0 ], [ %2, %1 ]
409   %2 = getelementptr inbounds i8, i8* %.0, i64 1
410   %3 = load i8, i8* %.0, align 1
411   %4 = sext i8 %3 to i64
412   %5 = getelementptr inbounds i8, i8* %c, i64 %4
413   %6 = load i8, i8* %5, align 1
414   %7 = add i8 %3, 1
415   %wrap.4 = sext i8 %7 to i64
416   %8 = getelementptr inbounds i8, i8* %c, i64 %wrap.4
417   %9 = load i8, i8* %8, align 1
418   store i8 %6, i8* %.08, align 1
419   %10 = getelementptr inbounds i8, i8* %.08, i64 1
420   store i8 %9, i8* %10, align 1
421   %11 = getelementptr inbounds i8, i8* %.08, i64 2
422   %12 = add nsw i32 %.09, -1
423   %13 = icmp eq i32 %12, 0
424   br i1 %13, label %14, label %1
425
426 ; <label>:14
427   ret void
428 }
429
430 ; PR21711 ( http://llvm.org/bugs/show_bug.cgi?id=21711 )
431 define void @merge_vec_element_store(<8 x float> %v, float* %ptr) {
432   %vecext0 = extractelement <8 x float> %v, i32 0
433   %vecext1 = extractelement <8 x float> %v, i32 1
434   %vecext2 = extractelement <8 x float> %v, i32 2
435   %vecext3 = extractelement <8 x float> %v, i32 3
436   %vecext4 = extractelement <8 x float> %v, i32 4
437   %vecext5 = extractelement <8 x float> %v, i32 5
438   %vecext6 = extractelement <8 x float> %v, i32 6
439   %vecext7 = extractelement <8 x float> %v, i32 7
440   %arrayidx1 = getelementptr inbounds float, float* %ptr, i64 1
441   %arrayidx2 = getelementptr inbounds float, float* %ptr, i64 2
442   %arrayidx3 = getelementptr inbounds float, float* %ptr, i64 3
443   %arrayidx4 = getelementptr inbounds float, float* %ptr, i64 4
444   %arrayidx5 = getelementptr inbounds float, float* %ptr, i64 5
445   %arrayidx6 = getelementptr inbounds float, float* %ptr, i64 6
446   %arrayidx7 = getelementptr inbounds float, float* %ptr, i64 7
447   store float %vecext0, float* %ptr, align 4
448   store float %vecext1, float* %arrayidx1, align 4
449   store float %vecext2, float* %arrayidx2, align 4
450   store float %vecext3, float* %arrayidx3, align 4
451   store float %vecext4, float* %arrayidx4, align 4
452   store float %vecext5, float* %arrayidx5, align 4
453   store float %vecext6, float* %arrayidx6, align 4
454   store float %vecext7, float* %arrayidx7, align 4
455   ret void
456
457 ; CHECK-LABEL: merge_vec_element_store
458 ; CHECK: vmovups
459 ; CHECK-NEXT: vzeroupper
460 ; CHECK-NEXT: retq
461 }
462
463 ; PR21711 - Merge vector stores into wider vector stores.
464 ; These should be merged into 32-byte stores.
465 define void @merge_vec_extract_stores(<8 x float> %v1, <8 x float> %v2, <4 x float>* %ptr) {
466   %idx0 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 3
467   %idx1 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 4
468   %idx2 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 5
469   %idx3 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 6
470   %shuffle0 = shufflevector <8 x float> %v1, <8 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
471   %shuffle1 = shufflevector <8 x float> %v1, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
472   %shuffle2 = shufflevector <8 x float> %v2, <8 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
473   %shuffle3 = shufflevector <8 x float> %v2, <8 x float> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
474   store <4 x float> %shuffle0, <4 x float>* %idx0, align 16
475   store <4 x float> %shuffle1, <4 x float>* %idx1, align 16
476   store <4 x float> %shuffle2, <4 x float>* %idx2, align 16
477   store <4 x float> %shuffle3, <4 x float>* %idx3, align 16
478   ret void
479
480 ; CHECK-LABEL: merge_vec_extract_stores
481 ; CHECK:      vmovaps %xmm0, 48(%rdi)
482 ; CHECK-NEXT: vextractf128 $1, %ymm0, 64(%rdi)
483 ; CHECK-NEXT: vmovaps %xmm1, 80(%rdi)
484 ; CHECK-NEXT: vextractf128 $1, %ymm1, 96(%rdi)
485 ; CHECK-NEXT: vzeroupper
486 ; CHECK-NEXT: retq
487 }
488
489 ; Merging vector stores when sourced from vector loads is not currently handled.
490 define void @merge_vec_stores_from_loads(<4 x float>* %v, <4 x float>* %ptr) {
491   %load_idx0 = getelementptr inbounds <4 x float>, <4 x float>* %v, i64 0
492   %load_idx1 = getelementptr inbounds <4 x float>, <4 x float>* %v, i64 1
493   %v0 = load <4 x float>, <4 x float>* %load_idx0
494   %v1 = load <4 x float>, <4 x float>* %load_idx1
495   %store_idx0 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 0
496   %store_idx1 = getelementptr inbounds <4 x float>, <4 x float>* %ptr, i64 1
497   store <4 x float> %v0, <4 x float>* %store_idx0, align 16
498   store <4 x float> %v1, <4 x float>* %store_idx1, align 16
499   ret void
500
501 ; CHECK-LABEL: merge_vec_stores_from_loads
502 ; CHECK:      vmovaps
503 ; CHECK-NEXT: vmovaps
504 ; CHECK-NEXT: vmovaps
505 ; CHECK-NEXT: vmovaps
506 ; CHECK-NEXT: retq
507 }
508
509 ; Merging vector stores when sourced from a constant vector is not currently handled. 
510 define void @merge_vec_stores_of_constants(<4 x i32>* %ptr) {
511   %idx0 = getelementptr inbounds <4 x i32>, <4 x i32>* %ptr, i64 3
512   %idx1 = getelementptr inbounds <4 x i32>, <4 x i32>* %ptr, i64 4
513   store <4 x i32> <i32 0, i32 0, i32 0, i32 0>, <4 x i32>* %idx0, align 16
514   store <4 x i32> <i32 0, i32 0, i32 0, i32 0>, <4 x i32>* %idx1, align 16
515   ret void
516
517 ; CHECK-LABEL: merge_vec_stores_of_constants
518 ; CHECK:      vxorps
519 ; CHECK-NEXT: vmovaps
520 ; CHECK-NEXT: vmovaps
521 ; CHECK-NEXT: retq
522 }
523
524 ; This is a minimized test based on real code that was failing.
525 ; We could merge stores (and loads) like this...
526
527 define void @merge_vec_element_and_scalar_load([6 x i64]* %array) {
528   %idx0 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 0
529   %idx1 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 1
530   %idx4 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 4
531   %idx5 = getelementptr inbounds [6 x i64], [6 x i64]* %array, i64 0, i64 5
532
533   %a0 = load i64, i64* %idx0, align 8
534   store i64 %a0, i64* %idx4, align 8
535
536   %b = bitcast i64* %idx1 to <2 x i64>*
537   %v = load <2 x i64>, <2 x i64>* %b, align 8
538   %a1 = extractelement <2 x i64> %v, i32 0
539   store i64 %a1, i64* %idx5, align 8
540   ret void
541
542 ; CHECK-LABEL: merge_vec_element_and_scalar_load
543 ; CHECK:      movq      (%rdi), %rax
544 ; CHECK-NEXT: movq      %rax, 32(%rdi)
545 ; CHECK-NEXT: movq      8(%rdi), %rax
546 ; CHECK-NEXT: movq      %rax, 40(%rdi)
547 ; CHECK-NEXT: retq
548 }