Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -4157,9 +4157,9 @@ if (RegInfo->needsStackRealignment(MF)) return false; - // Also avoid sibcall optimization if either caller or callee uses struct - // return semantics. - if (isCalleeStructRet || isCallerStructRet) + // 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 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 } @@ -606,3 +596,86 @@ } declare fastcc double @foo20(double) nounwind + +; 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: jmp t21_f_sret # TAILCALL +; +; X64-LABEL: t21_sret_to_sret: +; X64: # %bb.0: +; X64-NEXT: jmp t21_f_sret # TAILCALL +; +; X32ABI-LABEL: t21_sret_to_sret: +; X32ABI: # %bb.0: +; 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 +; X32-NEXT: subl $8, %esp +; X32-NEXT: movl %ecx, %esi +; X32-NEXT: calll t21_f_non_sret +; X32-NEXT: movl %esi, %eax +; X32-NEXT: addl $8, %esp +; X32-NEXT: popl %esi +; X32-NEXT: retl +; +; 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 +; +; X32ABI-LABEL: t21_sret_to_non_sret: +; X32ABI: # %bb.0: +; X32ABI-NEXT: pushq %rbx +; X32ABI-NEXT: movl %edi, %ebx +; X32ABI-NEXT: callq t21_f_non_sret +; X32ABI-NEXT: movl %ebx, %eax +; X32ABI-NEXT: popq %rbx +; X32ABI-NEXT: retq + tail call fastcc void @t21_f_non_sret(%struct.foo* %agg.result) nounwind + ret void +} + +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: jmp t21_f_sret # TAILCALL +; +; X64-LABEL: t21_non_sret_to_sret: +; X64: # %bb.0: +; X64-NEXT: jmp t21_f_sret # TAILCALL +; +; X32ABI-LABEL: t21_non_sret_to_sret: +; X32ABI: # %bb.0: +; X32ABI-NEXT: jmp t21_f_sret # TAILCALL + tail call fastcc void @t21_f_sret(%struct.foo* noalias sret %agg.result) nounwind + ret void +} + +declare fastcc void @t21_f_sret(%struct.foo* noalias sret) nounwind +declare fastcc void @t21_f_non_sret(%struct.foo*) nounwind