aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-07-29 18:39:32 +0000
committerChris Lattner <sabre@nondot.org>2010-07-29 18:39:32 +0000
commit0b3620066bfbb33004bed1816c851a923b9301af (patch)
treec0f57276865ece101a6b70796b26ecf0d2fc3bba
parentcba8d310163f84630fd140fbfa9b6fdad9d26587 (diff)
Implement the clang-side of detection for when to pass as
<2 x float> instead of double. This works but can't be turned on until I teach codegen to pass <2 x float> as one XMM register instead of two. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109790 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/TargetInfo.cpp42
1 files changed, 39 insertions, 3 deletions
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 6ce824ba18..5f4efcf0bd 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -1297,6 +1297,35 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
return false;
}
+/// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a
+/// float member at the specified offset. For example, {int,{float}} has a
+/// float at offset 4. It is conservatively correct for this routine to return
+/// false.
+static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset,
+ const llvm::TargetData &TD) {
+ // Base case if we find a float.
+ if (IROffset == 0 && IRType->isFloatTy())
+ return true;
+
+ // If this is a struct, recurse into the field at the specified offset.
+ if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
+ const llvm::StructLayout *SL = TD.getStructLayout(STy);
+ unsigned Elt = SL->getElementContainingOffset(IROffset);
+ IROffset -= SL->getElementOffset(Elt);
+ return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD);
+ }
+
+ // If this is an array, recurse into the field at the specified offset.
+ if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
+ const llvm::Type *EltTy = ATy->getElementType();
+ unsigned EltSize = TD.getTypeAllocSize(EltTy);
+ IROffset -= IROffset/EltSize*EltSize;
+ return ContainsFloatAtOffset(EltTy, IROffset, TD);
+ }
+
+ 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.
@@ -1310,9 +1339,16 @@ GetSSETypeAtOffset(const llvm::Type *IRType, unsigned IROffset,
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);
+ // We want to pass as <2 x float> if the LLVM IR type contains a float at
+ // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the
+ // case.
+ if (ContainsFloatAtOffset(IRType, IROffset, getTargetData()) &&
+ ContainsFloatAtOffset(IRType, IROffset+4, getTargetData())) {
+ // 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());
}