diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 44e001ceb6dc..be2d5b38c615 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -957,8 +957,16 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { else State.FreeRegs = DefaultNumRegisterParameters; - if (!getCXXABI().classifyReturnType(FI)) + if (!getCXXABI().classifyReturnType(FI)) { FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State); + } else if (FI.getReturnInfo().isIndirect()) { + // The C++ ABI is not aware of register usage, so we have to check if the + // return value was sret and put it in a register ourselves if appropriate. + if (State.FreeRegs) { + --State.FreeRegs; // The sret parameter consumes a register. + FI.getReturnInfo().setInReg(true); + } + } bool UsedInAlloca = false; for (auto &I : FI.arguments()) { diff --git a/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp index 2f8a66ea8e87..da58c461dcc0 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp @@ -33,3 +33,12 @@ int main() { // CHECK: call void {{.*}} @"\01?variadic_sret@C@@QAA?AUS@@PBDZZ" // CHECK: call void @"\01?cdecl_sret@C@@QAA?AUS@@XZ" // CHECK: call void @"\01?byval_and_sret@C@@QAA?AUS@@U2@@Z" + +// __fastcall has similar issues. +struct A { + S __fastcall f(int x); +}; +S A::f(int x) { + return S(); +} +// CHECK-LABEL: define x86_fastcallcc void @"\01?f@A@@QAI?AUS@@H@Z"(%struct.A* inreg %this, %struct.S* inreg noalias sret %agg.result, i32 %x)