From 73b802fc806c47637fdc2bcf1987b0412216b3ef Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 6 Mar 2014 22:47:09 +0000 Subject: [PATCH] C. Compare vector sizes using their raw element size instead of getTypeSize (which rounds up sizes) in order to issue diagnostics when casting to mismatched vector sizes; instead of crashing in IRGen. // rdar:// 16196902. Reviewed offline by John McCall. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203175 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 87 +++++++++++++++++++----------------- test/Sema/ext_vector_casts.c | 10 +++++ 2 files changed, 55 insertions(+), 42 deletions(-) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index eedfdc4b21..38d1724c9c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5049,12 +5049,55 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { llvm_unreachable("Unhandled scalar cast"); } +static bool breakDownVectorType(QualType type, uint64_t &len, + QualType &eltType) { + // Vectors are simple. + if (const VectorType *vecType = type->getAs()) { + len = vecType->getNumElements(); + eltType = vecType->getElementType(); + assert(eltType->isScalarType()); + return true; + } + + // We allow lax conversion to and from non-vector types, but only if + // they're real types (i.e. non-complex, non-pointer scalar types). + if (!type->isRealType()) return false; + + len = 1; + eltType = type; + return true; +} + +static bool VectorTypesMatch(Sema &S, QualType srcTy, QualType destTy) { + uint64_t srcLen, destLen; + QualType srcElt, destElt; + if (!breakDownVectorType(srcTy, srcLen, srcElt)) return false; + if (!breakDownVectorType(destTy, destLen, destElt)) return false; + + // ASTContext::getTypeSize will return the size rounded up to a + // power of 2, so instead of using that, we need to use the raw + // element size multiplied by the element count. + uint64_t srcEltSize = S.Context.getTypeSize(srcElt); + uint64_t destEltSize = S.Context.getTypeSize(destElt); + + return (srcLen * srcEltSize == destLen * destEltSize); +} + +/// Is this a legal conversion between two known vector types? +bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) { + assert(destTy->isVectorType() || srcTy->isVectorType()); + + if (!Context.getLangOpts().LaxVectorConversions) + return false; + return VectorTypesMatch(*this, srcTy, destTy); +} + bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind) { assert(VectorTy->isVectorType() && "Not a vector type!"); if (Ty->isVectorType() || Ty->isIntegerType()) { - if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty)) + if (!VectorTypesMatch(*this, Ty, VectorTy)) return Diag(R.getBegin(), Ty->isVectorType() ? diag::err_invalid_conversion_between_vectors : @@ -5080,7 +5123,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, // In OpenCL, casts between vectors of different types are not allowed. // (See OpenCL 6.2). if (SrcTy->isVectorType()) { - if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy) + if (!VectorTypesMatch(*this, SrcTy, DestTy) || (getLangOpts().OpenCL && (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) @@ -6657,46 +6700,6 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, return QualType(); } -static bool breakDownVectorType(QualType type, uint64_t &len, - QualType &eltType) { - // Vectors are simple. - if (const VectorType *vecType = type->getAs()) { - len = vecType->getNumElements(); - eltType = vecType->getElementType(); - assert(eltType->isScalarType()); - return true; - } - - // We allow lax conversion to and from non-vector types, but only if - // they're real types (i.e. non-complex, non-pointer scalar types). - if (!type->isRealType()) return false; - - len = 1; - eltType = type; - return true; -} - -/// Is this a legal conversion between two known vector types? -bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) { - assert(destTy->isVectorType() || srcTy->isVectorType()); - - if (!Context.getLangOpts().LaxVectorConversions) - return false; - - uint64_t srcLen, destLen; - QualType srcElt, destElt; - if (!breakDownVectorType(srcTy, srcLen, srcElt)) return false; - if (!breakDownVectorType(destTy, destLen, destElt)) return false; - - // ASTContext::getTypeSize will return the size rounded up to a - // power of 2, so instead of using that, we need to use the raw - // element size multiplied by the element count. - uint64_t srcEltSize = Context.getTypeSize(srcElt); - uint64_t destEltSize = Context.getTypeSize(destElt); - - return (srcLen * srcEltSize == destLen * destEltSize); -} - /// Try to convert a value of non-vector type to a vector type by /// promoting (and only promoting) the type to the element type of the /// vector and then performing a vector splat. diff --git a/test/Sema/ext_vector_casts.c b/test/Sema/ext_vector_casts.c index c590932678..5ad24faaae 100644 --- a/test/Sema/ext_vector_casts.c +++ b/test/Sema/ext_vector_casts.c @@ -79,3 +79,13 @@ stride4 RDar15091442_get_stride4(int4 x, PixelByteStride pixelByteStride) return stride; } +// rdar://16196902 +typedef __attribute__((ext_vector_type(4))) float float32x4_t; + +typedef float C3DVector3 __attribute__((ext_vector_type(3))); + +extern float32x4_t vabsq_f32(float32x4_t __a); + +C3DVector3 Func(const C3DVector3 a) { + return (C3DVector3)vabsq_f32((float32x4_t)a); // expected-error {{invalid conversion between ext-vector type 'float32x4_t' and 'C3DVector3'}} +} -- 2.40.0