From 10ee1173aacfe673b36255be3dad366665298499 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <reid@kleckner.net>
Date: Thu, 10 Jul 2014 01:58:55 +0000
Subject: [PATCH] MS ABI: Fix __fastcall methods that return structs

The sret paramater consumes the register after the implicit 'this'
parameter, as with other calling conventions.

Fixes PR20278, which turned out to be very easy.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@212669 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/TargetInfo.cpp                          | 10 +++++++++-
 test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp |  9 +++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 44e001ceb6d..be2d5b38c61 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/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/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp b/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp
index 2f8a66ea8e8..da58c461dcc 100644
--- a/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp
+++ b/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)
-- 
GitLab