[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