1; RUN: llc < %s | FileCheck %s 2 3target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4target triple = "x86_64-unknown-linux-gnu" 5 6declare hhvmcc i64 @bar(i64, i64, i64) nounwind 7 8; Simply check we can modify %rbx and %rbp before returning via call to bar. 9define hhvmcc i64 @foo(i64 %a, i64 %b, i64 %c) nounwind { 10entry: 11; CHECK-LABEL: foo: 12; CHECK-DAG: movl $1, %ebx 13; CHECK-DAG: movl $3, %ebp 14; CHECK: jmp bar 15 %ret = musttail call hhvmcc i64 @bar(i64 1, i64 %b, i64 3) 16 ret i64 %ret 17} 18 19; Check that we can read and modify %rbx returned from PHP function. 20define hhvmcc i64 @mod_return(i64 %a, i64 %b, i64 %c) nounwind { 21entry: 22; CHECK-LABEL: mod_return: 23; CHECK-NEXT: {{^#.*}} 24; CHECK-NEXT: callq bar 25; CHECK-NEXT: incq %rbx 26 %tmp = call hhvmcc i64 @bar(i64 %a, i64 %b, i64 %c) 27 %retval = add i64 %tmp, 1 28 ret i64 %retval 29} 30 31%rettype = type { i64, i64, i64, i64, i64, i64, i64, 32 i64, i64, i64, i64, i64, i64, i64 33} 34 35; Check that we can return up to 14 64-bit args in registers. 36define hhvmcc %rettype @return_all(i64 %a, i64 %b, i64 %c) nounwind { 37entry: 38; CHECK-LABEL: return_all: 39; CHECK-DAG: movl $1, %ebx 40; CHECK-DAG: movl $2, %ebp 41; CHECK-DAG: movl $3, %edi 42; CHECK-DAG: movl $4, %esi 43; CHECK-DAG: movl $5, %edx 44; CHECK-DAG: movl $6, %ecx 45; CHECK-DAG: movl $7, %r8 46; CHECK-DAG: movl $8, %r9 47; CHECK-DAG: movl $9, %eax 48; CHECK-DAG: movl $10, %r10 49; CHECK-DAG: movl $11, %r11 50; CHECK-DAG: movl $12, %r13 51; CHECK-DAG: movl $13, %r14 52; CHECK-DAG: movl $14, %r15 53; CHECK: retq 54 %r1 = insertvalue %rettype zeroinitializer, i64 1, 0 55 %r2 = insertvalue %rettype %r1, i64 2, 1 56 %r3 = insertvalue %rettype %r2, i64 3, 2 57 %r4 = insertvalue %rettype %r3, i64 4, 3 58 %r5 = insertvalue %rettype %r4, i64 5, 4 59 %r6 = insertvalue %rettype %r5, i64 6, 5 60 %r7 = insertvalue %rettype %r6, i64 7, 6 61 %r8 = insertvalue %rettype %r7, i64 8, 7 62 %r9 = insertvalue %rettype %r8, i64 9, 8 63 %r10 = insertvalue %rettype %r9, i64 10, 9 64 %r11 = insertvalue %rettype %r10, i64 11, 10 65 %r12 = insertvalue %rettype %r11, i64 12, 11 66 %r13 = insertvalue %rettype %r12, i64 13, 12 67 %r14 = insertvalue %rettype %r13, i64 14, 13 68 ret %rettype %r14 69} 70 71declare hhvmcc void @return_all_tc(i64, i64, i64, i64, i64, i64, i64, i64, 72 i64, i64, i64, i64, i64, i64, i64) 73 74; Check that we can return up to 14 64-bit args in registers via tail call. 75define hhvmcc void @test_return_all_tc(i64 %a, i64 %b, i64 %c) nounwind { 76entry: 77; CHECK-LABEL: test_return_all_tc: 78; CHECK-NEXT: {{^#.*}} 79; CHECK-DAG: movl $1, %ebx 80; CHECK-DAG: movl $3, %ebp 81; CHECK-DAG: movl $4, %r15 82; CHECK-DAG: movl $5, %edi 83; CHECK-DAG: movl $6, %esi 84; CHECK-DAG: movl $7, %edx 85; CHECK-DAG: movl $8, %ecx 86; CHECK-DAG: movl $9, %r8 87; CHECK-DAG: movl $10, %r9 88; CHECK-DAG: movl $11, %eax 89; CHECK-DAG: movl $12, %r10 90; CHECK-DAG: movl $13, %r11 91; CHECK-DAG: movl $14, %r13 92; CHECK-DAG: movl $15, %r14 93; CHECK: jmp return_all_tc 94 tail call hhvmcc void @return_all_tc( 95 i64 1, i64 %b, i64 3, i64 4, i64 5, i64 6, i64 7, 96 i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15) 97 ret void 98} 99 100declare hhvmcc {i64, i64} @php_short(i64, i64, i64, i64) 101 102define hhvmcc i64 @test_php_short(i64 %a, i64 %b, i64 %c) nounwind { 103entry: 104; CHECK-LABEL: test_php_short: 105; CHECK-NEXT: {{^#.*}} 106; CHECK-NEXT: movl $42, %r15 107; CHECK-NEXT: callq php_short 108; CHECK-NEXT: leaq (%rbp,%r12), %rbx 109; CHECK-NEXT: retq 110 %pair = call hhvmcc {i64, i64} @php_short(i64 %a, i64 %b, i64 %c, i64 42) 111 %fp = extractvalue {i64, i64} %pair, 1 112 %rv = add i64 %fp, %b 113 ret i64 %rv 114} 115 116declare hhvmcc %rettype @php_all(i64, i64, i64, i64, i64, i64, i64, 117 i64, i64, i64, i64, i64, i64, i64, i64) 118 119; Check that we can pass 15 arguments in registers. 120; Also check that %r12 (2nd arg) is not spilled. 121define hhvmcc i64 @test_php_all(i64 %a, i64 %b, i64 %c) nounwind { 122entry: 123; CHECK-LABEL: test_php_all: 124; CHECK-NEXT: {{^#.*}} 125; CHECK-NOT: sub 126; CHECK-NOT: sub 127; CHECK-DAG: movl $1, %ebx 128; CHECK-DAG: movl $3, %ebp 129; CHECK-DAG: movl $4, %r15 130; CHECK-DAG: movl $5, %edi 131; CHECK-DAG: movl $6, %esi 132; CHECK-DAG: movl $7, %edx 133; CHECK-DAG: movl $8, %ecx 134; CHECK-DAG: movl $9, %r8 135; CHECK-DAG: movl $10, %r9 136; CHECK-DAG: movl $11, %eax 137; CHECK-DAG: movl $12, %r10 138; CHECK-DAG: movl $13, %r11 139; CHECK-DAG: movl $14, %r13 140; CHECK-DAG: movl $15, %r14 141; CHECK: callq php_all 142 %pair = call hhvmcc %rettype @php_all( 143 i64 1, i64 %b, i64 3, i64 4, i64 5, i64 6, i64 7, 144 i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15) 145 %fp = extractvalue %rettype %pair, 1 146 %rv = add i64 %fp, %b 147 ret i64 %rv 148} 149 150declare hhvmcc void @svcreq(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, 151 i64, i64) 152 153define hhvmcc void @test_svcreq(i64 %a, i64 %b, i64 %c) nounwind { 154entry: 155; CHECK-LABEL: test_svcreq: 156; CHECK-DAG: movl $42, %r10 157; CHECK-DAG: movl $1, %edi 158; CHECK-DAG: movl $2, %esi 159; CHECK-DAG: movl $3, %edx 160; CHECK-DAG: movl $4, %ecx 161; CHECK-DAG: movl $5, %r8 162; CHECK-DAG: movl $6, %r9 163; CHECK: jmp svcreq 164 tail call hhvmcc void @svcreq(i64 %a, i64 %b, i64 %c, i64 undef, i64 1, 165 i64 2, i64 3, i64 4, i64 5, i64 6, i64 undef, 166 i64 42) 167 ret void 168} 169 170declare hhvm_ccc void @helper_short(i64, i64, i64, i64, i64, i64, i64) 171 172; Pass all arguments in registers and check that we don't adjust stack 173; for the call. 174define hhvmcc void @test_helper_short(i64 %a, i64 %b, i64 %c) nounwind { 175entry: 176; CHECK-LABEL: test_helper_short: 177; CHECK-NOT: push 178; CHECK-NOT: sub 179; CHECK-DAG: movl $1, %edi 180; CHECK-DAG: movl $2, %esi 181; CHECK-DAG: movl $3, %edx 182; CHECK-DAG: movl $4, %ecx 183; CHECK-DAG: movl $5, %r8 184; CHECK-DAG: movl $6, %r9 185; CHECK: callq helper_short 186 call hhvm_ccc void @helper_short(i64 %c, i64 1, i64 2, i64 3, i64 4, 187 i64 5, i64 6) 188 ret void 189} 190 191declare hhvm_ccc void @helper(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) 192 193define hhvmcc void @test_helper(i64 %a, i64 %b, i64 %c) nounwind { 194entry: 195; CHECK-LABEL: test_helper: 196; CHECK-DAG: movl $1, %edi 197; CHECK-DAG: movl $2, %esi 198; CHECK-DAG: movl $3, %edx 199; CHECK-DAG: movl $4, %ecx 200; CHECK-DAG: movl $5, %r8 201; CHECK-DAG: movl $6, %r9 202; CHECK: callq helper 203 call hhvm_ccc void @helper(i64 %c, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, 204 i64 7, i64 8, i64 9) 205 ret void 206} 207 208; When we enter function with HHVM calling convention, the stack is aligned 209; at 16 bytes. This means we align objects on the stack differently and 210; adjust the stack differently for calls. 211declare hhvm_ccc void @stack_helper(i64, i64, i64) 212declare hhvm_ccc void @stack_helper2(<2 x double>, i64) 213 214define hhvmcc void @test_stack_helper(i64 %a, i64 %b, i64 %c) nounwind { 215entry: 216; CHECK-LABEL: test_stack_helper: 217; CHECK-NOT: push 218; CHECK: subq $32, %rsp 219; CHECK: movaps 16(%rsp), %xmm0 220; CHECK: callq stack_helper2 221 %t1 = alloca <2 x double>, align 16 222 %t2 = alloca i64, align 8 223 %t3 = alloca i64, align 8 224 %load3 = load i64, i64 *%t3 225 call hhvm_ccc void @stack_helper(i64 %c, i64 %load3, i64 42) 226 %load = load <2 x double>, <2 x double> *%t1 227 %load2 = load i64, i64 *%t2 228 call hhvm_ccc void @stack_helper2(<2 x double> %load, i64 %load2) 229 ret void 230} 231 232; Check that we are not adjusting the stack before calling the helper. 233define hhvmcc void @test_stack_helper2(i64 %a, i64 %b, i64 %c) nounwind { 234entry: 235; CHECK-LABEL: test_stack_helper2: 236; CHECK-NOT: push 237; CHECK-NOT: subq 238 call hhvm_ccc void @stack_helper(i64 %c, i64 7, i64 42) 239 ret void 240} 241 242