[cfe-commits] r112686 - in /cfe/trunk: lib/CodeGen/TargetInfo.cpp test/CodeGenCXX/x86_64-arguments.cpp
Chris Lattner
sabre at nondot.org
Tue Aug 31 17:50:20 PDT 2010
Author: lattner
Date: Tue Aug 31 19:50:20 2010
New Revision: 112686
URL: http://llvm.org/viewvc/llvm-project?rev=112686&view=rev
Log:
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.
Modified:
cfe/trunk/lib/CodeGen/TargetInfo.cpp
cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp
Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=112686&r1=112685&r2=112686&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Tue Aug 31 19:50:20 2010
@@ -1426,6 +1426,50 @@
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 @@
// 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 @@
// 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);
}
Modified: cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp?rev=112686&r1=112685&r2=112686&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/x86_64-arguments.cpp Tue Aug 31 19:50:20 2010
@@ -100,3 +100,18 @@
// CHECK: alloca %"struct.test5::X"
// CHECK: alloca %"struct.test5::Y"
}
+
+
+// rdar://8360877
+namespace test6 {
+ struct outer {
+ int x;
+ struct epsilon_matcher {} e;
+ int f;
+ };
+
+ int test(outer x) {
+ return x.x + x.f;
+ }
+ // CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1)
+}
More information about the cfe-commits
mailing list