diff options
-rw-r--r-- | clang/include/clang/CodeGen/CGFunctionInfo.h | 12 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 22 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 2 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp | 7 |
4 files changed, 39 insertions, 4 deletions
diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index cb8c5a01182..ec41e8bdec2 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/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/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a21e4783b60..756b0b2b605 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/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/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 05cb21dd190..e1c586a7d28 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/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/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp index 00d36b7d492..985b1ce62e9 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp +++ b/clang/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 %{{[^,]*}}) |