r200810 - Tighten lax vector-conversion rules and enforce them consistently.
John McCall
rjmccall at apple.com
Tue Feb 4 15:58:19 PST 2014
Author: rjmccall
Date: Tue Feb 4 17:58:19 2014
New Revision: 200810
URL: http://llvm.org/viewvc/llvm-project?rev=200810&view=rev
Log:
Tighten lax vector-conversion rules and enforce them consistently.
When a lax conversion featured a vector and a non-vector, we were
only requiring the non-vector to be a scalar type, but really it
needs to be a real type (i.e. integral or real floating); it is
not reasonable to allow a pointer, member pointer, or complex
type here.
r198474 required lax conversions to match in "data size", i.e.
element size * element count, forbidding matches that happen
only because a vector is rounded up to the nearest power of two
in size. Unfortunately, the erroneous logic was repeated in
several different places; unify them to use the new condition,
so that it triggers for arbitrary conversions and not just
those performed as part of binary operator checking.
rdar://15931426
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/Sema/ext_vector_casts.c
cfe/trunk/test/Sema/vector-cast.c
cfe/trunk/test/SemaCXX/vector-casts.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=200810&r1=200809&r2=200810&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 4 17:58:19 2014
@@ -7441,6 +7441,8 @@ public:
QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc);
+ bool isLaxVectorConversion(QualType srcType, QualType destType);
+
/// type checking declaration initializers (C99 6.7.8)
bool CheckForConstantInitializer(Expr *e, QualType t);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=200810&r1=200809&r2=200810&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb 4 17:58:19 2014
@@ -6259,8 +6259,7 @@ Sema::CheckAssignmentConstraints(QualTyp
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a bitcast;
// no bits are changed but the result type is different.
- if (getLangOpts().LaxVectorConversions &&
- (Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) {
+ if (isLaxVectorConversion(RHSType, LHSType)) {
Kind = CK_BitCast;
return IncompatibleVectors;
}
@@ -6626,44 +6625,86 @@ QualType Sema::InvalidOperands(SourceLoc
return QualType();
}
-static bool areVectorOperandsLaxBitCastable(ASTContext &Ctx,
- QualType LHSType, QualType RHSType){
- if (!Ctx.getLangOpts().LaxVectorConversions)
- return false;
+static bool breakDownVectorType(QualType type, uint64_t &len,
+ QualType &eltType) {
+ // Vectors are simple.
+ if (const VectorType *vecType = type->getAs<VectorType>()) {
+ 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;
- if (!(LHSType->isVectorType() || LHSType->isScalarType()) ||
- !(RHSType->isVectorType() || RHSType->isScalarType()))
- return false;
+ len = 1;
+ eltType = type;
+ return true;
+}
- unsigned LHSSize = Ctx.getTypeSize(LHSType);
- unsigned RHSSize = Ctx.getTypeSize(RHSType);
- if (LHSSize != RHSSize)
+/// 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;
- // For a non-power-of-2 vector ASTContext::getTypeSize returns the size
- // rounded to the next power-of-2, but the LLVM IR type that we create
- // is considered to have num-of-elements*width-of-element width.
- // Make sure such width is the same between the types, otherwise we may end
- // up with an invalid bitcast.
- unsigned LHSIRSize, RHSIRSize;
- if (LHSType->isVectorType()) {
- const VectorType *Vec = LHSType->getAs<VectorType>();
- LHSIRSize = Vec->getNumElements() *
- Ctx.getTypeSize(Vec->getElementType());
- } else {
- LHSIRSize = LHSSize;
- }
- if (RHSType->isVectorType()) {
- const VectorType *Vec = RHSType->getAs<VectorType>();
- RHSIRSize = Vec->getNumElements() *
- Ctx.getTypeSize(Vec->getElementType());
+ 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.
+///
+/// \param scalar - if non-null, actually perform the conversions
+/// \return true if the operation fails (but without diagnosing the failure)
+static bool tryVectorPromoteAndSplat(Sema &S, ExprResult *scalar,
+ QualType scalarTy,
+ QualType vectorEltTy,
+ QualType vectorTy) {
+ // The conversion to apply to the scalar before splatting it,
+ // if necessary.
+ CastKind scalarCast = CK_Invalid;
+
+ if (vectorEltTy->isIntegralType(S.Context)) {
+ if (!scalarTy->isIntegralType(S.Context)) return true;
+ int order = S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy);
+ if (order < 0) return true;
+ if (order > 0) scalarCast = CK_IntegralCast;
+ } else if (vectorEltTy->isRealFloatingType()) {
+ if (scalarTy->isRealFloatingType()) {
+ int order = S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy);
+ if (order < 0) return true;
+ if (order > 0) scalarCast = CK_FloatingCast;
+ } else if (scalarTy->isIntegralType(S.Context)) {
+ scalarCast = CK_IntegralToFloating;
+ } else {
+ return true;
+ }
} else {
- RHSIRSize = RHSSize;
+ return true;
}
- if (LHSIRSize != RHSIRSize)
- return false;
- return true;
+ // Adjust scalar if desired.
+ if (scalar) {
+ if (scalarCast != CK_Invalid)
+ *scalar = S.ImpCastExprToType(scalar->take(), vectorEltTy, scalarCast);
+ *scalar = S.ImpCastExprToType(scalar->take(), vectorTy, CK_VectorSplat);
+ }
+ return false;
}
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
@@ -6679,19 +6720,21 @@ QualType Sema::CheckVectorOperands(ExprR
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
- QualType LHSType =
- Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
- QualType RHSType =
- Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
+ QualType LHSType = LHS.get()->getType().getUnqualifiedType();
+ QualType RHSType = RHS.get()->getType().getUnqualifiedType();
// If the vector types are identical, return.
- if (LHSType == RHSType)
+ if (Context.hasSameType(LHSType, RHSType))
return LHSType;
- // Handle the case of equivalent AltiVec and GCC vector types
- if (LHSType->isVectorType() && RHSType->isVectorType() &&
+ const VectorType *LHSVecType = LHSType->getAs<VectorType>();
+ const VectorType *RHSVecType = RHSType->getAs<VectorType>();
+ assert(LHSVecType || RHSVecType);
+
+ // If we have compatible AltiVec and GCC vector types, use the AltiVec type.
+ if (LHSVecType && RHSVecType &&
Context.areCompatibleVectorTypes(LHSType, RHSType)) {
- if (LHSType->isExtVectorType()) {
+ if (isa<ExtVectorType>(LHSVecType)) {
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return LHSType;
}
@@ -6701,69 +6744,43 @@ QualType Sema::CheckVectorOperands(ExprR
return RHSType;
}
- if (areVectorOperandsLaxBitCastable(Context, LHSType, RHSType)) {
- // If we are allowing lax vector conversions, and LHS and RHS are both
- // vectors, the total size only needs to be the same. This is a
- // bitcast; no bits are changed but the result type is different.
- // FIXME: Should we really be allowing this?
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
- return LHSType;
+ // If we're allowing lax vector conversions, only the total (data) size
+ // needs to be the same.
+ // FIXME: Should we really be allowing this?
+ // FIXME: We really just pick the LHS type arbitrarily?
+ if (isLaxVectorConversion(RHSType, LHSType)) {
+ QualType resultType = LHSType;
+ RHS = ImpCastExprToType(RHS.take(), resultType, CK_BitCast);
+ return resultType;
}
- if (!(LHSType->isVectorType() || LHSType->isScalarType()) ||
- !(RHSType->isVectorType() || RHSType->isScalarType())) {
- Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar)
- << LHS.get()->getType() << RHS.get()->getType()
- << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
- return QualType();
+ // If there's an ext-vector type and a scalar, try to promote (and
+ // only promote) and splat the scalar to the vector type.
+ if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) {
+ if (!tryVectorPromoteAndSplat(*this, &RHS, RHSType,
+ LHSVecType->getElementType(), LHSType))
+ return LHSType;
+ }
+ if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) {
+ if (!tryVectorPromoteAndSplat(*this, (IsCompAssign ? 0 : &LHS), LHSType,
+ RHSVecType->getElementType(), RHSType))
+ return RHSType;
}
- // Canonicalize the ExtVector to the LHS, remember if we swapped so we can
- // swap back (so that we don't reverse the inputs to a subtract, for instance.
- bool swapped = false;
- if (RHSType->isExtVectorType() && !IsCompAssign) {
- swapped = true;
- std::swap(RHS, LHS);
- std::swap(RHSType, LHSType);
- }
-
- // Handle the case of an ext vector and scalar.
- if (const ExtVectorType *LV = LHSType->getAs<ExtVectorType>()) {
- QualType EltTy = LV->getElementType();
- if (EltTy->isIntegralType(Context) && RHSType->isIntegralType(Context)) {
- int order = Context.getIntegerTypeOrder(EltTy, RHSType);
- if (order > 0)
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralCast);
- if (order >= 0) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
- if (swapped) std::swap(RHS, LHS);
- return LHSType;
- }
- }
- if (EltTy->isRealFloatingType() && RHSType->isScalarType()) {
- if (RHSType->isRealFloatingType()) {
- int order = Context.getFloatingTypeOrder(EltTy, RHSType);
- if (order > 0)
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast);
- if (order >= 0) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
- if (swapped) std::swap(RHS, LHS);
- return LHSType;
- }
- }
- if (RHSType->isIntegralType(Context)) {
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralToFloating);
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
- if (swapped) std::swap(RHS, LHS);
- return LHSType;
- }
- }
+ // Okay, the expression is invalid.
+
+ // If there's a non-vector, non-real operand, diagnose that.
+ if ((!RHSVecType && !RHSType->isRealType()) ||
+ (!LHSVecType && !LHSType->isRealType())) {
+ Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar)
+ << LHSType << RHSType
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ return QualType();
}
- // Vectors of different size or scalar and non-ext-vector are errors.
- if (swapped) std::swap(RHS, LHS);
+ // Otherwise, use the generic diagnostic.
Diag(Loc, diag::err_typecheck_vector_not_convertable)
- << LHS.get()->getType() << RHS.get()->getType()
+ << LHSType << RHSType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=200810&r1=200809&r2=200810&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Feb 4 17:58:19 2014
@@ -1372,7 +1372,7 @@ bool Sema::IsNoReturnConversion(QualType
///
/// \param ICK Will be set to the vector conversion kind, if this is a vector
/// conversion.
-static bool IsVectorConversion(ASTContext &Context, QualType FromType,
+static bool IsVectorConversion(Sema &S, QualType FromType,
QualType ToType, ImplicitConversionKind &ICK) {
// We need at least one of these types to be a vector type to have a vector
// conversion.
@@ -1380,7 +1380,7 @@ static bool IsVectorConversion(ASTContex
return false;
// Identical types require no conversions.
- if (Context.hasSameUnqualifiedType(FromType, ToType))
+ if (S.Context.hasSameUnqualifiedType(FromType, ToType))
return false;
// There are no conversions between extended vector types, only identity.
@@ -1402,9 +1402,8 @@ static bool IsVectorConversion(ASTContex
// 2)lax vector conversions are permitted and the vector types are of the
// same size
if (ToType->isVectorType() && FromType->isVectorType()) {
- if (Context.areCompatibleVectorTypes(FromType, ToType) ||
- (Context.getLangOpts().LaxVectorConversions &&
- (Context.getTypeSize(FromType) == Context.getTypeSize(ToType)))) {
+ if (S.Context.areCompatibleVectorTypes(FromType, ToType) ||
+ S.isLaxVectorConversion(FromType, ToType)) {
ICK = ICK_Vector_Conversion;
return true;
}
@@ -1633,7 +1632,7 @@ static bool IsStandardConversion(Sema &S
InOverloadResolution, FromType)) {
// Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
- } else if (IsVectorConversion(S.Context, FromType, ToType, SecondICK)) {
+ } else if (IsVectorConversion(S, FromType, ToType, SecondICK)) {
SCS.Second = SecondICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
Modified: cfe/trunk/test/Sema/ext_vector_casts.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/ext_vector_casts.c?rev=200810&r1=200809&r2=200810&view=diff
==============================================================================
--- cfe/trunk/test/Sema/ext_vector_casts.c (original)
+++ cfe/trunk/test/Sema/ext_vector_casts.c Tue Feb 4 17:58:19 2014
@@ -49,7 +49,7 @@ static void test() {
ivec4 += (int4)vec4;
ivec4 -= ivec4;
ivec4 |= ivec4;
- ivec4 += ptr; // expected-error {{can't convert between vector values of different size ('int4' and 'int *')}}
+ ivec4 += ptr; // expected-error {{can't convert between vector and non-scalar values ('int4' and 'int *')}}
}
typedef __attribute__(( ext_vector_type(2) )) float2 vecfloat2; // expected-error{{invalid vector element type 'float2'}}
Modified: cfe/trunk/test/Sema/vector-cast.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/vector-cast.c?rev=200810&r1=200809&r2=200810&view=diff
==============================================================================
--- cfe/trunk/test/Sema/vector-cast.c (original)
+++ cfe/trunk/test/Sema/vector-cast.c Tue Feb 4 17:58:19 2014
@@ -44,3 +44,13 @@ void f4() {
f2 += d;
d += f2;
}
+
+// rdar://15931426
+// Don't permit a lax conversion to and from a pointer type.
+typedef short short_sizeof_pointer __attribute__((vector_size(sizeof(void*))));
+void f5() {
+ short_sizeof_pointer v;
+ void *ptr;
+ v = ptr; // expected-error {{assigning to 'short_sizeof_pointer' from incompatible type 'void *'}}
+ ptr = v; // expected-error {{assigning to 'void *' from incompatible type 'short_sizeof_pointer'}}
+}
Modified: cfe/trunk/test/SemaCXX/vector-casts.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/vector-casts.cpp?rev=200810&r1=200809&r2=200810&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/vector-casts.cpp (original)
+++ cfe/trunk/test/SemaCXX/vector-casts.cpp Tue Feb 4 17:58:19 2014
@@ -2,6 +2,7 @@
typedef int __v2si __attribute__((__vector_size__(8)));
typedef short __v4hi __attribute__((__vector_size__(8)));
typedef short __v8hi __attribute__((__vector_size__(16)));
+typedef short __v3hi __attribute__((__ext_vector_type__(3)));
struct S { }; // expected-note 2 {{candidate constructor}}
@@ -46,3 +47,19 @@ struct testvec {
v = v + rhs; // expected-error {{can't convert between vector and non-scalar values}}
}
};
+
+// rdar://15931426
+// Conversions for return values.
+__v4hi threeToFour(__v3hi v) { // expected-note {{not viable}}
+ return v; // expected-error {{cannot initialize return object}}
+}
+__v3hi fourToThree(__v4hi v) { // expected-note {{not viable}}
+ return v; // expected-error {{cannot initialize return object}}
+}
+// Conversions for calls.
+void call3to4(__v4hi v) {
+ (void) threeToFour(v); // expected-error {{no matching function for call}}
+}
+void call4to3(__v3hi v) {
+ (void) fourToThree(v); // expected-error {{no matching function for call}}
+}
More information about the cfe-commits
mailing list