Index: clang/test/CodeGenCXX/pr51000.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/pr51000.cpp @@ -0,0 +1,107 @@ +// RUN: %clang -S %s -o - -O2 -Xclang -triple=x86_64-linux | FileCheck %s --check-prefix=X86 --check-prefix=X86_64 +// RUN: %clang -S %s -o - -O2 -Xclang -triple=x86_64-linux-gnux32 | FileCheck %s --check-prefix=X86 --check-prefix=X86_32 +// RUN: %clang -S %s -o - -O2 -Xclang -triple=x86_64-win64 | FileCheck %s --check-prefix=X86 --check-prefix=X86_64 +// RUN: %clang -S %s -o - -O2 -Xclang -triple=x86_64-win32 | FileCheck %s --check-prefix=X86_WIN + +inline void *operator new(decltype(sizeof(0)), void *p) noexcept { + return p; +} +inline void operator delete(void *p, decltype(sizeof(0))) noexcept { +} + +namespace One { // pr 51000 + +struct T { + int x; + T(int) + noexcept; + ~T(); +}; + +T factory(int) noexcept; + +alignas(T) char buffer[sizeof(T)]; + +void placement_new() { + // tailcallable ctor + ::new ((void *)buffer) T(42); +} +// X86-LABEL: _ZN3One13placement_newEv: +// X86: jmp _ZN3One1TC1Ei # TAILCALL +// X86_WIN-LABEL: "?placement_new@One@@YAXXZ": +// X86_WIN: jmp "??0T@One@@QEAA@H@Z" # TAILCALL + +void placement_call() { + // tailcallable factory + ::new ((void *)buffer) T(factory(42)); +} +// X86-LABEL: _ZN3One14placement_callEv: +// X86: jmp _ZN3One7factoryEi # TAILCALL +// X86_WIN-LABEL: "?placement_call@One@@YAXXZ": +// X86_WIN: jmp "?factory@One@@YA?AUT@1@H@Z" # TAILCALL + +} // namespace One + +namespace Two { + +struct A { // return in register + int m; +}; + +A foo(); + +A baz() { + // tailcallable + return foo(); +} +// X86-LABEL: _ZN3Two3bazEv: +// X86: jmp _ZN3Two3fooEv # TAILCALL +// X86_WIN-LABEL: "?baz@Two@@YA?AUA@1@XZ": +// X86_WIN: "?foo@Two@@YA?AUA@1@XZ" # TAILCALL + +void bar() { + // tailcallable + foo(); +} +// X86-LABEL: _ZN3Two3barEv: +// X86: jmp _ZN3Two3fooEv # TAILCALL +// X86_WIN-LABEL: "?bar@Two@@YAXXZ": +// X86_WIN: "?foo@Two@@YA?AUA@1@XZ" # TAILCALL + +} // namespace Two + +namespace Three { + +struct A { // return via pointer + int m[16]; +}; + +A foo(); + +A baz() { + // tailcallable + return foo(); +} +// X86-LABEL: _ZN5Three3bazEv: +// X86: jmp _ZN5Three3fooEv # TAILCALL +// X86_WIN-LABEL: "?baz@Three@@YA?AUA@1@XZ": +// X86_WIN: "?foo@Three@@YA?AUA@1@XZ" # TAILCALL + +void bar() { + // NOT tailcallable + foo(); +} +// X86-LABEL: _ZN5Three3barEv: +// X86_64: subq ${{[0-9]+}}, %rsp +// X86_32: subl ${{[0-9]+}}, %esp +// X86: callq _ZN5Three3fooEv +// X86_64: addq ${{[0-9]+}}, %rsp +// X86_32: addl ${{[0-9]+}}, %esp +// X86: retq +// X86_WIN-LABEL: "?bar@Three@@YAXXZ": +// X86_WIN: subq ${{[0-9]+}}, %rsp +// X86_WIN: callq "?foo@Three@@YA?AUA@1@XZ" +// X86_WIN: addq ${{[0-9]+}}, %rsp +// X86_WIN: retq + +} // namespace Three Index: llvm/lib/Target/X86/X86ISelLowering.h =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.h +++ llvm/lib/Target/X86/X86ISelLowering.h @@ -1475,8 +1475,6 @@ bool IsEligibleForTailCallOptimization(SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, - bool isCalleeStructRet, - bool isCallerStructRet, Type *RetTy, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -3951,10 +3951,8 @@ if (isTailCall && !IsMustTail) { // Check if it's really possible to do a tail call. - isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, - isVarArg, SR != NotStructReturn, - MF.getFunction().hasStructRetAttr(), CLI.RetTy, - Outs, OutVals, Ins, DAG); + isTailCall = IsEligibleForTailCallOptimization( + Callee, CallConv, isVarArg, CLI.RetTy, Outs, OutVals, Ins, DAG); // Sibcalls are automatically detected tailcalls which do not require // ABI changes. @@ -4629,8 +4627,7 @@ /// Check whether the call is eligible for tail call optimization. Targets /// that want to do tail call optimization should implement this function. bool X86TargetLowering::IsEligibleForTailCallOptimization( - SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, - bool isCalleeStructRet, bool isCallerStructRet, Type *RetTy, + SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, Type *RetTy, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SmallVectorImpl &Ins, SelectionDAG &DAG) const { @@ -4675,11 +4672,6 @@ if (RegInfo->hasStackRealignment(MF)) return false; - // Also avoid sibcall optimization if either caller or callee uses struct - // return semantics. - if (isCalleeStructRet || isCallerStructRet) - return false; - // Do not sibcall optimize vararg calls unless all arguments are passed via // registers. LLVMContext &C = *DAG.getContext(); Index: llvm/test/CodeGen/X86/sibcall.ll =================================================================== --- llvm/test/CodeGen/X86/sibcall.ll +++ llvm/test/CodeGen/X86/sibcall.ll @@ -2,6 +2,7 @@ ; RUN: llc -verify-machineinstrs < %s -mtriple=i686-linux -mcpu=core2 -mattr=+sse2 | FileCheck %s --check-prefix=X86 ; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-linux -mcpu=core2 -mattr=+sse2 | FileCheck %s --check-prefix=X64 ; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-linux-gnux32 -mcpu=core2 -mattr=+sse2 | FileCheck %s --check-prefix=X32 +; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-win64 -mcpu=core2 -mattr=+sse2 | FileCheck %s --check-prefix=X64 define dso_local void @t1(i32 %x) nounwind ssp { ; X86-LABEL: t1: @@ -464,21 +465,11 @@ ; ; X64-LABEL: t15: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rdi, %rbx -; X64-NEXT: callq f -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: jmp f # TAILCALL ; ; X32-LABEL: t15: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rdi, %rbx -; X32-NEXT: callq f -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: jmp f # TAILCALL tail call fastcc void @f(%struct.foo* noalias sret(%struct.foo) %agg.result) nounwind ret void } @@ -627,32 +618,15 @@ define fastcc void @t21_sret_to_sret(%struct.foo* noalias sret(%struct.foo) %agg.result) nounwind { ; X86-LABEL: t21_sret_to_sret: ; X86: # %bb.0: -; X86-NEXT: pushl %esi -; X86-NEXT: subl $8, %esp -; X86-NEXT: movl %ecx, %esi -; X86-NEXT: calll t21_f_sret -; X86-NEXT: movl %esi, %eax -; X86-NEXT: addl $8, %esp -; X86-NEXT: popl %esi -; X86-NEXT: retl +; X86-NEXT: jmp t21_f_sret # TAILCALL ; ; X64-LABEL: t21_sret_to_sret: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rdi, %rbx -; X64-NEXT: callq t21_f_sret -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: jmp t21_f_sret # TAILCALL ; ; X32-LABEL: t21_sret_to_sret: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rdi, %rbx -; X32-NEXT: callq t21_f_sret -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: jmp t21_f_sret # TAILCALL tail call fastcc void @t21_f_sret(%struct.foo* noalias sret(%struct.foo) %agg.result) nounwind ret void } @@ -701,34 +675,15 @@ define fastcc void @t21_sret_to_sret_more_args(%struct.foo* noalias sret(%struct.foo) %agg.result, i32 %a, i32 %b) nounwind { ; X86-LABEL: t21_sret_to_sret_more_args: ; X86: # %bb.0: -; X86-NEXT: pushl %esi -; X86-NEXT: subl $8, %esp -; X86-NEXT: movl %ecx, %esi -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: movl %eax, (%esp) -; X86-NEXT: calll f_sret@PLT -; X86-NEXT: movl %esi, %eax -; X86-NEXT: addl $8, %esp -; X86-NEXT: popl %esi -; X86-NEXT: retl +; X86-NEXT: jmp f_sret@PLT # TAILCALL ; ; X64-LABEL: t21_sret_to_sret_more_args: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rdi, %rbx -; X64-NEXT: callq f_sret@PLT -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: jmp f_sret@PLT # TAILCALL ; ; X32-LABEL: t21_sret_to_sret_more_args: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rdi, %rbx -; X32-NEXT: callq f_sret@PLT -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: jmp f_sret@PLT # TAILCALL tail call fastcc void @f_sret(%struct.foo* noalias sret(%struct.foo) %agg.result, i32 %a, i32 %b) nounwind ret void } @@ -736,35 +691,18 @@ define fastcc void @t21_sret_to_sret_second_arg_sret(%struct.foo* noalias %agg.result, %struct.foo* noalias sret(%struct.foo) %ret) nounwind { ; X86-LABEL: t21_sret_to_sret_second_arg_sret: ; X86: # %bb.0: -; X86-NEXT: pushl %esi -; X86-NEXT: subl $8, %esp -; X86-NEXT: movl %edx, %esi -; X86-NEXT: movl %edx, %ecx -; X86-NEXT: calll t21_f_sret -; X86-NEXT: movl %esi, %eax -; X86-NEXT: addl $8, %esp -; X86-NEXT: popl %esi -; X86-NEXT: retl +; X86-NEXT: movl %edx, %ecx +; X86-NEXT: jmp t21_f_sret # TAILCALL ; ; X64-LABEL: t21_sret_to_sret_second_arg_sret: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rsi, %rbx -; X64-NEXT: movq %rsi, %rdi -; X64-NEXT: callq t21_f_sret -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: movq %rsi, %rdi +; X64-NEXT: jmp t21_f_sret # TAILCALL ; ; X32-LABEL: t21_sret_to_sret_second_arg_sret: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rsi, %rbx -; X32-NEXT: movq %rsi, %rdi -; X32-NEXT: callq t21_f_sret -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: movq %rsi, %rdi +; X32-NEXT: jmp t21_f_sret # TAILCALL tail call fastcc void @t21_f_sret(%struct.foo* noalias sret(%struct.foo) %ret) nounwind ret void } @@ -786,27 +724,17 @@ ; ; X64-LABEL: t21_sret_to_sret_more_args2: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx ; X64-NEXT: movl %esi, %eax -; X64-NEXT: movq %rdi, %rbx ; X64-NEXT: movl %edx, %esi ; X64-NEXT: movl %eax, %edx -; X64-NEXT: callq f_sret@PLT -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: jmp f_sret@PLT # TAILCALL ; ; X32-LABEL: t21_sret_to_sret_more_args2: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx ; X32-NEXT: movl %esi, %eax -; X32-NEXT: movq %rdi, %rbx ; X32-NEXT: movl %edx, %esi ; X32-NEXT: movl %eax, %edx -; X32-NEXT: callq f_sret@PLT -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: jmp f_sret@PLT # TAILCALL tail call fastcc void @f_sret(%struct.foo* noalias sret(%struct.foo) %agg.result, i32 %b, i32 %a) nounwind ret void } @@ -815,35 +743,18 @@ define fastcc void @t21_sret_to_sret_args_mismatch(%struct.foo* noalias sret(%struct.foo) %agg.result, %struct.foo* noalias %ret) nounwind { ; X86-LABEL: t21_sret_to_sret_args_mismatch: ; X86: # %bb.0: -; X86-NEXT: pushl %esi -; X86-NEXT: subl $8, %esp -; X86-NEXT: movl %ecx, %esi -; X86-NEXT: movl %edx, %ecx -; X86-NEXT: calll t21_f_sret -; X86-NEXT: movl %esi, %eax -; X86-NEXT: addl $8, %esp -; X86-NEXT: popl %esi -; X86-NEXT: retl +; X86-NEXT: movl %edx, %ecx +; X86-NEXT: jmp t21_f_sret # TAILCALL ; ; X64-LABEL: t21_sret_to_sret_args_mismatch: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rdi, %rbx -; X64-NEXT: movq %rsi, %rdi -; X64-NEXT: callq t21_f_sret -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: movq %rsi, %rdi +; X64-NEXT: jmp t21_f_sret # TAILCALL ; ; X32-LABEL: t21_sret_to_sret_args_mismatch: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rdi, %rbx -; X32-NEXT: movq %rsi, %rdi -; X32-NEXT: callq t21_f_sret -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: movq %rsi, %rdi +; X32-NEXT: jmp t21_f_sret # TAILCALL tail call fastcc void @t21_f_sret(%struct.foo* noalias sret(%struct.foo) %ret) nounwind ret void } @@ -851,35 +762,18 @@ define fastcc void @t21_sret_to_sret_args_mismatch2(%struct.foo* noalias sret(%struct.foo) %agg.result, %struct.foo* noalias %ret) nounwind { ; X86-LABEL: t21_sret_to_sret_args_mismatch2: ; X86: # %bb.0: -; X86-NEXT: pushl %esi -; X86-NEXT: subl $8, %esp -; X86-NEXT: movl %ecx, %esi -; X86-NEXT: movl %edx, %ecx -; X86-NEXT: calll t21_f_sret -; X86-NEXT: movl %esi, %eax -; X86-NEXT: addl $8, %esp -; X86-NEXT: popl %esi -; X86-NEXT: retl +; X86-NEXT: movl %edx, %ecx +; X86-NEXT: jmp t21_f_sret # TAILCALL ; ; X64-LABEL: t21_sret_to_sret_args_mismatch2: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rdi, %rbx -; X64-NEXT: movq %rsi, %rdi -; X64-NEXT: callq t21_f_sret -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: movq %rsi, %rdi +; X64-NEXT: jmp t21_f_sret # TAILCALL ; ; X32-LABEL: t21_sret_to_sret_args_mismatch2: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rdi, %rbx -; X32-NEXT: movq %rsi, %rdi -; X32-NEXT: callq t21_f_sret -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: movq %rsi, %rdi +; X32-NEXT: jmp t21_f_sret # TAILCALL tail call fastcc void @t21_f_sret(%struct.foo* noalias sret(%struct.foo) %ret) nounwind ret void } @@ -927,54 +821,35 @@ define fastcc void @t21_sret_to_sret_structs_mismatch(%struct.foo* noalias sret(%struct.foo) %agg.result, %struct.foo* noalias %a) nounwind { ; X86-LABEL: t21_sret_to_sret_structs_mismatch: ; X86: # %bb.0: -; X86-NEXT: pushl %edi -; X86-NEXT: pushl %esi -; X86-NEXT: pushl %eax -; X86-NEXT: movl %edx, %esi -; X86-NEXT: movl %ecx, %edi -; X86-NEXT: calll ret_struct@PLT -; X86-NEXT: movl %esi, %ecx -; X86-NEXT: movl %eax, %edx -; X86-NEXT: calll t21_f_sret2 -; X86-NEXT: movl %edi, %eax -; X86-NEXT: addl $4, %esp -; X86-NEXT: popl %esi -; X86-NEXT: popl %edi -; X86-NEXT: retl +; X86-NEXT: pushl %esi +; X86-NEXT: subl $8, %esp +; X86-NEXT: movl %edx, %esi +; X86-NEXT: calll ret_struct@PLT +; X86-NEXT: movl %esi, %ecx +; X86-NEXT: movl %eax, %edx +; X86-NEXT: addl $8, %esp +; X86-NEXT: popl %esi +; X86-NEXT: jmp t21_f_sret2 # TAILCALL ; ; X64-LABEL: t21_sret_to_sret_structs_mismatch: ; X64: # %bb.0: -; X64-NEXT: pushq %r14 ; X64-NEXT: pushq %rbx -; X64-NEXT: pushq %rax ; X64-NEXT: movq %rsi, %rbx -; X64-NEXT: movq %rdi, %r14 ; X64-NEXT: callq ret_struct@PLT ; X64-NEXT: movq %rbx, %rdi ; X64-NEXT: movq %rax, %rsi -; X64-NEXT: callq t21_f_sret2 -; X64-NEXT: movq %r14, %rax -; X64-NEXT: addq $8, %rsp ; X64-NEXT: popq %rbx -; X64-NEXT: popq %r14 -; X64-NEXT: retq +; X64-NEXT: jmp t21_f_sret2 # TAILCALL ; ; X32-LABEL: t21_sret_to_sret_structs_mismatch: ; X32: # %bb.0: -; X32-NEXT: pushq %r14 ; X32-NEXT: pushq %rbx -; X32-NEXT: pushq %rax ; X32-NEXT: movq %rsi, %rbx -; X32-NEXT: movq %rdi, %r14 ; X32-NEXT: callq ret_struct@PLT ; X32-NEXT: movl %eax, %esi ; X32-NEXT: movq %rbx, %rdi -; X32-NEXT: callq t21_f_sret2 -; X32-NEXT: movl %r14d, %eax -; X32-NEXT: addl $8, %esp ; X32-NEXT: popq %rbx -; X32-NEXT: popq %r14 -; X32-NEXT: retq +; X32-NEXT: jmp t21_f_sret2 # TAILCALL %b = call fastcc %struct.foo* @ret_struct() tail call fastcc void @t21_f_sret2(%struct.foo* noalias sret(%struct.foo) %a, %struct.foo* noalias %b) nounwind ret void @@ -986,32 +861,15 @@ define fastcc void @t21_sret_to_non_sret(%struct.foo* noalias sret(%struct.foo) %agg.result) nounwind { ; X86-LABEL: t21_sret_to_non_sret: ; X86: # %bb.0: -; X86-NEXT: pushl %esi -; X86-NEXT: subl $8, %esp -; X86-NEXT: movl %ecx, %esi -; X86-NEXT: calll t21_f_non_sret -; X86-NEXT: movl %esi, %eax -; X86-NEXT: addl $8, %esp -; X86-NEXT: popl %esi -; X86-NEXT: retl +; X86-NEXT: jmp t21_f_non_sret # TAILCALL ; ; X64-LABEL: t21_sret_to_non_sret: ; X64: # %bb.0: -; X64-NEXT: pushq %rbx -; X64-NEXT: movq %rdi, %rbx -; X64-NEXT: callq t21_f_non_sret -; X64-NEXT: movq %rbx, %rax -; X64-NEXT: popq %rbx -; X64-NEXT: retq +; X64-NEXT: jmp t21_f_non_sret # TAILCALL ; ; X32-LABEL: t21_sret_to_non_sret: ; X32: # %bb.0: -; X32-NEXT: pushq %rbx -; X32-NEXT: movq %rdi, %rbx -; X32-NEXT: callq t21_f_non_sret -; X32-NEXT: movl %ebx, %eax -; X32-NEXT: popq %rbx -; X32-NEXT: retq +; X32-NEXT: jmp t21_f_non_sret # TAILCALL tail call fastcc void @t21_f_non_sret(%struct.foo* %agg.result) nounwind ret void } @@ -1020,26 +878,15 @@ define ccc void @t22_non_sret_to_sret(%struct.foo* %agg.result) nounwind { ; X86-LABEL: t22_non_sret_to_sret: ; X86: # %bb.0: -; X86-NEXT: subl $12, %esp -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: movl %eax, (%esp) -; X86-NEXT: calll t22_f_sret@PLT -; X86-NEXT: addl $8, %esp -; X86-NEXT: retl +; X86-NEXT: jmp t22_f_sret@PLT # TAILCALL ; ; X64-LABEL: t22_non_sret_to_sret: ; X64: # %bb.0: -; X64-NEXT: pushq %rax -; X64-NEXT: callq t22_f_sret@PLT -; X64-NEXT: popq %rax -; X64-NEXT: retq +; X64-NEXT: jmp t22_f_sret@PLT # TAILCALL ; ; X32-LABEL: t22_non_sret_to_sret: ; X32: # %bb.0: -; X32-NEXT: pushq %rax -; X32-NEXT: callq t22_f_sret@PLT -; X32-NEXT: popq %rax -; X32-NEXT: retq +; X32-NEXT: jmp t22_f_sret@PLT # TAILCALL tail call ccc void @t22_f_sret(%struct.foo* noalias sret(%struct.foo) %agg.result) nounwind ret void }