From 5b7370af534c437fd60456e955c36820e44c7513 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 25 Feb 2014 00:59:14 +0000 Subject: [PATCH] MS ABI: Return sret parameters when using inalloca 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 | 12 +++++++++++ lib/CodeGen/CGCall.cpp | 22 ++++++++++++++++++-- lib/CodeGen/TargetInfo.cpp | 2 ++ test/CodeGenCXX/microsoft-abi-byval-sret.cpp | 7 +++++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h index cb8c5a0118..ec41e8bdec 100644 --- a/include/clang/CodeGen/CGFunctionInfo.h +++ b/include/clang/CodeGen/CGFunctionInfo.h @@ -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; }; diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index a21e4783b6..756b0b2b60 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -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: { diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 05cb21dd19..e1c586a7d2 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -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. diff --git a/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/test/CodeGenCXX/microsoft-abi-byval-sret.cpp index 00d36b7d49..985b1ce62e 100644 --- a/test/CodeGenCXX/microsoft-abi-byval-sret.cpp +++ b/test/CodeGenCXX/microsoft-abi-byval-sret.cpp @@ -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 %{{[^,]*}}) -- 2.40.0