[X86] Call frame optimization - allow stack-relative movs to be folded into a push
[oota-llvm.git] / test / CodeGen / X86 / movtopush.ll
1 ; RUN: llc < %s -mtriple=i686-windows | FileCheck %s -check-prefix=NORMAL
2 ; RUN: llc < %s -mtriple=x86_64-windows | FileCheck %s -check-prefix=X64
3 ; RUN: llc < %s -mtriple=i686-windows -force-align-stack -stack-alignment=32 | FileCheck %s -check-prefix=ALIGNED 
4
5 declare void @good(i32 %a, i32 %b, i32 %c, i32 %d)
6 declare void @inreg(i32 %a, i32 inreg %b, i32 %c, i32 %d)
7 declare void @oneparam(i32 %a)
8 declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
9
10
11 ; Here, we should have a reserved frame, so we don't expect pushes
12 ; NORMAL-LABEL: test1:
13 ; NORMAL: subl    $16, %esp
14 ; NORMAL-NEXT: movl    $4, 12(%esp)
15 ; NORMAL-NEXT: movl    $3, 8(%esp)
16 ; NORMAL-NEXT: movl    $2, 4(%esp)
17 ; NORMAL-NEXT: movl    $1, (%esp)
18 ; NORMAL-NEXT: call
19 ; NORMAL-NEXT: addl $16, %esp
20 define void @test1() {
21 entry:
22   call void @good(i32 1, i32 2, i32 3, i32 4)
23   ret void
24 }
25
26 ; We're optimizing for code size, so we should get pushes for x86,
27 ; even though there is a reserved call frame.
28 ; Make sure we don't touch x86-64
29 ; NORMAL-LABEL: test1b:
30 ; NORMAL-NOT: subl {{.*}} %esp
31 ; NORMAL: pushl   $4
32 ; NORMAL-NEXT: pushl   $3
33 ; NORMAL-NEXT: pushl   $2
34 ; NORMAL-NEXT: pushl   $1
35 ; NORMAL-NEXT: call
36 ; NORMAL-NEXT: addl $16, %esp
37 ; X64-LABEL: test1b:
38 ; X64: movl    $1, %ecx
39 ; X64-NEXT: movl    $2, %edx
40 ; X64-NEXT: movl    $3, %r8d
41 ; X64-NEXT: movl    $4, %r9d
42 ; X64-NEXT: callq   good
43 define void @test1b() optsize {
44 entry:
45   call void @good(i32 1, i32 2, i32 3, i32 4)
46   ret void
47 }
48
49 ; Same as above, but for minsize
50 ; NORMAL-LABEL: test1c:
51 ; NORMAL-NOT: subl {{.*}} %esp
52 ; NORMAL: pushl   $4
53 ; NORMAL-NEXT: pushl   $3
54 ; NORMAL-NEXT: pushl   $2
55 ; NORMAL-NEXT: pushl   $1
56 ; NORMAL-NEXT: call
57 ; NORMAL-NEXT: addl $16, %esp
58 define void @test1c() minsize {
59 entry:
60   call void @good(i32 1, i32 2, i32 3, i32 4)
61   ret void
62 }
63
64 ; If we have a reserved frame, we should have pushes
65 ; NORMAL-LABEL: test2:
66 ; NORMAL-NOT: subl {{.*}} %esp
67 ; NORMAL: pushl   $4
68 ; NORMAL-NEXT: pushl   $3
69 ; NORMAL-NEXT: pushl   $2
70 ; NORMAL-NEXT: pushl   $1
71 ; NORMAL-NEXT: call
72 define void @test2(i32 %k) {
73 entry:
74   %a = alloca i32, i32 %k
75   call void @good(i32 1, i32 2, i32 3, i32 4)
76   ret void
77 }
78
79 ; Again, we expect a sequence of 4 immediate pushes
80 ; Checks that we generate the right pushes for >8bit immediates
81 ; NORMAL-LABEL: test2b:
82 ; NORMAL-NOT: subl {{.*}} %esp
83 ; NORMAL: pushl   $4096
84 ; NORMAL-NEXT: pushl   $3072
85 ; NORMAL-NEXT: pushl   $2048
86 ; NORMAL-NEXT: pushl   $1024
87 ; NORMAL-NEXT: call
88 ; NORMAL-NEXT: addl $16, %esp
89 define void @test2b() optsize {
90 entry:
91   call void @good(i32 1024, i32 2048, i32 3072, i32 4096)
92   ret void
93 }
94
95 ; The first push should push a register
96 ; NORMAL-LABEL: test3:
97 ; NORMAL-NOT: subl {{.*}} %esp
98 ; NORMAL: pushl   $4
99 ; NORMAL-NEXT: pushl   $3
100 ; NORMAL-NEXT: pushl   $2
101 ; NORMAL-NEXT: pushl   %e{{..}}
102 ; NORMAL-NEXT: call
103 ; NORMAL-NEXT: addl $16, %esp
104 define void @test3(i32 %k) optsize {
105 entry:
106   %f = add i32 %k, 1
107   call void @good(i32 %f, i32 2, i32 3, i32 4)
108   ret void
109 }
110
111 ; We don't support weird calling conventions
112 ; NORMAL-LABEL: test4:
113 ; NORMAL: subl    $12, %esp
114 ; NORMAL-NEXT: movl    $4, 8(%esp)
115 ; NORMAL-NEXT: movl    $3, 4(%esp)
116 ; NORMAL-NEXT: movl    $1, (%esp)
117 ; NORMAL-NEXT: movl    $2, %eax
118 ; NORMAL-NEXT: call
119 ; NORMAL-NEXT: addl $12, %esp
120 define void @test4() optsize {
121 entry:
122   call void @inreg(i32 1, i32 2, i32 3, i32 4)
123   ret void
124 }
125
126 ; When there is no reserved call frame, check that additional alignment
127 ; is added when the pushes don't add up to the required alignment.
128 ; ALIGNED-LABEL: test5:
129 ; ALIGNED: subl    $16, %esp
130 ; ALIGNED-NEXT: pushl   $4
131 ; ALIGNED-NEXT: pushl   $3
132 ; ALIGNED-NEXT: pushl   $2
133 ; ALIGNED-NEXT: pushl   $1
134 ; ALIGNED-NEXT: call
135 define void @test5(i32 %k) {
136 entry:
137   %a = alloca i32, i32 %k
138   call void @good(i32 1, i32 2, i32 3, i32 4)
139   ret void
140 }
141
142 ; When the alignment adds up, do the transformation
143 ; ALIGNED-LABEL: test5b:
144 ; ALIGNED: pushl   $8
145 ; ALIGNED-NEXT: pushl   $7
146 ; ALIGNED-NEXT: pushl   $6
147 ; ALIGNED-NEXT: pushl   $5
148 ; ALIGNED-NEXT: pushl   $4
149 ; ALIGNED-NEXT: pushl   $3
150 ; ALIGNED-NEXT: pushl   $2
151 ; ALIGNED-NEXT: pushl   $1
152 ; ALIGNED-NEXT: call
153 define void @test5b() optsize {
154 entry:
155   call void @eightparams(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8)
156   ret void
157 }
158
159 ; When having to compensate for the alignment isn't worth it,
160 ; don't use pushes.
161 ; ALIGNED-LABEL: test5c:
162 ; ALIGNED: movl $1, (%esp)
163 ; ALIGNED-NEXT: call
164 define void @test5c() optsize {
165 entry:
166   call void @oneparam(i32 1)
167   ret void
168 }
169
170 ; Check that pushing the addresses of globals (Or generally, things that 
171 ; aren't exactly immediates) isn't broken.
172 ; Fixes PR21878.
173 ; NORMAL-LABEL: test6:
174 ; NORMAL: pushl    $_ext
175 ; NORMAL-NEXT: call
176 declare void @f(i8*)
177 @ext = external constant i8
178
179 define void @test6() {
180   call void @f(i8* @ext)
181   br label %bb
182 bb:
183   alloca i32
184   ret void
185 }
186
187 ; Check that we fold simple cases into the push
188 ; NORMAL-LABEL: test7:
189 ; NORMAL-NOT: subl {{.*}} %esp
190 ; NORMAL: movl 4(%esp), [[EAX:%e..]]
191 ; NORMAL-NEXT: pushl   $4
192 ; NORMAL-NEXT: pushl   ([[EAX]])
193 ; NORMAL-NEXT: pushl   $2
194 ; NORMAL-NEXT: pushl   $1
195 ; NORMAL-NEXT: call
196 ; NORMAL-NEXT: addl $16, %esp
197 define void @test7(i32* %ptr) optsize {
198 entry:
199   %val = load i32* %ptr
200   call void @good(i32 1, i32 2, i32 %val, i32 4)
201   ret void
202 }
203
204 ; Fold stack-relative loads into the push, with correct offset
205 ; In particular, at the second push, %b was at 12(%esp) and
206 ; %a wast at 8(%esp), but the second push bumped %esp, so %a
207 ; is now it at 12(%esp)
208 ; NORMAL-LABEL: test8:
209 ; NORMAL: pushl   $4
210 ; NORMAL-NEXT: pushl   12(%esp)
211 ; NORMAL-NEXT: pushl   12(%esp)
212 ; NORMAL-NEXT: pushl   $1
213 ; NORMAL-NEXT: call
214 ; NORMAL-NEXT: addl $16, %esp
215 define void @test8(i32 %a, i32 %b) optsize {
216 entry:
217   call void @good(i32 1, i32 %a, i32 %b, i32 4)
218   ret void
219 }
220
221 ; If one function is using push instructions, and the other isn't
222 ; (because it has frame-index references), then we must resolve
223 ; these references correctly.
224 ; NORMAL-LABEL: test9:
225 ; NORMAL-NOT: leal (%esp), 
226 ; NORMAL: pushl $4
227 ; NORMAL-NEXT: pushl $3
228 ; NORMAL-NEXT: pushl $2
229 ; NORMAL-NEXT: pushl $1
230 ; NORMAL-NEXT: call
231 ; NORMAL-NEXT: addl $16, %esp
232 ; NORMAL-NEXT: subl $16, %esp
233 ; NORMAL-NEXT: leal 16(%esp), [[EAX:%e..]]
234 ; NORMAL-NEXT: movl    [[EAX]], 12(%esp)
235 ; NORMAL-NEXT: movl    $7, 8(%esp)
236 ; NORMAL-NEXT: movl    $6, 4(%esp)
237 ; NORMAL-NEXT: movl    $5, (%esp)
238 ; NORMAL-NEXT: call
239 ; NORMAL-NEXT: addl $16, %esp
240 define void @test9() optsize {
241 entry:
242   %p = alloca i32, align 4
243   call void @good(i32 1, i32 2, i32 3, i32 4)
244   %0 = ptrtoint i32* %p to i32
245   call void @good(i32 5, i32 6, i32 7, i32 %0)
246   ret void
247 }
248
249 ; We can end up with an indirect call which gets reloaded on the spot.
250 ; Make sure we reference the correct stack slot - we spill into (%esp)
251 ; and reload from 16(%esp) due to the pushes.
252 ; NORMAL-LABEL: test10:
253 ; NORMAL: movl $_good, [[ALLOC:.*]]
254 ; NORMAL-NEXT: movl [[ALLOC]], [[EAX:%e..]]
255 ; NORMAL-NEXT: movl [[EAX]], (%esp) # 4-byte Spill
256 ; NORMAL: nop
257 ; NORMAL: pushl $4
258 ; NORMAL-NEXT: pushl $3
259 ; NORMAL-NEXT: pushl $2
260 ; NORMAL-NEXT: pushl $1
261 ; NORMAL-NEXT: calll *16(%esp)
262 ; NORMAL-NEXT: addl $16, %esp
263 define void @test10() optsize {
264   %stack_fptr = alloca void (i32, i32, i32, i32)*
265   store void (i32, i32, i32, i32)* @good, void (i32, i32, i32, i32)** %stack_fptr
266   %good_ptr = load volatile void (i32, i32, i32, i32)** %stack_fptr
267   call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di}"()
268   call void (i32, i32, i32, i32)* %good_ptr(i32 1, i32 2, i32 3, i32 4)
269   ret void
270 }
271
272 ; We can't fold the load from the global into the push because of 
273 ; interference from the store
274 ; NORMAL-LABEL: test11:
275 ; NORMAL: movl    _the_global, [[EAX:%e..]]
276 ; NORMAL-NEXT: movl    $42, _the_global
277 ; NORMAL-NEXT: pushl $4
278 ; NORMAL-NEXT: pushl $3
279 ; NORMAL-NEXT: pushl $2
280 ; NORMAL-NEXT: pushl [[EAX]]
281 ; NORMAL-NEXT: call
282 ; NORMAL-NEXT: addl $16, %esp
283 @the_global = external global i32
284 define void @test11() optsize {
285   %myload = load i32* @the_global
286   store i32 42, i32* @the_global
287   call void @good(i32 %myload, i32 2, i32 3, i32 4)
288   ret void
289 }
290
291 ; Converting one mov into a push isn't worth it when 
292 ; doing so forces too much overhead for other calls.
293 ; NORMAL-LABEL: test12:
294 ; NORMAL: subl    $16, %esp
295 ; NORMAL-NEXT: movl    $4, 8(%esp)
296 ; NORMAL-NEXT: movl    $3, 4(%esp)
297 ; NORMAL-NEXT: movl    $1, (%esp)
298 ; NORMAL-NEXT: movl    $2, %eax
299 ; NORMAL-NEXT: calll _inreg
300 ; NORMAL-NEXT: movl    $8, 12(%esp)
301 ; NORMAL-NEXT: movl    $7, 8(%esp)
302 ; NORMAL-NEXT: movl    $6, 4(%esp)
303 ; NORMAL-NEXT: movl    $5, (%esp)
304 ; NORMAL-NEXT: calll _good
305 ; NORMAL-NEXT: movl    $12, 8(%esp)
306 ; NORMAL-NEXT: movl    $11, 4(%esp)
307 ; NORMAL-NEXT: movl    $9, (%esp)
308 ; NORMAL-NEXT: movl    $10, %eax
309 ; NORMAL-NEXT: calll _inreg
310 ; NORMAL-NEXT: addl $16, %esp
311 define void @test12() optsize {
312 entry:
313   call void @inreg(i32 1, i32 2, i32 3, i32 4)
314   call void @good(i32 5, i32 6, i32 7, i32 8)
315   call void @inreg(i32 9, i32 10, i32 11, i32 12)
316   ret void
317 }
318
319 ; But if the gains outweigh the overhead, we should do it
320 ; NORMAL-LABEL: test12b:
321 ; NORMAL: pushl    $4
322 ; NORMAL-NEXT: pushl    $3
323 ; NORMAL-NEXT: pushl    $2
324 ; NORMAL-NEXT: pushl    $1
325 ; NORMAL-NEXT: calll _good
326 ; NORMAL-NEXT: addl    $16, %esp
327 ; NORMAL-NEXT: subl    $12, %esp
328 ; NORMAL-NEXT: movl    $8, 8(%esp)
329 ; NORMAL-NEXT: movl    $7, 4(%esp)
330 ; NORMAL-NEXT: movl    $5, (%esp)
331 ; NORMAL-NEXT: movl    $6, %eax
332 ; NORMAL-NEXT: calll _inreg
333 ; NORMAL-NEXT: addl    $12, %esp
334 ; NORMAL-NEXT: pushl    $12
335 ; NORMAL-NEXT: pushl    $11
336 ; NORMAL-NEXT: pushl    $10
337 ; NORMAL-NEXT: pushl    $9
338 ; NORMAL-NEXT: calll _good
339 ; NORMAL-NEXT: addl $16, %esp
340 define void @test12b() optsize {
341 entry:
342   call void @good(i32 1, i32 2, i32 3, i32 4)
343   call void @inreg(i32 5, i32 6, i32 7, i32 8)
344   call void @good(i32 9, i32 10, i32 11, i32 12)
345   ret void
346 }