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
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)
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)
19 ; NORMAL-NEXT: addl $16, %esp
20 define void @test1() {
22 call void @good(i32 1, i32 2, i32 3, i32 4)
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
32 ; NORMAL-NEXT: pushl $3
33 ; NORMAL-NEXT: pushl $2
34 ; NORMAL-NEXT: pushl $1
36 ; NORMAL-NEXT: addl $16, %esp
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 {
45 call void @good(i32 1, i32 2, i32 3, i32 4)
49 ; Same as above, but for minsize
50 ; NORMAL-LABEL: test1c:
51 ; NORMAL-NOT: subl {{.*}} %esp
53 ; NORMAL-NEXT: pushl $3
54 ; NORMAL-NEXT: pushl $2
55 ; NORMAL-NEXT: pushl $1
57 ; NORMAL-NEXT: addl $16, %esp
58 define void @test1c() minsize {
60 call void @good(i32 1, i32 2, i32 3, i32 4)
64 ; If we have a reserved frame, we should have pushes
65 ; NORMAL-LABEL: test2:
66 ; NORMAL-NOT: subl {{.*}} %esp
68 ; NORMAL-NEXT: pushl $3
69 ; NORMAL-NEXT: pushl $2
70 ; NORMAL-NEXT: pushl $1
72 define void @test2(i32 %k) {
74 %a = alloca i32, i32 %k
75 call void @good(i32 1, i32 2, i32 3, i32 4)
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
84 ; NORMAL-NEXT: pushl $3072
85 ; NORMAL-NEXT: pushl $2048
86 ; NORMAL-NEXT: pushl $1024
88 ; NORMAL-NEXT: addl $16, %esp
89 define void @test2b() optsize {
91 call void @good(i32 1024, i32 2048, i32 3072, i32 4096)
95 ; The first push should push a register
96 ; NORMAL-LABEL: test3:
97 ; NORMAL-NOT: subl {{.*}} %esp
99 ; NORMAL-NEXT: pushl $3
100 ; NORMAL-NEXT: pushl $2
101 ; NORMAL-NEXT: pushl %e{{..}}
103 ; NORMAL-NEXT: addl $16, %esp
104 define void @test3(i32 %k) optsize {
107 call void @good(i32 %f, i32 2, i32 3, i32 4)
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
119 ; NORMAL-NEXT: addl $12, %esp
120 define void @test4() optsize {
122 call void @inreg(i32 1, i32 2, i32 3, i32 4)
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
135 define void @test5(i32 %k) {
137 %a = alloca i32, i32 %k
138 call void @good(i32 1, i32 2, i32 3, i32 4)
142 ; When the alignment adds up, do the transformation
143 ; ALIGNED-LABEL: test5b:
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
153 define void @test5b() optsize {
155 call void @eightparams(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8)
159 ; When having to compensate for the alignment isn't worth it,
161 ; ALIGNED-LABEL: test5c:
162 ; ALIGNED: movl $1, (%esp)
164 define void @test5c() optsize {
166 call void @oneparam(i32 1)
170 ; Check that pushing the addresses of globals (Or generally, things that
171 ; aren't exactly immediates) isn't broken.
173 ; NORMAL-LABEL: test6:
174 ; NORMAL: pushl $_ext
177 @ext = external constant i8
179 define void @test6() {
180 call void @f(i8* @ext)
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
196 ; NORMAL-NEXT: addl $16, %esp
197 define void @test7(i32* %ptr) optsize {
199 %val = load i32, i32* %ptr
200 call void @good(i32 1, i32 2, i32 %val, i32 4)
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:
210 ; NORMAL-NEXT: pushl 12(%esp)
211 ; NORMAL-NEXT: pushl 12(%esp)
212 ; NORMAL-NEXT: pushl $1
214 ; NORMAL-NEXT: addl $16, %esp
215 define void @test8(i32 %a, i32 %b) optsize {
217 call void @good(i32 1, i32 %a, i32 %b, i32 4)
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),
227 ; NORMAL-NEXT: pushl $3
228 ; NORMAL-NEXT: pushl $2
229 ; NORMAL-NEXT: pushl $1
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)
239 ; NORMAL-NEXT: addl $16, %esp
240 define void @test9() optsize {
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)
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
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)*, 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)
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]]
282 ; NORMAL-NEXT: addl $16, %esp
283 @the_global = external global i32
284 define void @test11() optsize {
285 %myload = load i32, i32* @the_global
286 store i32 42, i32* @the_global
287 call void @good(i32 %myload, i32 2, i32 3, i32 4)
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 {
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)
319 ; But if the gains outweigh the overhead, we should do it
320 ; NORMAL-LABEL: test12b:
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 {
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)