; 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 ; RUN: llc < %s -enable-tail-merge=0 -mtriple=i686-windows | FileCheck %s --check-prefix=X86 ; 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 @llvm.va_start(i8*) nounwind declare void(i8*, ...)* @get_f(i8* %this) define void @f_thunk(i8* %this, ...) { ; Use va_start so that we exercise the combination. %ap = alloca [4 x i8*], align 16 %ap_i8 = bitcast [4 x i8*]* %ap to i8* call void @llvm.va_start(i8* %ap_i8) %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 ; No regparms on normal x86 conventions. ; X86-LABEL: _f_thunk: ; X86: calll _get_f ; X86: jmpl *{{.*}} # 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 ; X86-LABEL: _g_thunk: ; X86: jmpl *%eax # 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, %struct.Foo* %this, i32 0, i32 0 %cond = load i1, i1* %cond_p br i1 %cond, label %then, label %else then: %a_p = getelementptr %struct.Foo, %struct.Foo* %this, i32 0, i32 1 %a_i8 = load i8*, 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, %struct.Foo* %this, i32 0, i32 2 %b_i8 = load i8*, 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 ; X86-LABEL: _h_thunk: ; X86: jne ; X86: jmpl *{{.*}} # TAILCALL ; X86: jmpl *{{.*}} # TAILCALL