aboutsummaryrefslogtreecommitdiffstats
path: root/test/CodeGen/X86/musttail-varargs.ll
blob: 1e99c141c03be7a2d3924f691128821544b63a2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
; RUN: llc < %s -enable-tail-merge=0 -mtriple=x86_64-linux | FileCheck %s --check-prefix=LINUX
; RUN: llc < %s -enable-tail-merge=0 -mtriple=x86_64-windows | FileCheck %s --check-prefix=WINDOWS

; Test that we actually spill and reload all arguments in the variadic argument
; pack. Doing a normal call will clobber all argument registers, and we will
; spill around it. A simple adjustment should not require any XMM spills.

declare void(i8*, ...)* @get_f(i8* %this)

define void @f_thunk(i8* %this, ...) {
  %fptr = call void(i8*, ...)*(i8*)* @get_f(i8* %this)
  musttail call void (i8*, ...)* %fptr(i8* %this, ...)
  ret void
}

; Save and restore 6 GPRs, 8 XMMs, and AL around the call.

; LINUX-LABEL: f_thunk:
; LINUX-DAG: movq %rdi, {{.*}}
; LINUX-DAG: movq %rsi, {{.*}}
; LINUX-DAG: movq %rdx, {{.*}}
; LINUX-DAG: movq %rcx, {{.*}}
; LINUX-DAG: movq %r8, {{.*}}
; LINUX-DAG: movq %r9, {{.*}}
; LINUX-DAG: movb %al, {{.*}}
; LINUX-DAG: movaps %xmm0, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm1, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm2, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm3, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm4, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm5, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm6, {{[0-9]*}}(%rsp)
; LINUX-DAG: movaps %xmm7, {{[0-9]*}}(%rsp)
; LINUX: callq get_f
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm0
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm1
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm2
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm3
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm4
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm5
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm6
; LINUX-DAG: movaps {{[0-9]*}}(%rsp), %xmm7
; LINUX-DAG: movq {{.*}}, %rdi
; LINUX-DAG: movq {{.*}}, %rsi
; LINUX-DAG: movq {{.*}}, %rdx
; LINUX-DAG: movq {{.*}}, %rcx
; LINUX-DAG: movq {{.*}}, %r8
; LINUX-DAG: movq {{.*}}, %r9
; LINUX-DAG: movb {{.*}}, %al
; LINUX: jmpq *{{.*}}  # TAILCALL

; WINDOWS-LABEL: f_thunk:
; WINDOWS-NOT: mov{{.}}ps
; WINDOWS-DAG: movq %rdx, {{.*}}
; WINDOWS-DAG: movq %rcx, {{.*}}
; WINDOWS-DAG: movq %r8, {{.*}}
; WINDOWS-DAG: movq %r9, {{.*}}
; WINDOWS-NOT: mov{{.}}ps
; WINDOWS: callq get_f
; WINDOWS-NOT: mov{{.}}ps
; WINDOWS-DAG: movq {{.*}}, %rdx
; WINDOWS-DAG: movq {{.*}}, %rcx
; WINDOWS-DAG: movq {{.*}}, %r8
; WINDOWS-DAG: movq {{.*}}, %r9
; WINDOWS-NOT: mov{{.}}ps
; WINDOWS: jmpq *{{.*}} # TAILCALL

; This thunk shouldn't require any spills and reloads, assuming the register
; allocator knows what it's doing.

define void @g_thunk(i8* %fptr_i8, ...) {
  %fptr = bitcast i8* %fptr_i8 to void (i8*, ...)*
  musttail call void (i8*, ...)* %fptr(i8* %fptr_i8, ...)
  ret void
}

; LINUX-LABEL: g_thunk:
; LINUX-NOT: movq
; LINUX: jmpq *%rdi  # TAILCALL

; WINDOWS-LABEL: g_thunk:
; WINDOWS-NOT: movq
; WINDOWS: jmpq *%rcx # TAILCALL

; Do a simple multi-exit multi-bb test.

%struct.Foo = type { i1, i8*, i8* }

@g = external global i32

define void @h_thunk(%struct.Foo* %this, ...) {
  %cond_p = getelementptr %struct.Foo* %this, i32 0, i32 0
  %cond = load i1* %cond_p
  br i1 %cond, label %then, label %else

then:
  %a_p = getelementptr %struct.Foo* %this, i32 0, i32 1
  %a_i8 = load i8** %a_p
  %a = bitcast i8* %a_i8 to void (%struct.Foo*, ...)*
  musttail call void (%struct.Foo*, ...)* %a(%struct.Foo* %this, ...)
  ret void

else:
  %b_p = getelementptr %struct.Foo* %this, i32 0, i32 2
  %b_i8 = load i8** %b_p
  %b = bitcast i8* %b_i8 to void (%struct.Foo*, ...)*
  store i32 42, i32* @g
  musttail call void (%struct.Foo*, ...)* %b(%struct.Foo* %this, ...)
  ret void
}

; LINUX-LABEL: h_thunk:
; LINUX: jne
; LINUX: jmpq *{{.*}} # TAILCALL
; LINUX: jmpq *{{.*}} # TAILCALL
; WINDOWS-LABEL: h_thunk:
; WINDOWS: jne
; WINDOWS: jmpq *{{.*}} # TAILCALL
; WINDOWS: jmpq *{{.*}} # TAILCALL