[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / llvm / test / CodeGen / X86 / movtopush.ll
bloba491986058e521601db69e4d33b35fdc3af2a17d
1 ; RUN: llc < %s -mtriple=i686-windows | FileCheck %s -check-prefix=NORMAL
2 ; RUN: llc < %s -mtriple=i686-windows -no-x86-call-frame-opt | FileCheck %s -check-prefix=NOPUSH
3 ; RUN: llc < %s -mtriple=x86_64-windows | FileCheck %s -check-prefix=X64
4 ; RUN: llc < %s -mtriple=i686-pc-linux | FileCheck %s -check-prefix=LINUX
6 %class.Class = type { i32 }
7 %struct.s = type { i64 }
9 declare void @good(i32 %a, i32 %b, i32 %c, i32 %d)
10 declare void @inreg(i32 %a, i32 inreg %b, i32 %c, i32 %d)
11 declare x86_thiscallcc void @thiscall(ptr %class, i32 %a, i32 %b, i32 %c, i32 %d)
12 declare void @oneparam(i32 %a)
13 declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
14 declare void @eightparams16(i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g, i16 %h)
15 declare void @eightparams64(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h)
16 declare void @struct(ptr byval(%struct.s) %a, i32 %b, i32 %c, i32 %d)
17 declare void @inalloca(ptr inalloca(<{ %struct.s }>))
19 declare ptr @llvm.stacksave()
20 declare void @llvm.stackrestore(ptr)
22 ; We should get pushes for x86, even though there is a reserved call frame.
23 ; Make sure we don't touch x86-64, and that turning it off works.
24 ; NORMAL-LABEL: test1:
25 ; NORMAL-NOT: subl {{.*}} %esp
26 ; NORMAL: pushl   $4
27 ; NORMAL-NEXT: pushl   $3
28 ; NORMAL-NEXT: pushl   $2
29 ; NORMAL-NEXT: pushl   $1
30 ; NORMAL-NEXT: call
31 ; NORMAL-NEXT: addl $16, %esp
32 ; X64-LABEL: test1:
33 ; X64: movl    $1, %ecx
34 ; X64-NEXT: movl    $2, %edx
35 ; X64-NEXT: movl    $3, %r8d
36 ; X64-NEXT: movl    $4, %r9d
37 ; X64-NEXT: callq   good
38 ; NOPUSH-LABEL: test1:
39 ; NOPUSH: subl    $16, %esp
40 ; NOPUSH-NEXT: movl    $4, 12(%esp)
41 ; NOPUSH-NEXT: movl    $3, 8(%esp)
42 ; NOPUSH-NEXT: movl    $2, 4(%esp)
43 ; NOPUSH-NEXT: movl    $1, (%esp)
44 ; NOPUSH-NEXT: call
45 ; NOPUSH-NEXT: addl $16, %esp
46 define void @test1() {
47 entry:
48   call void @good(i32 1, i32 2, i32 3, i32 4)
49   ret void
52 ; If we have a reserved frame, we should have pushes
53 ; NORMAL-LABEL: test2:
54 ; NORMAL-NOT: subl {{.*}} %esp
55 ; NORMAL: pushl   $4
56 ; NORMAL-NEXT: pushl   $3
57 ; NORMAL-NEXT: pushl   $2
58 ; NORMAL-NEXT: pushl   $1
59 ; NORMAL-NEXT: call
60 define void @test2(i32 %k) {
61 entry:
62   %a = alloca i32, i32 %k
63   call void @good(i32 1, i32 2, i32 3, i32 4)
64   ret void
67 ; Again, we expect a sequence of 4 immediate pushes
68 ; Checks that we generate the right pushes for >8bit immediates
69 ; NORMAL-LABEL: test2b:
70 ; NORMAL-NOT: subl {{.*}} %esp
71 ; NORMAL: pushl   $4096
72 ; NORMAL-NEXT: pushl   $3072
73 ; NORMAL-NEXT: pushl   $2048
74 ; NORMAL-NEXT: pushl   $1024
75 ; NORMAL-NEXT: call
76 ; NORMAL-NEXT: addl $16, %esp
77 define void @test2b() optsize {
78 entry:
79   call void @good(i32 1024, i32 2048, i32 3072, i32 4096)
80   ret void
83 ; The first push should push a register
84 ; NORMAL-LABEL: test3:
85 ; NORMAL-NOT: subl {{.*}} %esp
86 ; NORMAL: pushl   $4
87 ; NORMAL-NEXT: pushl   $3
88 ; NORMAL-NEXT: pushl   $2
89 ; NORMAL-NEXT: pushl   %e{{..}}
90 ; NORMAL-NEXT: call
91 ; NORMAL-NEXT: addl $16, %esp
92 define void @test3(i32 %k) optsize {
93 entry:
94   %f = add i32 %k, 1
95   call void @good(i32 %f, i32 2, i32 3, i32 4)
96   ret void
99 ; We support weird calling conventions
100 ; NORMAL-LABEL: test4:
101 ; NORMAL: movl    $2, %eax
102 ; NORMAL-NEXT: pushl   $4
103 ; NORMAL-NEXT: pushl   $3
104 ; NORMAL-NEXT: pushl   $1
105 ; NORMAL-NEXT: call
106 ; NORMAL-NEXT: addl $12, %esp
107 define void @test4() optsize {
108 entry:
109   call void @inreg(i32 1, i32 inreg 2, i32 3, i32 4)
110   ret void
113 ; NORMAL-LABEL: test4b:
114 ; NORMAL: movl 4(%esp), %ecx
115 ; NORMAL-NEXT: pushl   $4
116 ; NORMAL-NEXT: pushl   $3
117 ; NORMAL-NEXT: pushl   $2
118 ; NORMAL-NEXT: pushl   $1
119 ; NORMAL-NEXT: call
120 ; NORMAL-NEXT: ret
121 define void @test4b(ptr %f) optsize {
122 entry:
123   call x86_thiscallcc void @thiscall(ptr %f, i32 1, i32 2, i32 3, i32 4)
124   ret void
127 ; Check that pushing the addresses of globals (Or generally, things that
128 ; aren't exactly immediates) isn't broken.
129 ; Fixes PR21878.
130 ; NORMAL-LABEL: test6:
131 ; NORMAL: pushl    $_ext
132 ; NORMAL-NEXT: call
133 declare void @f(ptr)
134 @ext = external dso_local constant i8
136 define void @test6() {
137   call void @f(ptr @ext)
138   br label %bb
140   alloca i32
141   ret void
144 ; Check that we fold simple cases into the push
145 ; NORMAL-LABEL: test7:
146 ; NORMAL-NOT: subl {{.*}} %esp
147 ; NORMAL: movl 4(%esp), [[EAX:%e..]]
148 ; NORMAL-NEXT: pushl   $4
149 ; NORMAL-NEXT: pushl   ([[EAX]])
150 ; NORMAL-NEXT: pushl   $2
151 ; NORMAL-NEXT: pushl   $1
152 ; NORMAL-NEXT: call
153 ; NORMAL-NEXT: addl $16, %esp
154 define void @test7(ptr %ptr) optsize {
155 entry:
156   %val = load i32, ptr %ptr
157   call void @good(i32 1, i32 2, i32 %val, i32 4)
158   ret void
161 ; Fold stack-relative loads into the push, with correct offset
162 ; In particular, at the second push, %b was at 12(%esp) and
163 ; %a wast at 8(%esp), but the second push bumped %esp, so %a
164 ; is now it at 12(%esp)
165 ; NORMAL-LABEL: test8:
166 ; NORMAL: pushl   $4
167 ; NORMAL-NEXT: pushl   12(%esp)
168 ; NORMAL-NEXT: pushl   12(%esp)
169 ; NORMAL-NEXT: pushl   $1
170 ; NORMAL-NEXT: call
171 ; NORMAL-NEXT: addl $16, %esp
172 define void @test8(i32 %a, i32 %b) optsize {
173 entry:
174   call void @good(i32 1, i32 %a, i32 %b, i32 4)
175   ret void
178 ; If one function is using push instructions, and the other isn't
179 ; (because it has frame-index references), then we must resolve
180 ; these references correctly.
181 ; NORMAL-LABEL: test9:
182 ; NORMAL-NOT: leal (%esp),
183 ; NORMAL: pushl $4
184 ; NORMAL-NEXT: pushl $3
185 ; NORMAL-NEXT: pushl $2
186 ; NORMAL-NEXT: pushl $1
187 ; NORMAL-NEXT: call
188 ; NORMAL-NEXT: addl $16, %esp
189 ; NORMAL-NEXT: movl (%esp), [[E1:%e..]]
190 ; NORMAL-NEXT: movl 4(%esp), [[E2:%e..]]
191 ; NORMAL-NEXT: leal 16(%esp), [[E3:%e..]]
192 ; NORMAL-NEXT: leal 12(%esp), [[E4:%e..]]
193 ; NORMAL-NEXT: pushl   [[E3]]
194 ; NORMAL-NEXT: pushl   [[E4]]
195 ; NORMAL-NEXT: pushl   $6
196 ; NORMAL-NEXT: pushl   [[E2]]
197 ; NORMAL-NEXT: pushl   [[E1]]
198 ; NORMAL-NEXT: call
199 ; NORMAL-NEXT: addl $20, %esp
200 define void @test9() optsize {
201 entry:
202   %p = alloca i32, align 4
203   %q = alloca i32, align 4
204   %s = alloca %struct.s, align 8
205   call void @good(i32 1, i32 2, i32 3, i32 4)
206   %pv = ptrtoint ptr %p to i32
207   %qv = ptrtoint ptr %q to i32
208   call void @struct(ptr byval(%struct.s) %s, i32 6, i32 %qv, i32 %pv)
209   ret void
212 ; We can end up with an indirect call which gets reloaded on the spot.
213 ; Make sure we reference the correct stack slot - we spill into (%esp)
214 ; and reload from 16(%esp) due to the pushes.
215 ; NORMAL-LABEL: test10:
216 ; NORMAL: movl $_good, [[ALLOC:.*]]
217 ; NORMAL-NEXT: movl [[ALLOC]], [[EAX:%e..]]
218 ; NORMAL-NEXT: movl [[EAX]], (%esp) # 4-byte Spill
219 ; NORMAL: nop
220 ; NORMAL: pushl $4
221 ; NORMAL-NEXT: pushl $3
222 ; NORMAL-NEXT: pushl $2
223 ; NORMAL-NEXT: pushl $1
224 ; NORMAL-NEXT: calll *16(%esp)
225 ; NORMAL-NEXT: addl $24, %esp
226 define void @test10() optsize {
227   %stack_fptr = alloca ptr
228   store ptr @good, ptr %stack_fptr
229   %good_ptr = load volatile ptr, ptr %stack_fptr
230   call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di}"()
231   call void (i32, i32, i32, i32) %good_ptr(i32 1, i32 2, i32 3, i32 4)
232   ret void
235 ; We can't fold the load from the global into the push because of
236 ; interference from the store
237 ; NORMAL-LABEL: test11:
238 ; NORMAL: movl    _the_global, [[EAX:%e..]]
239 ; NORMAL-NEXT: movl    $42, _the_global
240 ; NORMAL-NEXT: pushl $4
241 ; NORMAL-NEXT: pushl $3
242 ; NORMAL-NEXT: pushl $2
243 ; NORMAL-NEXT: pushl [[EAX]]
244 ; NORMAL-NEXT: call
245 ; NORMAL-NEXT: addl $16, %esp
246 @the_global = external dso_local global i32
247 define void @test11() optsize {
248   %myload = load i32, ptr @the_global
249   store i32 42, ptr @the_global
250   call void @good(i32 %myload, i32 2, i32 3, i32 4)
251   ret void
254 ; Converting one mov into a push isn't worth it when
255 ; doing so forces too much overhead for other calls.
256 ; NORMAL-LABEL: test12:
257 ; NORMAL:       pushl  $8
258 ; NORMAL-NEXT:  pushl  $7
259 ; NORMAL-NEXT:  pushl  $6
260 ; NORMAL-NEXT:  pushl  $5
261 ; NORMAL-NEXT: calll _good
262 define void @test12() optsize {
263 entry:
264   %s = alloca %struct.s, align 4
265   call void @struct(ptr byval(%struct.s) %s, i32 2, i32 3, i32 4)
266   call void @good(i32 5, i32 6, i32 7, i32 8)
267   call void @struct(ptr byval(%struct.s) %s, i32 10, i32 11, i32 12)
268   ret void
271 ; But if the gains outweigh the overhead, we should do it
272 ; NORMAL-LABEL: test12b:
273 ; NORMAL: pushl    $4
274 ; NORMAL-NEXT: pushl    $3
275 ; NORMAL-NEXT: pushl    $2
276 ; NORMAL-NEXT: pushl    $1
277 ; NORMAL-NEXT: calll _good
278 ; NORMAL-NEXT: addl    $16, %esp
279 ; NORMAL=NEXT: movl  (%esp), %eax
280 ; NORMAL=NEXT: movl  4(%esp), %ecx
281 ; NORMAL=NEXT: pushl  $8
282 ; NORMAL=NEXT: pushl  $7
283 ; NORMAL=NEXT: pushl  $6
284 ; NORMAL=NEXT: pushl  %ecx
285 ; NORMAL=NEXT: pushl  %eax
286 ; NORMAL=NEXT: calll  _struct
287 ; NORMAL=NEXT: addl  $20, %esp
288 ; NORMAL=NEXT: pushl  $12
289 ; NORMAL=NEXT: pushl  $11
290 ; NORMAL=NEXT: pushl  $10
291 ; NORMAL=NEXT: pushl  $9
292 ; NORMAL=NEXT: calll  _good
293 ; NORMAL=NEXT: addl  $16, %esp
294 define void @test12b() optsize {
295 entry:
296   %s = alloca %struct.s, align 4
297   call void @good(i32 1, i32 2, i32 3, i32 4)
298   call void @struct(ptr byval(%struct.s) %s, i32 6, i32 7, i32 8)
299   call void @good(i32 9, i32 10, i32 11, i32 12)
300   ret void
303 ; Make sure the add does not prevent folding loads into pushes.
304 ; val1 and val2 will not be folded into pushes since they have
305 ; an additional use, but val3 should be.
306 ; NORMAL-LABEL: test13:
307 ; NORMAL: movl ([[P1:%e..]]), [[V1:%e..]]
308 ; NORMAL-NEXT: movl ([[P2:%e..]]), [[V2:%e..]]
309 ; NORMAL-NEXT: , [[ADD:%e..]]
310 ; NORMAL-NEXT: pushl [[ADD]]
311 ; NORMAL-NEXT: pushl ([[P3:%e..]])
312 ; NORMAL-NEXT: pushl [[V2]]
313 ; NORMAL-NEXT: pushl [[V1]]
314 ; NORMAL-NEXT: calll _good
315 ; NORMAL: movl [[P3]], %eax
316 define ptr @test13(ptr inreg %ptr1, ptr inreg %ptr2, ptr inreg %ptr3) optsize {
317 entry:
318   %val1 = load i32, ptr %ptr1
319   %val2 = load i32, ptr %ptr2
320   %val3 = load i32, ptr %ptr3
321   %add = add i32 %val1, %val2
322   call void @good(i32 %val1, i32 %val2, i32 %val3, i32 %add)
323   ret ptr %ptr3
326 ; Make sure to fold adjacent stack adjustments.
327 ; LINUX-LABEL: pr27140:
328 ; LINUX: subl    $12, %esp
329 ; LINUX: .cfi_def_cfa_offset 16
330 ; LINUX-NOT: sub
331 ; LINUX: pushl   $4
332 ; LINUX: .cfi_adjust_cfa_offset 4
333 ; LINUX: pushl   $3
334 ; LINUX: .cfi_adjust_cfa_offset 4
335 ; LINUX: pushl   $2
336 ; LINUX: .cfi_adjust_cfa_offset 4
337 ; LINUX: pushl   $1
338 ; LINUX: .cfi_adjust_cfa_offset 4
339 ; LINUX: calll   good
340 ; LINUX: addl    $28, %esp
341 ; LINUX: .cfi_adjust_cfa_offset -28
342 ; LINUX-NOT: add
343 ; LINUX: retl
344 define void @pr27140() optsize {
345 entry:
346   tail call void @good(i32 1, i32 2, i32 3, i32 4)
347   ret void
350 ; Check that a stack restore (leal -4(%ebp), %esp) doesn't get merged with a
351 ; stack adjustment (addl $12, %esp). Just because it's a lea doesn't mean it's
352 ; simply decreasing the stack pointer.
353 ; NORMAL-LABEL: test14:
354 ; NORMAL: calll _B_func
355 ; NORMAL: leal -4(%ebp), %esp
356 ; NORMAL-NOT: %esp
357 ; NORMAL: retl
358 %struct.A = type { i32, i32 }
359 %struct.B = type { i8 }
360 declare x86_thiscallcc ptr @B_ctor(ptr returned, ptr byval(%struct.A))
361 declare void @B_func(ptr sret(%struct.B), ptr, i32)
362 define void @test14(ptr %a) {
363 entry:
364   %ref.tmp = alloca %struct.B, align 1
365   %agg.tmp = alloca i64, align 8
366   %tmp = alloca %struct.B, align 1
367   %0 = load i64, ptr %a, align 4
368   store i64 %0, ptr %agg.tmp, align 4
369   %call = call x86_thiscallcc ptr @B_ctor(ptr returned %ref.tmp, ptr byval(%struct.A) %agg.tmp)
370   call void @B_func(ptr sret(%struct.B) %tmp, ptr %ref.tmp, i32 1)
371   ret void
374 ; NORMAL-LABEL: pr34863_16
375 ; NORMAL:       movl  4(%esp), %eax
376 ; NORMAL-NEXT:  pushl  $65535
377 ; NORMAL-NEXT:  pushl  $0
378 ; NORMAL-NEXT:  pushl  %eax
379 ; NORMAL-NEXT:  pushl  %eax
380 ; NORMAL-NEXT:  pushl  %eax
381 ; NORMAL-NEXT:  pushl  %eax
382 ; NORMAL-NEXT:  pushl  %eax
383 ; NORMAL-NEXT:  pushl  %eax
384 ; NORMAL-NEXT:  calll  _eightparams16
385 ; NORMAL-NEXT:  addl  $32, %esp
387 ; NOPUSH-LABEL: pr34863_16
388 ; NOPUSH:       subl  $32, %esp
389 ; NOPUSH-NEXT:  movl  36(%esp), %eax
390 ; NOPUSH-NEXT:  movl  %eax, 20(%esp)
391 ; NOPUSH-NEXT:  movl  %eax, 16(%esp)
392 ; NOPUSH-NEXT:  movl  %eax, 12(%esp)
393 ; NOPUSH-NEXT:  movl  %eax, 8(%esp)
394 ; NOPUSH-NEXT:  movl  %eax, 4(%esp)
395 ; NOPUSH-NEXT:  movl  %eax, (%esp)
396 ; NOPUSH-NEXT:  movl  $65535, 28(%esp)
397 ; NOPUSH-NEXT:  andl  $0, 24(%esp)
398 ; NOPUSH-NEXT:  calll  _eightparams16
399 ; NOPUSH-NEXT:   addl  $32, %esp
400 define void @pr34863_16(i16 %x) minsize nounwind {
401 entry:
402   tail call void @eightparams16(i16 %x, i16 %x, i16 %x, i16 %x, i16 %x, i16 %x, i16 0, i16 -1)
403   ret void
406 ; NORMAL-LABEL: pr34863_32
407 ; NORMAL:      movl  4(%esp), %eax
408 ; NORMAL-NEXT: pushl  $-1
409 ; NORMAL-NEXT: pushl  $0
410 ; NORMAL-NEXT: pushl  %eax
411 ; NORMAL-NEXT: pushl  %eax
412 ; NORMAL-NEXT: pushl  %eax
413 ; NORMAL-NEXT: pushl  %eax
414 ; NORMAL-NEXT: pushl  %eax
415 ; NORMAL-NEXT: pushl  %eax
416 ; NORMAL-NEXT: calll  _eightparams
417 ; NORMAL-NEXT: addl  $32, %esp
419 ; NOPUSH-LABEL: pr34863_32
420 ; NOPUSH:      subl  $32, %esp
421 ; NOPUSH-NEXT: movl  36(%esp), %eax
422 ; NOPUSH-NEXT: movl  %eax, 20(%esp)
423 ; NOPUSH-NEXT: movl  %eax, 16(%esp)
424 ; NOPUSH-NEXT: movl  %eax, 12(%esp)
425 ; NOPUSH-NEXT: movl  %eax, 8(%esp)
426 ; NOPUSH-NEXT: movl  %eax, 4(%esp)
427 ; NOPUSH-NEXT: movl  %eax, (%esp)
428 ; NOPUSH-NEXT: orl  $-1, 28(%esp)
429 ; NOPUSH-NEXT: andl  $0, 24(%esp)
430 ; NOPUSH-NEXT: calll  _eightparams
431 ; NOPUSH-NEXT: addl  $32, %esp
432 define void @pr34863_32(i32 %x) minsize nounwind {
433 entry:
434   tail call void @eightparams(i32 %x, i32 %x, i32 %x, i32 %x, i32 %x, i32 %x, i32 0, i32 -1)
435   ret void
438 ; NORMAL-LABEL: pr34863_64
439 ; NORMAL:      movl  4(%esp), %eax
440 ; NORMAL-NEXT: movl  8(%esp), %ecx
441 ; NORMAL-NEXT: pushl  $-1
442 ; NORMAL-NEXT: pushl  $-1
443 ; NORMAL-NEXT: pushl  $0
444 ; NORMAL-NEXT: pushl  $0
445 ; NORMAL-NEXT: pushl  %ecx
446 ; NORMAL-NEXT: pushl  %eax
447 ; NORMAL-NEXT: pushl  %ecx
448 ; NORMAL-NEXT: pushl  %eax
449 ; NORMAL-NEXT: pushl  %ecx
450 ; NORMAL-NEXT: pushl  %eax
451 ; NORMAL-NEXT: pushl  %ecx
452 ; NORMAL-NEXT: pushl  %eax
453 ; NORMAL-NEXT: pushl  %ecx
454 ; NORMAL-NEXT: pushl  %eax
455 ; NORMAL-NEXT: pushl  %ecx
456 ; NORMAL-NEXT: pushl  %eax
457 ; NORMAL-NEXT: calll  _eightparams64
458 ; NORMAL-NEXT: addl  $64, %esp
460 ; NOPUSH-LABEL: pr34863_64
461 ; NOPUSH:      subl  $64, %esp
462 ; NOPUSH-NEXT: movl  68(%esp), %eax
463 ; NOPUSH-NEXT: movl  72(%esp), %ecx
464 ; NOPUSH-NEXT: movl  %ecx, 44(%esp)
465 ; NOPUSH-NEXT: movl  %eax, 40(%esp)
466 ; NOPUSH-NEXT: movl  %ecx, 36(%esp)
467 ; NOPUSH-NEXT: movl  %eax, 32(%esp)
468 ; NOPUSH-NEXT: movl  %ecx, 28(%esp)
469 ; NOPUSH-NEXT: movl  %eax, 24(%esp)
470 ; NOPUSH-NEXT: movl  %ecx, 20(%esp)
471 ; NOPUSH-NEXT: movl  %eax, 16(%esp)
472 ; NOPUSH-NEXT: movl  %ecx, 12(%esp)
473 ; NOPUSH-NEXT: movl  %eax, 8(%esp)
474 ; NOPUSH-NEXT: movl  %ecx, 4(%esp)
475 ; NOPUSH-NEXT: movl  %eax, (%esp)
476 ; NOPUSH-NEXT: orl  $-1, 60(%esp)
477 ; NOPUSH-NEXT: orl  $-1, 56(%esp)
478 ; NOPUSH-NEXT: andl  $0, 52(%esp)
479 ; NOPUSH-NEXT: andl  $0, 48(%esp)
480 ; NOPUSH-NEXT: calll  _eightparams64
481 ; NOPUSH-NEXT: addl  $64, %esp
482 define void @pr34863_64(i64 %x) minsize nounwind {
483 entry:
484   tail call void @eightparams64(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 0, i64 -1)
485   ret void