227 lines · plain
1; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s -check-prefix=NORMAL -check-prefix=NORMALFP2; RUN: llc < %s -mtriple=x86_64-windows | FileCheck %s -check-prefix=NOPUSH3; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s -check-prefix=NOPUSH -check-prefix=NORMALFP4; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -no-x86-call-frame-opt | FileCheck %s -check-prefix=NOPUSH5 6declare void @seven_params(i32 %a, i64 %b, i32 %c, i64 %d, i32 %e, i64 %f, i32 %g)7declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)8declare void @eightparams16(i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g, i16 %h)9declare void @eightparams64(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h)10declare void @ten_params(i32 %a, i64 %b, i32 %c, i64 %d, i32 %e, i64 %f, i32 %g, i64 %h, i32 %i, i64 %j)11declare void @ten_params_ptr(i32 %a, i64 %b, i32 %c, i64 %d, i32 %e, i64 %f, i32 %g, ptr %h, i32 %i, i64 %j)12declare void @cannot_push(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, float %i)13 14; We should get pushes for the last 4 parameters. Test that the15; in-register parameters are all in the right places, and check16; that the stack manipulations are correct and correctly17; described by the DWARF directives. Test that the switch18; to disable the optimization works and that the optimization19; doesn't kick in on Windows64 where it is not allowed.20; NORMAL-LABEL: test121; NORMAL: pushq22; NORMAL-DAG: movl $1, %edi23; NORMAL-DAG: movl $2, %esi24; NORMAL-DAG: movl $3, %edx25; NORMAL-DAG: movl $4, %ecx26; NORMAL-DAG: movl $5, %r8d27; NORMAL-DAG: movl $6, %r9d28; NORMAL: pushq $1029; NORMAL: .cfi_adjust_cfa_offset 830; NORMAL: pushq $931; NORMAL: .cfi_adjust_cfa_offset 832; NORMAL: pushq $833; NORMAL: .cfi_adjust_cfa_offset 834; NORMAL: pushq $735; NORMAL: .cfi_adjust_cfa_offset 836; NORMAL: callq ten_params37; NORMAL: addq $32, %rsp38; NORMAL: .cfi_adjust_cfa_offset -3239; NORMAL: popq40; NORMAL: retq41; NOPUSH-LABEL: test142; NOPUSH-NOT: pushq43; NOPUSH: retq44define void @test1() {45entry:46 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, i64 8, i32 9, i64 10)47 ret void48}49 50; The presence of a frame pointer should not prevent pushes. But we51; don't need the CFI directives in that case.52; Also check that we generate the right pushes for >8bit immediates.53; NORMALFP-LABEL: test254; NORMALFP: pushq $1000055; NORMALFP-NEXT: pushq $900056; NORMALFP-NEXT: pushq $800057; NORMALFP-NEXT: pushq $700058; NORMALFP-NEXT: callq {{_?}}ten_params59define void @test2(i32 %k) {60entry:61 %a = alloca i32, i32 %k62 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7000, i64 8000, i32 9000, i64 10000)63 ret void64}65 66; Parameters 7 & 8 should push a 64-bit register.67; TODO: Note that the regular expressions disallow r8 and r9. That's fine for68; now, because the pushes will always follow the moves into r8 and r9.69; Eventually, though, we want to be able to schedule the pushes better.70; In this example, it will save two copies, because we have to move the71; incoming parameters out of %rdi and %rsi to make room for the outgoing72; parameters.73; NORMAL-LABEL: test374; NORMAL: pushq $1000075; NORMAL: pushq $900076; NORMAL: pushq %r{{..}}77; NORMAL: pushq %r{{..}}78; NORMAL: callq ten_params79define void @test3(i32 %a, i64 %b) {80entry:81 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 %a, i64 %b, i32 9000, i64 10000)82 ret void83}84 85; Check that we avoid the optimization for just one push.86; NORMAL-LABEL: test487; NORMAL: movl $7, (%rsp)88; NORMAL: callq seven_params89define void @test4() {90entry:91 call void @seven_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7)92 ret void93}94 95; Check that pushing link-time constant addresses works correctly96; NORMAL-LABEL: test597; NORMAL: pushq $1098; NORMAL: pushq $999; NORMAL: pushq $ext100; NORMAL: pushq $7101; NORMAL: callq ten_params_ptr102@ext = external dso_local constant i8103define void @test5() {104entry:105 call void @ten_params_ptr(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, ptr @ext, i32 9, i64 10)106 ret void107}108 109; Check that we fuse 64-bit loads but not 32-bit loads into PUSH mem.110; NORMAL-LABEL: test6111; NORMAL: movq %rsi, [[REG64:%.+]]112; NORMAL: pushq $10113; NORMAL: pushq $9114; NORMAL: pushq ([[REG64]])115; NORMAL: pushq {{%r..}}116; NORMAL: callq ten_params117define void @test6(ptr %p32, ptr %p64) {118entry:119 %v32 = load i32, ptr %p32120 %v64 = load i64, ptr %p64121 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 %v32, i64 %v64, i32 9, i64 10)122 ret void123}124 125; Fold stack-relative loads into the push with correct offsets.126; Do the same for an indirect call whose address is loaded from the stack.127; On entry, %p7 is at 8(%rsp) and %p8 is at 16(%rsp). Prior to the call128; sequence, 72 bytes are allocated to the stack, 48 for register saves and129; 24 for local storage and alignment, so %p7 is at 80(%rsp) and %p8 is at130; 88(%rsp). The call address can be stored anywhere in the local space but131; happens to be stored at 8(%rsp). Each push bumps these offsets up by132; 8 bytes.133; NORMAL-LABEL: test7134; NORMAL: movq %r{{.*}}, 8(%rsp) {{.*Spill$}}135; NORMAL: pushq 88(%rsp)136; NORMAL: pushq $9137; NORMAL: pushq 96(%rsp)138; NORMAL: pushq $7139; NORMAL: callq *40(%rsp)140define void @test7(i64 %p1, i64 %p2, i64 %p3, i64 %p4, i64 %p5, i64 %p6, i64 %p7, i64 %p8) {141entry:142 %stack_fptr = alloca ptr143 store ptr @ten_params, ptr %stack_fptr144 %ten_params_ptr = load volatile ptr, ptr %stack_fptr145 call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"()146 call void (i32, i64, i32, i64, i32, i64, i32, i64, i32, i64) %ten_params_ptr(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, i64 %p7, i32 9, i64 %p8)147 ret void148}149 150; We can't fold the load from the global into the push because of 151; interference from the store152; NORMAL-LABEL: test8153; NORMAL: movq the_global(%rip), [[REG:%r.+]]154; NORMAL: movq $42, the_global155; NORMAL: pushq $10156; NORMAL: pushq $9157; NORMAL: pushq [[REG]]158; NORMAL: pushq $7159; NORMAL: callq ten_params160@the_global = external dso_local global i64161define void @test8() {162 %myload = load i64, ptr @the_global163 store i64 42, ptr @the_global164 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, i64 %myload, i32 9, i64 10)165 ret void166}167 168 169; Converting one function call to use pushes negatively affects170; other calls that pass arguments on the stack without pushes.171; If the cost outweighs the benefit, avoid using pushes.172; NORMAL-LABEL: test9173; NORMAL: callq cannot_push174; NORMAL-NOT: push175; NORMAL: callq ten_params176define void @test9(float %p1) {177 call void @cannot_push(float 1.0e0, float 2.0e0, float 3.0e0, float 4.0e0, float 5.0e0, float 6.0e0, float 7.0e0, float 8.0e0, float %p1)178 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, i64 8, i32 9, i64 10)179 call void @cannot_push(float 1.0e0, float 2.0e0, float 3.0e0, float 4.0e0, float 5.0e0, float 6.0e0, float 7.0e0, float 8.0e0, float %p1)180 ret void181}182 183; But if the benefit outweighs the cost, use pushes.184; NORMAL-LABEL: test10185; NORMAL: callq cannot_push186; NORMAL: pushq $10187; NORMAL: pushq $9188; NORMAL: pushq $8189; NORMAL: pushq $7190; NORMAL: callq ten_params191define void @test10(float %p1) {192 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, i64 8, i32 9, i64 10)193 call void @cannot_push(float 1.0e0, float 2.0e0, float 3.0e0, float 4.0e0, float 5.0e0, float 6.0e0, float 7.0e0, float 8.0e0, float %p1)194 call void @ten_params(i32 1, i64 2, i32 3, i64 4, i32 5, i64 6, i32 7, i64 8, i32 9, i64 10)195 ret void196}197 198; NORMAL-LABEL: pr34863_16199; NORMAL: pushq ${{-1|65535}}200; NORMAL-NEXT: pushq $0201; NORMAL-NEXT: call202define void @pr34863_16(i16 %x) minsize nounwind {203entry:204 tail call void @eightparams16(i16 %x, i16 %x, i16 %x, i16 %x, i16 %x, i16 %x, i16 0, i16 -1)205 ret void206}207 208; NORMAL-LABEL: pr34863_32209; NORMAL: pushq ${{-1|65535}}210; NORMAL-NEXT: pushq $0211; NORMAL-NEXT: call212define void @pr34863_32(i32 %x) minsize nounwind {213entry:214 tail call void @eightparams(i32 %x, i32 %x, i32 %x, i32 %x, i32 %x, i32 %x, i32 0, i32 -1)215 ret void216}217 218; NORMAL-LABEL: pr34863_64219; NORMAL: pushq ${{-1|65535}}220; NORMAL-NEXT: pushq $0221; NORMAL-NEXT: call222define void @pr34863_64(i64 %x) minsize nounwind {223entry:224 tail call void @eightparams64(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 0, i64 -1)225 ret void226}227