diff options
author | Chris Lattner <sabre@nondot.org> | 2010-09-01 00:50:20 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-09-01 00:50:20 +0000 |
commit | 66e7b68b0016aeebe349e21ace93ff0178665d69 (patch) | |
tree | 7f8cc4ecc9c3f28f7bb5497729da65a7971b59ce /lib/CodeGen/TargetInfo.cpp | |
parent | 645406a3d3405ad0f4b5a0e46a34ae92d9d23bd3 (diff) |
fix rdar://8360877 a really nasty miscompilation in Boost.Xpressive
caused by my ABI work. Passing:
struct outer {
int x;
struct epsilon_matcher {} e;
int f;
};
as {i32,i32} isn't safe, because the offset of the second element
needs to be at 8 when it is interpreted as a memory value.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112686 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/TargetInfo.cpp')
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 389fa110fa..4d221d4e65 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -1426,6 +1426,50 @@ GetINTEGERTypeAtOffset(const llvm::Type *IRType, unsigned IROffset, std::min(TySizeInBytes-SourceOffset, 8U)*8); } + +/// GetX86_64ByValArgumentPair - Given a high and low type that can ideally +/// be used as elements of a two register pair to pass or return, return a +/// first class aggregate to represent them. For example, if the low part of +/// a by-value argument should be passed as i32* and the high part as float, +/// return {i32*, float}. +static const llvm::Type * +GetX86_64ByValArgumentPair(const llvm::Type *Lo, const llvm::Type *Hi, + const llvm::TargetData &TD) { + // In order to correctly satisfy the ABI, we need to the high part to start + // at offset 8. If the high and low parts we inferred are both 4-byte types + // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have + // the second element at offset 8. Check for this: + unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo); + unsigned HiAlign = TD.getABITypeAlignment(Hi); + unsigned HiStart = llvm::TargetData::RoundUpAlignment(LoSize, HiAlign); + assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!"); + + // To handle this, we have to increase the size of the low part so that the + // second element will start at an 8 byte offset. We can't increase the size + // of the second element because it might make us access off the end of the + // struct. + if (HiStart != 8) { + // There are only two sorts of types the ABI generation code can produce for + // the low part of a pair that aren't 8 bytes in size: float or i8/i16/i32. + // Promote these to a larger type. + if (Lo->isFloatTy()) + Lo = llvm::Type::getDoubleTy(Lo->getContext()); + else { + assert(Lo->isIntegerTy() && "Invalid/unknown lo type"); + Lo = llvm::Type::getInt64Ty(Lo->getContext()); + } + } + + const llvm::StructType *Result = + llvm::StructType::get(Lo->getContext(), Lo, Hi, NULL); + + + // Verify that the second element is at an 8-byte offset. + assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 && + "Invalid x86-64 argument pair!"); + return Result; +} + ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the @@ -1552,8 +1596,8 @@ classifyReturnType(QualType RetTy) const { // If a high part was specified, merge it together with the low part. It is // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} - if (HighPart) - ResType = llvm::StructType::get(getVMContext(), ResType, HighPart, NULL); + if (HighPart) + ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData()); return ABIArgInfo::getDirect(ResType); } @@ -1674,7 +1718,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt, // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) - ResType = llvm::StructType::get(getVMContext(), ResType, HighPart, NULL); + ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData()); return ABIArgInfo::getDirect(ResType); } |