Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -4183,10 +4183,10 @@ if (RegInfo->needsStackRealignment(MF)) return false; - // Also avoid sibcall optimization if either caller or callee uses struct - // return semantics. - if (isCalleeStructRet || isCallerStructRet) - return false; + // Struct-return functions need to return its argument in RAX, so they can not + // sibcall non-struct-return functions. + if (!isCalleeStructRet && isCallerStructRet) + return false; // Do not sibcall optimize vararg calls unless all arguments are passed via // registers. Index: test/CodeGen/X86/sibcall.ll =================================================================== --- test/CodeGen/X86/sibcall.ll +++ test/CodeGen/X86/sibcall.ll @@ -448,21 +448,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 ; ; X32ABI-LABEL: t15: ; X32ABI: # %bb.0: -; X32ABI-NEXT: pushq %rbx -; X32ABI-NEXT: movl %edi, %ebx -; X32ABI-NEXT: callq f -; X32ABI-NEXT: movl %ebx, %eax -; X32ABI-NEXT: popq %rbx -; X32ABI-NEXT: retq +; X32ABI-NEXT: jmp f # TAILCALL tail call fastcc void @f(%struct.foo* noalias sret %agg.result) nounwind ret void } @@ -609,49 +599,22 @@ ; bug 28417 define fastcc void @t21_sret_to_sret(%struct.foo* noalias sret %agg.result) nounwind { -; 32-LABEL: t21_sret_to_sret: -; 32: jmp {{_?}}t21_f_sret -; 64-LABEL: t21_sret_to_sret: -; 64: jmp {{_?}}t21_f_sret ; X32-LABEL: t21_sret_to_sret: ; X32: # %bb.0: -; X32-NEXT: pushl %esi -; X32-NEXT: subl $8, %esp -; X32-NEXT: movl %ecx, %esi -; X32-NEXT: calll t21_f_sret -; X32-NEXT: movl %esi, %eax -; X32-NEXT: addl $8, %esp -; X32-NEXT: popl %esi -; X32-NEXT: retl +; X32-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 ; ; X32ABI-LABEL: t21_sret_to_sret: ; X32ABI: # %bb.0: -; X32ABI-NEXT: pushq %rbx -; X32ABI-NEXT: movl %edi, %ebx -; X32ABI-NEXT: callq t21_f_sret -; X32ABI-NEXT: movl %ebx, %eax -; X32ABI-NEXT: popq %rbx -; X32ABI-NEXT: retq +; X32ABI-NEXT: jmp t21_f_sret # TAILCALL tail call fastcc void @t21_f_sret(%struct.foo* noalias sret %agg.result) nounwind ret void } define fastcc void @t21_sret_to_non_sret(%struct.foo* noalias sret %agg.result) nounwind { -; 32-LABEL: t21_sret_to_non_sret: -; 32: calll {{_?}}t21_f_non_sret -; 32: retl -; 64-LABEL: t21_sret_to_non_sret: -; 64: callq {{_?}}t21_f_non_sret -; 64: retq ; X32-LABEL: t21_sret_to_non_sret: ; X32: # %bb.0: ; X32-NEXT: pushl %esi @@ -685,30 +648,17 @@ } define fastcc void @t21_non_sret_to_sret(%struct.foo* %agg.result) nounwind { -; 32-LABEL: t21_non_sret_to_sret: -; 32: jmp {{_?}}t21_f_sret -; 64-LABEL: t21_non_sret_to_sret: -; 64: jmp {{_?}}t21_f_sret ; X32-LABEL: t21_non_sret_to_sret: ; X32: # %bb.0: -; X32-NEXT: subl $12, %esp -; X32-NEXT: calll t21_f_sret -; X32-NEXT: addl $12, %esp -; X32-NEXT: retl +; X32-NEXT: jmp t21_f_sret # TAILCALL ; ; X64-LABEL: t21_non_sret_to_sret: ; X64: # %bb.0: -; X64-NEXT: pushq %rax -; X64-NEXT: callq t21_f_sret -; X64-NEXT: popq %rax -; X64-NEXT: retq +; X64-NEXT: jmp t21_f_sret # TAILCALL ; ; X32ABI-LABEL: t21_non_sret_to_sret: ; X32ABI: # %bb.0: -; X32ABI-NEXT: pushq %rax -; X32ABI-NEXT: callq t21_f_sret -; X32ABI-NEXT: popq %rax -; X32ABI-NEXT: retq +; X32ABI-NEXT: jmp t21_f_sret # TAILCALL tail call fastcc void @t21_f_sret(%struct.foo* noalias sret %agg.result) nounwind ret void }