xref: /llvm-project/llvm/test/CodeGen/X86/preserve_nonecc_call.ll (revision d3e77f5408fded2b4bb70f51d6d9e52684badc92)
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