]> granicus.if.org Git - clang/commitdiff
fix rdar://8251384, another case where we could access beyond the
authorChris Lattner <sabre@nondot.org>
Thu, 29 Jul 2010 18:13:09 +0000 (18:13 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 29 Jul 2010 18:13:09 +0000 (18:13 +0000)
end of a struct.  This improves the case when the struct being passed
contains 3 floats, either due to a struct or array of 3 things.  Before
we'd generate this IR for the testcase:

define float @bar(double %X.coerce0, double %X.coerce1) nounwind {
entry:
  %X = alloca %struct.foof, align 8               ; <%struct.foof*> [#uses=2]
  %0 = bitcast %struct.foof* %X to %1*            ; <%1*> [#uses=2]
  %1 = getelementptr %1* %0, i32 0, i32 0         ; <double*> [#uses=1]
  store double %X.coerce0, double* %1
  %2 = getelementptr %1* %0, i32 0, i32 1         ; <double*> [#uses=1]
  store double %X.coerce1, double* %2
  %tmp = getelementptr inbounds %struct.foof* %X, i32 0, i32 2 ; <float*> [#uses=1]
  %tmp1 = load float* %tmp                        ; <float> [#uses=1]
  ret float %tmp1
}

which compiled (with optimization) to:

_bar:                                   ## @bar
## BB#0:                                ## %entry
movd %xmm1, %rax
movd %eax, %xmm0
ret

Now we produce:

define float @bar(double %X.coerce0, float %X.coerce1) nounwind {
entry:
  %X = alloca %struct.foof, align 8               ; <%struct.foof*> [#uses=2]
  %0 = bitcast %struct.foof* %X to %0*            ; <%0*> [#uses=2]
  %1 = getelementptr %0* %0, i32 0, i32 0         ; <double*> [#uses=1]
  store double %X.coerce0, double* %1
  %2 = getelementptr %0* %0, i32 0, i32 1         ; <float*> [#uses=1]
  store float %X.coerce1, float* %2
  %tmp = getelementptr inbounds %struct.foof* %X, i32 0, i32 2 ; <float*> [#uses=1]
  %tmp1 = load float* %tmp                        ; <float> [#uses=1]
  ret float %tmp1
}

and:

_bar:                                   ## @bar
## BB#0:                                ## %entry
movaps %xmm1, %xmm0
ret

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109776 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/TargetInfo.cpp
test/CodeGen/x86_64-arguments.c

index 1e66f046b0cd10f5b517ae0e97824a98ee4353f3..ec52b93bdf8793348046ab5942a7a491c8719f6a 100644 (file)
@@ -719,7 +719,8 @@ class X86_64ABIInfo : public ABIInfo {
 
   const llvm::Type *Get16ByteVectorType(QualType Ty) const;
   const llvm::Type *GetSSETypeAtOffset(const llvm::Type *IRType,
-                                       unsigned IROffset) const;
+                                       unsigned IROffset, QualType SourceTy,
+                                       unsigned SourceOffset) const;
   const llvm::Type *GetINTEGERTypeAtOffset(const llvm::Type *IRType,
                                            unsigned IROffset, QualType SourceTy,
                                            unsigned SourceOffset) const;
@@ -1211,21 +1212,6 @@ const llvm::Type *X86_64ABIInfo::Get16ByteVectorType(QualType Ty) const {
   return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()), 2);
 }
 
-
-/// GetSSETypeAtOffset - Return a type that will be passed by the backend in the
-/// low 8 bytes of an XMM register, corresponding to the SSE class.
-const llvm::Type *X86_64ABIInfo::GetSSETypeAtOffset(const llvm::Type *IRType,
-                                                    unsigned IROffset) const {
-  // The only two choices we have are either double or <2 x float>.
-  
-  // FIXME: <2 x float> doesn't pass as one XMM register yet.  Don't enable this
-  // code until it does.
-  
-  return llvm::Type::getDoubleTy(getVMContext());
-}
-
-
-
 /// BitsContainNoUserData - Return true if the specified [start,end) bit range
 /// is known to either be off the end of the specified type or being in
 /// alignment padding.  The user type specified is known to be at most 128 bits
@@ -1311,6 +1297,27 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
   return false;
 }
 
+
+/// GetSSETypeAtOffset - Return a type that will be passed by the backend in the
+/// low 8 bytes of an XMM register, corresponding to the SSE class.
+const llvm::Type *X86_64ABIInfo::
+GetSSETypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
+                   QualType SourceTy, unsigned SourceOffset) const {
+  // The only two choices we have are either double, <2 x float>, or float.  We
+  // pass as float if the last 4 bytes is just padding.  This happens for
+  // structs that contain 3 floats.
+  if (BitsContainNoUserData(SourceTy, SourceOffset*8+32,
+                            SourceOffset*8+64, getContext()))
+    return llvm::Type::getFloatTy(getVMContext());
+  
+  // FIXME: <2 x float> doesn't pass as one XMM register yet.  Don't enable this
+  // code until it does.
+  //return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2); 
+  
+  return llvm::Type::getDoubleTy(getVMContext());
+}
+
+
 /// GetINTEGERTypeAtOffset - The ABI specifies that a value should be passed in
 /// an 8-byte GPR.  This means that we either have a scalar or we are talking
 /// about the high or low part of an up-to-16-byte struct.  This routine picks
@@ -1420,7 +1427,7 @@ classifyReturnType(QualType RetTy) const {
     // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
     // available SSE register of the sequence %xmm0, %xmm1 is used.
   case SSE:
-    ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 0);
+    ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 0, RetTy, 0);
     break;
 
     // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
@@ -1460,7 +1467,7 @@ classifyReturnType(QualType RetTy) const {
   }
   case SSE: {
     const llvm::Type *HiType =
-      GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 8);
+      GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 8, RetTy, 8);
     ResType = llvm::StructType::get(getVMContext(), ResType, HiType,NULL);
     break;
   }
@@ -1483,7 +1490,7 @@ classifyReturnType(QualType RetTy) const {
     // extra bits in an SSE reg.
     if (Lo != X87) {
       const llvm::Type *HiType =
-        GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 8);
+        GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 8, RetTy, 8);
       ResType = llvm::StructType::get(getVMContext(), ResType, HiType, NULL);
     }
     break;
@@ -1539,7 +1546,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
     // order from %xmm0 to %xmm7.
   case SSE:
     ++neededSSE;
-    ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 0);
+    ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 0, Ty, 0);
     break;
   }
 
@@ -1569,7 +1576,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
   case X87Up:
   case SSE: {
     const llvm::Type *HiType =
-      GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 8);
+      GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 8, Ty, 8);
     ResType = llvm::StructType::get(getVMContext(), ResType, HiType, NULL);
     ++neededSSE;
     break;
index 1243dd7239b8b87556bd4dacedffc2b21769af72..9fd08dd4a8be20bb1a63c4c8aecb0ae63b525445 100644 (file)
@@ -210,3 +210,13 @@ struct S0 { char f0[8]; char f2; char f3; char f4; };
 void f30(struct S0 p_4) {
   // CHECK: define void @f30(i64 %p_4.coerce0, i24 %p_4.coerce1)
 }
+
+// Pass the third element as a float when followed by tail padding.
+// rdar://8251384
+struct f31foo { float a, b, c; };
+float f31(struct f31foo X) {
+  // CHECK: define float @f31(double %X.coerce0, float %X.coerce1)
+  return X.c;
+}
+
+