OpenCL 1.0 support: explicit casts to ext-vector types


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74247 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 5343ceb..62e0eb3 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1860,6 +1860,9 @@
 def err_collection_expr_type : Error<
   "collection expression type %0 is not a valid object">;
 
+def err_invalid_conversion_between_ext_vectors : Error<
+  "invalid conversion between ext-vector type %0 and %1">;
+
 // Type
 def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
 def warn_receiver_forward_class : Warning<
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 36f3ff9..48e6772 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3063,6 +3063,13 @@
   // returns true if the cast is invalid
   bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
   
+  // CheckExtVectorCast - check type constraints for extended vectors. 
+  // Since vectors are an extension, there are no C standard reference for this.
+  // We allow casting between vectors and integer datatypes of the same size,
+  // or vectors and the element type of that vector.
+  // returns true if the cast is invalid
+  bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
+  
   /// CheckMessageArgumentTypes - Check types in an Obj-C message send. 
   /// \param Method - May be null.
   /// \param [out] ReturnType - The return type of the send.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a01fbb1..3d22321 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2876,12 +2876,15 @@
     return Diag(castExpr->getLocStart(),
                 diag::err_typecheck_expect_scalar_operand)
       << castExpr->getType() << castExpr->getSourceRange();
-  } else if (castExpr->getType()->isVectorType()) {
-    if (CheckVectorCast(TyR, castExpr->getType(), castType))
+  } else if (castType->isExtVectorType()) {
+    if (CheckExtVectorCast(TyR, castType, castExpr->getType()))
       return true;
   } else if (castType->isVectorType()) {
     if (CheckVectorCast(TyR, castType, castExpr->getType()))
       return true;
+  } else if (castExpr->getType()->isVectorType()) {
+    if (CheckVectorCast(TyR, castExpr->getType(), castType))
+      return true;
   } else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) {
     return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
   } else if (!castType->isArithmeticType()) {
@@ -2919,6 +2922,35 @@
   return false;
 }
 
+bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
+  assert(DestTy->isExtVectorType() && "Not an extended vector type!");
+  
+  // If SrcTy is also an ExtVectorType, the types must be identical unless 
+  // lax vector conversions is enabled.
+  if (SrcTy->isExtVectorType()) {
+    if (getLangOptions().LaxVectorConversions &&
+        Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy))
+      return false;
+    if (DestTy != SrcTy)
+      return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
+      << DestTy << SrcTy << R;
+    return false;
+  }
+  
+  // If SrcTy is a VectorType, then only the total size must match.
+  if (SrcTy->isVectorType()) {
+    if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy))
+      return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
+        << DestTy << SrcTy << R;
+    return false;
+  }
+
+  // All scalar -> ext vector "c-style" casts are legal; the appropriate
+  // conversion will take place first from scalar to elt type, and then
+  // splat from elt type to vector.
+  return false;
+}
+
 Action::OwningExprResult
 Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
                     SourceLocation RParenLoc, ExprArg Op) {
diff --git a/test/Sema/ext_vector_casts.c b/test/Sema/ext_vector_casts.c
new file mode 100644
index 0000000..8aa762e
--- /dev/null
+++ b/test/Sema/ext_vector_casts.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef __attribute__(( ext_vector_type(4) )) int int4;
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+typedef float t3 __attribute__ ((vector_size (16)));
+
+static void test() {
+    float2 vec2;
+    float4 vec4, vec4_2;
+    int4 ivec4;
+    t3 vec4_3;
+    
+    vec4 = (float4)5.0f;
+    vec4 = (float4)5;
+    vec4 = (float4)vec4_3;
+    
+    ivec4 = (int4)5.0f;
+    ivec4 = (int4)5;
+    ivec4 = (int4)vec4_3;
+    
+    vec4 = (float4)vec2; // expected-error {{invalid conversion between ext-vector type 'float4' and 'float2'}}
+}
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index bd09e69..9460cac 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -11,9 +11,9 @@
   t3 v3;
   
   v2 = (t2)v1; // -expected-error {{invalid conversion between vector type \
-'t1' and 't2' of different size}}
-  v1 = (t1)v2; // -expected-error {{invalid conversion between vector type \
 't2' and 't1' of different size}}
+  v1 = (t1)v2; // -expected-error {{invalid conversion between vector type \
+'t1' and 't2' of different size}}
   v3 = (t3)v2;
   
   v1 = (t1)(char *)10; // -expected-error {{invalid conversion between vector \