A DAGCombine optimization for mergeing consecutive stores to memory. The optimization
[oota-llvm.git] / test / CodeGen / X86 / MergeConsecutiveStores.ll
1 ; RUN: llc -march=x86-64 -mcpu=corei7 < %s | FileCheck %s
2
3 target 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 target triple = "x86_64-apple-macosx10.8.0"
5
6 %struct.A = type { i8, i8, i8, i8, i8, i8, i8, i8 }
7 %struct.B = type { i32, i32, i32, i32, i32, i32, i32, i32 }
8
9 ; Move all of the constants using a single vector store.
10 ; CHECK: merge_const_store
11 ; save 1,2,3 ... as one big integer.
12 ; CHECK: movabsq $578437695752307201
13 ; CHECK: ret
14 define void @merge_const_store(i32 %count, %struct.A* nocapture %p) nounwind uwtable noinline ssp {
15   %1 = icmp sgt i32 %count, 0
16   br i1 %1, label %.lr.ph, label %._crit_edge
17 .lr.ph:
18   %i.02 = phi i32 [ %10, %.lr.ph ], [ 0, %0 ]
19   %.01 = phi %struct.A* [ %11, %.lr.ph ], [ %p, %0 ]
20   %2 = getelementptr inbounds %struct.A* %.01, i64 0, i32 0
21   store i8 1, i8* %2, align 1
22   %3 = getelementptr inbounds %struct.A* %.01, i64 0, i32 1
23   store i8 2, i8* %3, align 1
24   %4 = getelementptr inbounds %struct.A* %.01, i64 0, i32 2
25   store i8 3, i8* %4, align 1
26   %5 = getelementptr inbounds %struct.A* %.01, i64 0, i32 3
27   store i8 4, i8* %5, align 1
28   %6 = getelementptr inbounds %struct.A* %.01, i64 0, i32 4
29   store i8 5, i8* %6, align 1
30   %7 = getelementptr inbounds %struct.A* %.01, i64 0, i32 5
31   store i8 6, i8* %7, align 1
32   %8 = getelementptr inbounds %struct.A* %.01, i64 0, i32 6
33   store i8 7, i8* %8, align 1
34   %9 = getelementptr inbounds %struct.A* %.01, i64 0, i32 7
35   store i8 8, i8* %9, align 1
36   %10 = add nsw i32 %i.02, 1
37   %11 = getelementptr inbounds %struct.A* %.01, i64 1
38   %exitcond = icmp eq i32 %10, %count
39   br i1 %exitcond, label %._crit_edge, label %.lr.ph
40 ._crit_edge:
41   ret void
42 }
43
44 ; Move the first 4 constants as a single vector. Move the rest as scalars.
45 ; CHECK: merge_nonconst_store
46 ; CHECK: movl $67305985
47 ; CHECK: movb
48 ; CHECK: movb
49 ; CHECK: movb
50 ; CHECK: movb
51 ; CHECK: ret
52 define void @merge_nonconst_store(i32 %count, i8 %zz, %struct.A* nocapture %p) nounwind uwtable noinline ssp {
53   %1 = icmp sgt i32 %count, 0
54   br i1 %1, label %.lr.ph, label %._crit_edge
55 .lr.ph:
56   %i.02 = phi i32 [ %10, %.lr.ph ], [ 0, %0 ]
57   %.01 = phi %struct.A* [ %11, %.lr.ph ], [ %p, %0 ]
58   %2 = getelementptr inbounds %struct.A* %.01, i64 0, i32 0
59   store i8 1, i8* %2, align 1
60   %3 = getelementptr inbounds %struct.A* %.01, i64 0, i32 1
61   store i8 2, i8* %3, align 1
62   %4 = getelementptr inbounds %struct.A* %.01, i64 0, i32 2
63   store i8 3, i8* %4, align 1
64   %5 = getelementptr inbounds %struct.A* %.01, i64 0, i32 3
65   store i8 4, i8* %5, align 1
66   %6 = getelementptr inbounds %struct.A* %.01, i64 0, i32 4
67   store i8 %zz, i8* %6, align 1                     ;  <----------- Not a const;
68   %7 = getelementptr inbounds %struct.A* %.01, i64 0, i32 5
69   store i8 6, i8* %7, align 1
70   %8 = getelementptr inbounds %struct.A* %.01, i64 0, i32 6
71   store i8 7, i8* %8, align 1
72   %9 = getelementptr inbounds %struct.A* %.01, i64 0, i32 7
73   store i8 8, i8* %9, align 1
74   %10 = add nsw i32 %i.02, 1
75   %11 = getelementptr inbounds %struct.A* %.01, i64 1
76   %exitcond = icmp eq i32 %10, %count
77   br i1 %exitcond, label %._crit_edge, label %.lr.ph
78 ._crit_edge:
79   ret void
80 }
81
82
83 ;CHECK: merge_loads_i16
84 ; load:
85 ;CHECK: movw
86 ; store:
87 ;CHECK: movw
88 ;CHECK: ret
89 define void @merge_loads_i16(i32 %count, %struct.A* noalias nocapture %q, %struct.A* noalias nocapture %p) nounwind uwtable noinline ssp {
90   %1 = icmp sgt i32 %count, 0
91   br i1 %1, label %.lr.ph, label %._crit_edge
92
93 .lr.ph:                                           ; preds = %0
94   %2 = getelementptr inbounds %struct.A* %q, i64 0, i32 0
95   %3 = getelementptr inbounds %struct.A* %q, i64 0, i32 1
96   br label %4
97
98 ; <label>:4                                       ; preds = %4, %.lr.ph
99   %i.02 = phi i32 [ 0, %.lr.ph ], [ %9, %4 ]
100   %.01 = phi %struct.A* [ %p, %.lr.ph ], [ %10, %4 ]
101   %5 = load i8* %2, align 1
102   %6 = load i8* %3, align 1
103   %7 = getelementptr inbounds %struct.A* %.01, i64 0, i32 0
104   store i8 %5, i8* %7, align 1
105   %8 = getelementptr inbounds %struct.A* %.01, i64 0, i32 1
106   store i8 %6, i8* %8, align 1
107   %9 = add nsw i32 %i.02, 1
108   %10 = getelementptr inbounds %struct.A* %.01, i64 1
109   %exitcond = icmp eq i32 %9, %count
110   br i1 %exitcond, label %._crit_edge, label %4
111
112 ._crit_edge:                                      ; preds = %4, %0
113   ret void
114 }
115
116 ; The loads and the stores are interleved. Can't merge them.
117 ;CHECK: no_merge_loads
118 ;CHECK: movb
119 ;CHECK: movb
120 ;CHECK: movb
121 ;CHECK: movb
122 ;CHECK: ret
123 define void @no_merge_loads(i32 %count, %struct.A* noalias nocapture %q, %struct.A* noalias nocapture %p) nounwind uwtable noinline ssp {
124   %1 = icmp sgt i32 %count, 0
125   br i1 %1, label %.lr.ph, label %._crit_edge
126
127 .lr.ph:                                           ; preds = %0
128   %2 = getelementptr inbounds %struct.A* %q, i64 0, i32 0
129   %3 = getelementptr inbounds %struct.A* %q, i64 0, i32 1
130   br label %a4
131
132 a4:                                       ; preds = %4, %.lr.ph
133   %i.02 = phi i32 [ 0, %.lr.ph ], [ %a9, %a4 ]
134   %.01 = phi %struct.A* [ %p, %.lr.ph ], [ %a10, %a4 ]
135   %a5 = load i8* %2, align 1
136   %a7 = getelementptr inbounds %struct.A* %.01, i64 0, i32 0
137   store i8 %a5, i8* %a7, align 1
138   %a8 = getelementptr inbounds %struct.A* %.01, i64 0, i32 1
139   %a6 = load i8* %3, align 1
140   store i8 %a6, i8* %a8, align 1
141   %a9 = add nsw i32 %i.02, 1
142   %a10 = getelementptr inbounds %struct.A* %.01, i64 1
143   %exitcond = icmp eq i32 %a9, %count
144   br i1 %exitcond, label %._crit_edge, label %a4
145
146 ._crit_edge:                                      ; preds = %4, %0
147   ret void
148 }
149
150
151 ;CHECK: merge_loads_integer
152 ; load:
153 ;CHECK: movq
154 ; store:
155 ;CHECK: movq
156 ;CHECK: ret
157 define void @merge_loads_integer(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
158   %1 = icmp sgt i32 %count, 0
159   br i1 %1, label %.lr.ph, label %._crit_edge
160
161 .lr.ph:                                           ; preds = %0
162   %2 = getelementptr inbounds %struct.B* %q, i64 0, i32 0
163   %3 = getelementptr inbounds %struct.B* %q, i64 0, i32 1
164   br label %4
165
166 ; <label>:4                                       ; preds = %4, %.lr.ph
167   %i.02 = phi i32 [ 0, %.lr.ph ], [ %9, %4 ]
168   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %10, %4 ]
169   %5 = load i32* %2
170   %6 = load i32* %3
171   %7 = getelementptr inbounds %struct.B* %.01, i64 0, i32 0
172   store i32 %5, i32* %7
173   %8 = getelementptr inbounds %struct.B* %.01, i64 0, i32 1
174   store i32 %6, i32* %8
175   %9 = add nsw i32 %i.02, 1
176   %10 = getelementptr inbounds %struct.B* %.01, i64 1
177   %exitcond = icmp eq i32 %9, %count
178   br i1 %exitcond, label %._crit_edge, label %4
179
180 ._crit_edge:                                      ; preds = %4, %0
181   ret void
182 }
183
184
185 ;CHECK: merge_loads_vector
186 ; load:
187 ;CHECK: movups
188 ; store:
189 ;CHECK: movups
190 ;CHECK: ret
191 define void @merge_loads_vector(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
192   %a1 = icmp sgt i32 %count, 0
193   br i1 %a1, label %.lr.ph, label %._crit_edge
194
195 .lr.ph:                                           ; preds = %0
196   %a2 = getelementptr inbounds %struct.B* %q, i64 0, i32 0
197   %a3 = getelementptr inbounds %struct.B* %q, i64 0, i32 1
198   %a4 = getelementptr inbounds %struct.B* %q, i64 0, i32 2
199   %a5 = getelementptr inbounds %struct.B* %q, i64 0, i32 3
200   br label %block4
201
202 block4:                                       ; preds = %4, %.lr.ph
203   %i.02 = phi i32 [ 0, %.lr.ph ], [ %c9, %block4 ]
204   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %c10, %block4 ]
205   %a7 = getelementptr inbounds %struct.B* %.01, i64 0, i32 0
206   %a8 = getelementptr inbounds %struct.B* %.01, i64 0, i32 1
207   %a9 = getelementptr inbounds %struct.B* %.01, i64 0, i32 2
208   %a10 = getelementptr inbounds %struct.B* %.01, i64 0, i32 3
209   %b1 = load i32* %a2
210   %b2 = load i32* %a3
211   %b3 = load i32* %a4
212   %b4 = load i32* %a5
213   store i32 %b1, i32* %a7
214   store i32 %b2, i32* %a8
215   store i32 %b3, i32* %a9
216   store i32 %b4, i32* %a10
217   %c9 = add nsw i32 %i.02, 1
218   %c10 = getelementptr inbounds %struct.B* %.01, i64 1
219   %exitcond = icmp eq i32 %c9, %count
220   br i1 %exitcond, label %._crit_edge, label %block4
221
222 ._crit_edge:                                      ; preds = %4, %0
223   ret void
224 }
225
226
227 ;CHECK: merge_loads_no_align
228 ; load:
229 ;CHECK: movl
230 ;CHECK: movl
231 ;CHECK: movl
232 ;CHECK: movl
233 ; store:
234 ;CHECK: movl
235 ;CHECK: movl
236 ;CHECK: movl
237 ;CHECK: movl
238 ;CHECK: ret
239 define void @merge_loads_no_align(i32 %count, %struct.B* noalias nocapture %q, %struct.B* noalias nocapture %p) nounwind uwtable noinline ssp {
240   %a1 = icmp sgt i32 %count, 0
241   br i1 %a1, label %.lr.ph, label %._crit_edge
242
243 .lr.ph:                                           ; preds = %0
244   %a2 = getelementptr inbounds %struct.B* %q, i64 0, i32 0
245   %a3 = getelementptr inbounds %struct.B* %q, i64 0, i32 1
246   %a4 = getelementptr inbounds %struct.B* %q, i64 0, i32 2
247   %a5 = getelementptr inbounds %struct.B* %q, i64 0, i32 3
248   br label %block4
249
250 block4:                                       ; preds = %4, %.lr.ph
251   %i.02 = phi i32 [ 0, %.lr.ph ], [ %c9, %block4 ]
252   %.01 = phi %struct.B* [ %p, %.lr.ph ], [ %c10, %block4 ]
253   %a7 = getelementptr inbounds %struct.B* %.01, i64 0, i32 0
254   %a8 = getelementptr inbounds %struct.B* %.01, i64 0, i32 1
255   %a9 = getelementptr inbounds %struct.B* %.01, i64 0, i32 2
256   %a10 = getelementptr inbounds %struct.B* %.01, i64 0, i32 3
257   %b1 = load i32* %a2, align 1
258   %b2 = load i32* %a3, align 1
259   %b3 = load i32* %a4, align 1
260   %b4 = load i32* %a5, align 1
261   store i32 %b1, i32* %a7, align 1
262   store i32 %b2, i32* %a8, align 1
263   store i32 %b3, i32* %a9, align 1
264   store i32 %b4, i32* %a10, align 1
265   %c9 = add nsw i32 %i.02, 1
266   %c10 = getelementptr inbounds %struct.B* %.01, i64 1
267   %exitcond = icmp eq i32 %c9, %count
268   br i1 %exitcond, label %._crit_edge, label %block4
269
270 ._crit_edge:                                      ; preds = %4, %0
271   ret void
272 }
273