summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
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
commite556a7185910dad6e66c58e423dbaf2b1611c4cd (patch)
tree1d31fd1166df2cb3004a84a6c357daddad65d85c /clang/lib/CodeGen
parenta9bf1b14934c8994694e6ac9cf41d7fed4656c0b (diff)
downloadbcm5719-llvm-e556a7185910dad6e66c58e423dbaf2b1611c4cd.tar.gz
bcm5719-llvm-e556a7185910dad6e66c58e423dbaf2b1611c4cd.zip
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. llvm-svn: 109790
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp42
1 files changed, 39 insertions, 3 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 6ce824ba189..5f4efcf0bd8 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/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());
}
OpenPOWER on IntegriCloud