summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/TargetInfo.cpp
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-07-26 00:12:26 +0000
committerReid Kleckner <reid@kleckner.net>2014-07-26 00:12:26 +0000
commit852361d2171f7b5689c5aaaccfa2583018a284e8 (patch)
tree7732dbd4c9625f6f1a62eb1107a7b3d6c7e8e1fe /clang/lib/CodeGen/TargetInfo.cpp
parent0e469609f3d829bbe95abfeb8737a4f7897c6418 (diff)
downloadbcm5719-llvm-852361d2171f7b5689c5aaaccfa2583018a284e8.tar.gz
bcm5719-llvm-852361d2171f7b5689c5aaaccfa2583018a284e8.zip
MS ABI: Ensure 'this' is first for byval+sret methods
Previously we were building up the inalloca struct in the usual pattern of return type followed by arguments. However, on Windows, 'this' always precedes the 'sret' parameter, so we need to insert it into the struct first as a special case. llvm-svn: 213990
Diffstat (limited to 'clang/lib/CodeGen/TargetInfo.cpp')
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp55
1 files changed, 34 insertions, 21 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 40fc51146aa..1a1ac8bd925 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -1002,6 +1002,26 @@ X86_32ABIInfo::addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
}
}
+static bool isArgInAlloca(const ABIArgInfo &Info) {
+ // Leave ignored and inreg arguments alone.
+ switch (Info.getKind()) {
+ case ABIArgInfo::InAlloca:
+ return true;
+ case ABIArgInfo::Indirect:
+ assert(Info.getIndirectByVal());
+ return true;
+ case ABIArgInfo::Ignore:
+ return false;
+ case ABIArgInfo::Direct:
+ case ABIArgInfo::Extend:
+ case ABIArgInfo::Expand:
+ if (Info.getInReg())
+ return false;
+ return true;
+ }
+ llvm_unreachable("invalid enum");
+}
+
void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
assert(IsWin32StructABI && "inalloca only supported on win32");
@@ -1009,9 +1029,19 @@ void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
SmallVector<llvm::Type *, 6> FrameFields;
unsigned StackOffset = 0;
+ CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
- // Put the sret parameter into the inalloca struct if it's in memory.
+ // Put 'this' into the struct before 'sret', if necessary.
+ bool IsThisCall =
+ FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall;
ABIArgInfo &Ret = FI.getReturnInfo();
+ if (Ret.isIndirect() && Ret.isSRetAfterThis() && !IsThisCall &&
+ isArgInAlloca(I->info)) {
+ addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
+ ++I;
+ }
+
+ // Put the sret parameter into the inalloca struct if it's in memory.
if (Ret.isIndirect() && !Ret.getInReg()) {
CanQualType PtrTy = getContext().getPointerType(FI.getReturnType());
addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy);
@@ -1020,30 +1050,13 @@ void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
}
// Skip the 'this' parameter in ecx.
- CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
- if (FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall)
+ if (IsThisCall)
++I;
// Put arguments passed in memory into the struct.
for (; I != E; ++I) {
-
- // Leave ignored and inreg arguments alone.
- switch (I->info.getKind()) {
- case ABIArgInfo::Indirect:
- assert(I->info.getIndirectByVal());
- break;
- case ABIArgInfo::Ignore:
- continue;
- case ABIArgInfo::Direct:
- case ABIArgInfo::Extend:
- if (I->info.getInReg())
- continue;
- break;
- default:
- break;
- }
-
- addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
+ if (isArgInAlloca(I->info))
+ addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
}
FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields,
OpenPOWER on IntegriCloud