diff options
author | Chris Lattner <sabre@nondot.org> | 2010-07-29 18:13:09 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-07-29 18:13:09 +0000 |
commit | 7f4b81af7aeb47c31e046cb282d2779beea2a9c9 (patch) | |
tree | e5effecb719b74b2e4504e0b429989672ef42318 /clang | |
parent | be2bb0d3379253eec7d40fdaff102e5817f8a40c (diff) | |
download | bcm5719-llvm-7f4b81af7aeb47c31e046cb282d2779beea2a9c9.tar.gz bcm5719-llvm-7f4b81af7aeb47c31e046cb282d2779beea2a9c9.zip |
fix rdar://8251384, another case where we could access beyond the
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
llvm-svn: 109776
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 49 | ||||
-rw-r--r-- | clang/test/CodeGen/x86_64-arguments.c | 10 |
2 files changed, 38 insertions, 21 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 1e66f046b0c..ec52b93bdf8 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -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; diff --git a/clang/test/CodeGen/x86_64-arguments.c b/clang/test/CodeGen/x86_64-arguments.c index 1243dd7239b..9fd08dd4a8b 100644 --- a/clang/test/CodeGen/x86_64-arguments.c +++ b/clang/test/CodeGen/x86_64-arguments.c @@ -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; +} + + |