summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-02-25 00:59:14 +0000
committerReid Kleckner <reid@kleckner.net>2014-02-25 00:59:14 +0000
commitfab1e89de90902e0713b8af320fc83a412ef2dad (patch)
tree921cb2409f929d4180bb4ffcbed5b94fff5366d6
parent1ce017e8cb0262730b0dcf8f722c62818752757c (diff)
downloadbcm5719-llvm-fab1e89de90902e0713b8af320fc83a412ef2dad.tar.gz
bcm5719-llvm-fab1e89de90902e0713b8af320fc83a412ef2dad.zip
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. llvm-svn: 202097
-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