1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4 2; RUN: llc -mtriple=x86_64-unknown-unknown -mcpu=corei7 < %s | FileCheck %s 3 4; This test checks various function call behaviors between preserve_none and 5; normal calling conventions. 6 7declare preserve_nonecc void @callee(ptr) 8 9; Normal caller calls preserve_none callee. Will not generated tail call because 10; of incompatible calling convention. Callee saved registers are saved/restored 11; around the call. 12define void @caller1(ptr %a) { 13; CHECK-LABEL: caller1: 14; CHECK: # %bb.0: 15; CHECK-NEXT: pushq %r15 16; CHECK-NEXT: .cfi_def_cfa_offset 16 17; CHECK-NEXT: pushq %r14 18; CHECK-NEXT: .cfi_def_cfa_offset 24 19; CHECK-NEXT: pushq %r13 20; CHECK-NEXT: .cfi_def_cfa_offset 32 21; CHECK-NEXT: pushq %r12 22; CHECK-NEXT: .cfi_def_cfa_offset 40 23; CHECK-NEXT: pushq %rbx 24; CHECK-NEXT: .cfi_def_cfa_offset 48 25; CHECK-NEXT: .cfi_offset %rbx, -48 26; CHECK-NEXT: .cfi_offset %r12, -40 27; CHECK-NEXT: .cfi_offset %r13, -32 28; CHECK-NEXT: .cfi_offset %r14, -24 29; CHECK-NEXT: .cfi_offset %r15, -16 30; CHECK-NEXT: movq %rdi, %r12 31; CHECK-NEXT: callq callee@PLT 32; CHECK-NEXT: popq %rbx 33; CHECK-NEXT: .cfi_def_cfa_offset 40 34; CHECK-NEXT: popq %r12 35; CHECK-NEXT: .cfi_def_cfa_offset 32 36; CHECK-NEXT: popq %r13 37; CHECK-NEXT: .cfi_def_cfa_offset 24 38; CHECK-NEXT: popq %r14 39; CHECK-NEXT: .cfi_def_cfa_offset 16 40; CHECK-NEXT: popq %r15 41; CHECK-NEXT: .cfi_def_cfa_offset 8 42; CHECK-NEXT: retq 43 tail call preserve_nonecc void @callee(ptr %a) 44 ret void 45} 46 47; Preserve_none caller calls preserve_none callee. Same function body. 48; The tail call is preserved. No registers are saved/restored around the call. 49; Actually a simple jmp instruction is generated. 50define preserve_nonecc void @caller2(ptr %a) { 51; CHECK-LABEL: caller2: 52; CHECK: # %bb.0: 53; CHECK-NEXT: jmp callee@PLT # TAILCALL 54 tail call preserve_nonecc void @callee(ptr %a) 55 ret void 56} 57 58; Preserve_none function can use more registers to pass parameters. 59declare preserve_nonecc i64 @callee_with_many_param2(i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11) 60define preserve_nonecc i64 @callee_with_many_param(i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12) { 61; CHECK-LABEL: callee_with_many_param: 62; CHECK: # %bb.0: 63; CHECK-NEXT: pushq %rax 64; CHECK-NEXT: .cfi_def_cfa_offset 16 65; CHECK-NEXT: movq %r13, %r12 66; CHECK-NEXT: movq %r14, %r13 67; CHECK-NEXT: movq %r15, %r14 68; CHECK-NEXT: movq %rdi, %r15 69; CHECK-NEXT: movq %rsi, %rdi 70; CHECK-NEXT: movq %rdx, %rsi 71; CHECK-NEXT: movq %rcx, %rdx 72; CHECK-NEXT: movq %r8, %rcx 73; CHECK-NEXT: movq %r9, %r8 74; CHECK-NEXT: movq %r11, %r9 75; CHECK-NEXT: movq %rax, %r11 76; CHECK-NEXT: callq callee_with_many_param2@PLT 77; CHECK-NEXT: popq %rcx 78; CHECK-NEXT: .cfi_def_cfa_offset 8 79; CHECK-NEXT: retq 80 %ret = call preserve_nonecc i64 @callee_with_many_param2(i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12) 81 ret i64 %ret 82} 83 84define i64 @caller3() { 85; CHECK-LABEL: caller3: 86; CHECK: # %bb.0: 87; CHECK-NEXT: pushq %r15 88; CHECK-NEXT: .cfi_def_cfa_offset 16 89; CHECK-NEXT: pushq %r14 90; CHECK-NEXT: .cfi_def_cfa_offset 24 91; CHECK-NEXT: pushq %r13 92; CHECK-NEXT: .cfi_def_cfa_offset 32 93; CHECK-NEXT: pushq %r12 94; CHECK-NEXT: .cfi_def_cfa_offset 40 95; CHECK-NEXT: pushq %rbx 96; CHECK-NEXT: .cfi_def_cfa_offset 48 97; CHECK-NEXT: .cfi_offset %rbx, -48 98; CHECK-NEXT: .cfi_offset %r12, -40 99; CHECK-NEXT: .cfi_offset %r13, -32 100; CHECK-NEXT: .cfi_offset %r14, -24 101; CHECK-NEXT: .cfi_offset %r15, -16 102; CHECK-NEXT: movl $1, %r12d 103; CHECK-NEXT: movl $2, %r13d 104; CHECK-NEXT: movl $3, %r14d 105; CHECK-NEXT: movl $4, %r15d 106; CHECK-NEXT: movl $5, %edi 107; CHECK-NEXT: movl $6, %esi 108; CHECK-NEXT: movl $7, %edx 109; CHECK-NEXT: movl $8, %ecx 110; CHECK-NEXT: movl $9, %r8d 111; CHECK-NEXT: movl $10, %r9d 112; CHECK-NEXT: movl $11, %r11d 113; CHECK-NEXT: movl $12, %eax 114; CHECK-NEXT: callq callee_with_many_param@PLT 115; CHECK-NEXT: popq %rbx 116; CHECK-NEXT: .cfi_def_cfa_offset 40 117; CHECK-NEXT: popq %r12 118; CHECK-NEXT: .cfi_def_cfa_offset 32 119; CHECK-NEXT: popq %r13 120; CHECK-NEXT: .cfi_def_cfa_offset 24 121; CHECK-NEXT: popq %r14 122; CHECK-NEXT: .cfi_def_cfa_offset 16 123; CHECK-NEXT: popq %r15 124; CHECK-NEXT: .cfi_def_cfa_offset 8 125; CHECK-NEXT: retq 126 %ret = call preserve_nonecc i64 @callee_with_many_param(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12) 127 ret i64 %ret 128} 129 130; Non-volatile registers are used to pass the first few parameters. 131declare void @boring() 132declare preserve_nonecc void @continuation(ptr, ptr, ptr, ptr) 133define preserve_nonecc void @entry(ptr %r12, ptr %r13, ptr %r14, ptr %r15) { 134; CHECK-LABEL: entry: 135; CHECK: # %bb.0: 136; CHECK-NEXT: pushq %rax 137; CHECK-NEXT: .cfi_def_cfa_offset 16 138; CHECK-NEXT: callq boring@PLT 139; CHECK-NEXT: popq %rax 140; CHECK-NEXT: .cfi_def_cfa_offset 8 141; CHECK-NEXT: jmp continuation@PLT # TAILCALL 142 call void @boring() 143 musttail call preserve_nonecc void @continuation(ptr %r12, ptr %r13, ptr %r14, ptr %r15) 144 ret void 145} 146