]> granicus.if.org Git - clang/commitdiff
MS ABI: Return sret parameters when using inalloca
authorReid Kleckner <reid@kleckner.net>
Tue, 25 Feb 2014 00:59:14 +0000 (00:59 +0000)
committerReid Kleckner <reid@kleckner.net>
Tue, 25 Feb 2014 00:59:14 +0000 (00:59 +0000)
Previously the X86 backend would look for the sret attribute and handle
this for us.  inalloca takes that all away, so we have to do the return
ourselves now.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202097 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/CodeGen/CGFunctionInfo.h
lib/CodeGen/CGCall.cpp
lib/CodeGen/TargetInfo.cpp
test/CodeGenCXX/microsoft-abi-byval-sret.cpp

index cb8c5a01182b2397c6f99bf0303ae6057927b9cf..ec41e8bdec2534291a3617b20ad2b20b1035c5d7 100644 (file)
@@ -191,6 +191,18 @@ public:
     return UIntData;
   }
 
+  /// \brief Return true if this field of an inalloca struct should be returned
+  /// to implement a struct return calling convention.
+  bool getInAllocaSRet() const {
+    assert(TheKind == InAlloca && "Invalid kind!");
+    return BoolData0;
+  }
+
+  void setInAllocaSRet(bool SRet) {
+    assert(TheKind == InAlloca && "Invalid kind!");
+    BoolData0 = SRet;
+  }
+
   void dump() const;
 };
 
index a21e4783b60b26376a2c3950c69e331ffda01e79..756b0b2b605c75f9cc89749436ad2851bab8cc94 100644 (file)
@@ -940,7 +940,15 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
     break;
 
   case ABIArgInfo::InAlloca:
-    resultType = llvm::Type::getVoidTy(getLLVMContext());
+    if (retAI.getInAllocaSRet()) {
+      // sret things on win32 aren't void, they return the sret pointer.
+      QualType ret = FI.getReturnType();
+      llvm::Type *ty = ConvertType(ret);
+      unsigned addressSpace = Context.getTargetAddressSpace(ret);
+      resultType = llvm::PointerType::get(ty, addressSpace);
+    } else {
+      resultType = llvm::Type::getVoidTy(getLLVMContext());
+    }
     break;
 
   case ABIArgInfo::Indirect: {
@@ -1779,7 +1787,17 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
 
   switch (RetAI.getKind()) {
   case ABIArgInfo::InAlloca:
-    // Do nothing; aggregrates get evaluated directly into the destination.
+    // Aggregrates get evaluated directly into the destination.  Sometimes we
+    // need to return the sret value in a register, though.
+    assert(hasAggregateEvaluationKind(RetTy));
+    if (RetAI.getInAllocaSRet()) {
+      llvm::Function::arg_iterator EI = CurFn->arg_end();
+      --EI;
+      llvm::Value *ArgStruct = EI;
+      llvm::Value *SRet =
+          Builder.CreateStructGEP(ArgStruct, RetAI.getInAllocaFieldIndex());
+      RV = Builder.CreateLoad(SRet, "sret");
+    }
     break;
 
   case ABIArgInfo::Indirect: {
index 05cb21dd1905dd7271323501e9f8cf092a467dad..e1c586a7d287be33d99d6623f11612a795c8bf1d 100644 (file)
@@ -1061,6 +1061,8 @@ void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
   if (Ret.isIndirect() && !Ret.getInReg()) {
     CanQualType PtrTy = getContext().getPointerType(FI.getReturnType());
     addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy);
+    // On Windows, the hidden sret parameter is always returned in eax.
+    Ret.setInAllocaSRet(IsWin32StructABI);
   }
 
   // Skip the 'this' parameter in ecx.
index 00d36b7d492442792858492fe2ed7e579137770c..985b1ce62e924d80637d5c0360bb948b23f0a733 100644 (file)
@@ -14,13 +14,16 @@ A A::foo(A x) {
   return y;
 }
 
-// CHECK: define x86_thiscallcc void @"\01?foo@A@@QAE?AU1@U1@@Z"
+// CHECK-LABEL: define x86_thiscallcc %struct.A* @"\01?foo@A@@QAE?AU1@U1@@Z"
 // CHECK:       (%struct.A* %this, <{ %struct.A*, %struct.A }>* inalloca)
+// CHECK:   getelementptr inbounds <{ %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 0
+// CHECK:   load %struct.A**
+// CHECK:   ret %struct.A*
 
 int main() {
   A x;
   A y = x.foo(x);
 }
 
-// CHECK: call x86_thiscallcc void @"\01?foo@A@@QAE?AU1@U1@@Z"
+// CHECK: call x86_thiscallcc %struct.A* @"\01?foo@A@@QAE?AU1@U1@@Z"
 // CHECK:       (%struct.A* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}})