summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/CodeGen/CGFunctionInfo.h12
-rw-r--r--clang/lib/CodeGen/CGCall.cpp22
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp2
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp7
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 %{{[^,]*}})
OpenPOWER on IntegriCloud