Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -4155,9 +4155,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 @@ -307,12 +307,10 @@ ; 32: retl $4 ; 64-LABEL: t15: -; 64: callq {{_?}}f -; 64: retq +; 64: jmp {{_?}}f ; X32ABI-LABEL: t15: -; X32ABI: callq {{_?}}f -; X32ABI: retq +; X32ABI: jmp {{_?}}f tail call fastcc void @f(%struct.foo* noalias sret %agg.result) nounwind ret void } @@ -408,3 +406,49 @@ } 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 + +; X32ABI-LABEL: t21_sret_to_sret: +; X32ABI: jmp {{_?}}t21_f_sret + 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 + +; X32ABI-LABEL: t21_sret_to_non_sret: +; X32ABI: callq {{_?}}t21_f_non_sret +; X32ABI: 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 + +; X32ABI-LABEL: t21_non_sret_to_sret: +; X32ABI: jmp {{_?}}t21_f_sret + 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