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