sdardis updated this revision to Diff 78531.
sdardis marked 4 inline comments as done.
sdardis added a comment.

Addressed review comments.


https://reviews.llvm.org/D25866

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExpr.cpp
  test/Sema/vector-cast.c
  test/Sema/vector-gcc-compat.c
  test/Sema/zvector.c
  test/SemaCXX/vector-no-lax.cpp

Index: test/SemaCXX/vector-no-lax.cpp
===================================================================
--- test/SemaCXX/vector-no-lax.cpp
+++ test/SemaCXX/vector-no-lax.cpp
@@ -4,6 +4,6 @@
 
 vSInt32 foo (vUInt32 a) {
   vSInt32 b = { 0, 0, 0, 0 };
-  b += a; // expected-error{{cannot convert between vector values}}
+  b += a; // expected-error{{cannot convert between vector type 'vUInt32' (vector of 4 'unsigned int' values) and vector type 'vSInt32' (vector of 4 'int' values) as implicit conversion would cause truncation}}
   return b;
 }
Index: test/Sema/zvector.c
===================================================================
--- test/Sema/zvector.c
+++ test/Sema/zvector.c
@@ -326,14 +326,14 @@
   bc = bc + sc2; // expected-error {{incompatible type}}
   bc = sc + bc2; // expected-error {{incompatible type}}
 
-  sc = sc + sc_scalar; // expected-error {{cannot convert}}
-  sc = sc + uc_scalar; // expected-error {{cannot convert}}
-  sc = sc_scalar + sc; // expected-error {{cannot convert}}
-  sc = uc_scalar + sc; // expected-error {{cannot convert}}
-  uc = uc + sc_scalar; // expected-error {{cannot convert}}
-  uc = uc + uc_scalar; // expected-error {{cannot convert}}
-  uc = sc_scalar + uc; // expected-error {{cannot convert}}
-  uc = uc_scalar + uc; // expected-error {{cannot convert}}
+  sc = sc + sc_scalar;
+  sc = sc + uc_scalar; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type '__vector signed char' (vector of 16 'signed char' values) as implicit conversion would cause truncation}}
+  sc = sc_scalar + sc;
+  sc = uc_scalar + sc; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type '__vector signed char' (vector of 16 'signed char' values) as implicit conversion would cause truncation}}
+  uc = uc + sc_scalar; // expected-error {{implicit conversion changes signedness: 'signed char' to '__vector unsigned char' (vector of 16 'unsigned char' values)}}
+  uc = uc + uc_scalar;
+  uc = sc_scalar + uc; // expected-error {{implicit conversion changes signedness: 'signed char' to '__vector unsigned char' (vector of 16 'unsigned char' values)}}
+  uc = uc_scalar + uc;
 
   ss = ss + ss2;
   us = us + us2;
@@ -368,10 +368,10 @@
   sc += sl2; // expected-error {{cannot convert}}
   sc += fd2; // expected-error {{cannot convert}}
 
-  sc += sc_scalar; // expected-error {{cannot convert}}
-  sc += uc_scalar; // expected-error {{cannot convert}}
-  uc += sc_scalar; // expected-error {{cannot convert}}
-  uc += uc_scalar; // expected-error {{cannot convert}}
+  sc += sc_scalar;
+  sc += uc_scalar; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type '__vector signed char' (vector of 16 'signed char' values) as implicit conversion would cause truncation}}
+  uc += sc_scalar; // expected-error {{implicit conversion changes signedness: 'signed char' to '__vector unsigned char' (vector of 16 'unsigned char' values)}}
+  uc += uc_scalar;
 
   ss += ss2;
   us += us2;
Index: test/Sema/vector-gcc-compat.c
===================================================================
--- /dev/null
+++ test/Sema/vector-gcc-compat.c
@@ -0,0 +1,304 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Weverything
+typedef long long v2i64 __attribute__((vector_size(16)));
+typedef int v2i32 __attribute__((vector_size(8)));
+typedef short v2i16 __attribute__((vector_size(4)));
+typedef char v2i8 __attribute__((vector_size(2)));
+
+typedef unsigned long long v2u64 __attribute__((vector_size(16)));
+typedef unsigned int v2u32 __attribute__((vector_size(8)));
+typedef unsigned short v2u16 __attribute__((vector_size(4)));
+typedef unsigned char v2u8 __attribute__((vector_size(2)));
+
+typedef float v4f32 __attribute__((vector_size(16)));
+typedef double v4f64 __attribute__((vector_size(32)));
+
+void arithmeticTest(void);
+void logicTest(void);
+void comparisonTest(void);
+void floatTestSignedType(char a, short b, int c, long long d);
+void floatTestUnsignedType(unsigned char a, unsigned short b, unsigned int c,
+                           unsigned long long d);
+void floatTestConstant(void);
+void intTestType(char a, short b, int c, long long d);
+void intTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+                         unsigned long long d);
+void uintTestType(char a, short b, int c, long long d);
+void uintTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+                          unsigned long long d);
+void uintTestConstant(v2u64 v2u64_a, v2u32 v2u32_a, v2u16 v2u16_a, v2u8 v2u8_a);
+void intTestConstant(v2i64 v2i64_a, v2i32 v2i32_a, v2i16 v2i16_a, v2i8 v2i8_a);
+
+void arithmeticTest(void) {
+  v2i64 v2i64_a = (v2i64){0, 1};
+  v2i64 v2i64_r;
+
+  v2i64_r = v2i64_a + 1;
+  v2i64_r = v2i64_a - 1;
+  v2i64_r = v2i64_a * 1;
+  v2i64_r = v2i64_a / 1;
+  v2i64_r = v2i64_a % 1;
+
+  v2i64_r = 1 + v2i64_a;
+  v2i64_r = 1 - v2i64_a;
+  v2i64_r = 1 * v2i64_a;
+  v2i64_r = 1 / v2i64_a;
+  v2i64_r = 1 % v2i64_a;
+
+  v2i64_a += 1;
+  v2i64_a -= 1;
+  v2i64_a *= 1;
+  v2i64_a /= 1;
+  v2i64_a %= 1;
+}
+
+void comparisonTest(void) {
+  v2i64 v2i64_a = (v2i64){0, 1};
+  v2i64 v2i64_r;
+
+  // FIXME: -Wall is showing that the type is somehow being converted to
+  //        "long __attribute__((ext_vector_type(2)))" when the types should
+  //        match.
+  v2i64_r = v2i64_a == 1; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = v2i64_a != 1; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = v2i64_a < 1;  // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = v2i64_a > 1;  // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = v2i64_a <= 1; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = v2i64_a >= 1; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+
+  v2i64_r = 1 == v2i64_a; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = 1 != v2i64_a; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = 1 < v2i64_a;  // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = 1 > v2i64_a;  // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = 1 <= v2i64_a; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = 1 >= v2i64_a; // expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+}
+
+void logicTest(void) {
+  v2i64 v2i64_a = (v2i64){0, 1};
+  v2i64 v2i64_r;
+
+  v2i64_r = v2i64_a & 1;
+  v2i64_r = v2i64_a | 1;
+  v2i64_r = v2i64_a ^ 1;
+
+  v2i64_r = 1 & v2i64_a;
+  v2i64_r = 1 | v2i64_a;
+  v2i64_r = 1 ^ v2i64_a;
+
+  v2i64_a &= 1;
+  v2i64_a |= 1;
+  v2i64_a ^= 1;
+
+  // FIXME: -Wall is showing that the type is somehow being converted to
+  //        "long __attribute__((ext_vector_type(2)))" when the types should
+  //        match.
+  v2i64_r = v2i64_a && 1; // expected-warning {{implicit conversion turns vector to scalar: 'v2i64' (vector of 2 'long long' values) to '_Bool'}} expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+  v2i64_r = v2i64_a || 1; // expected-warning {{implicit conversion turns vector to scalar: 'v2i64' (vector of 2 'long long' values) to '_Bool'}} expected-warning {{incompatible vector types assigning to 'v2i64' (vector of 2 'long long' values) from 'long __attribute__((ext_vector_type(2)))' (vector of 2 'long' values)}}
+
+  v2i64_r = v2i64_a << 1;
+  v2i64_r = v2i64_a >> 1;
+
+  v2i64_r = 1 << v2i64_a;
+  v2i64_r = 1 >> v2i64_a;
+
+  v2i64_a <<= 1;
+  v2i64_a >>= 1;
+}
+
+// For operations with floating point types, we check that interger constants
+// can be respresented, or failing that checking based on the integer types.
+void floatTestConstant(void) {
+  // Test that constants added to floats must be expressible as floating point
+  // numbers.
+  v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+  v4f32_a = v4f32_a + 1;
+  v4f32_a = v4f32_a + 0xFFFFFF;
+  v4f32_a = v4f32_a + (-1567563LL);
+  v4f32_a = v4f32_a + (16777208);
+  v4f32_a = v4f32_a + (16777219); // expected-error {{cannot convert between scalar type 'int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+}
+
+void floatTestUnsignedType(unsigned char a, unsigned short b, unsigned int c,
+                           unsigned long long d) {
+
+  v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+  v4f64 v4f64_b = {0.4, 0.4, 0.4, 0.4};
+
+  v4f32_a = v4f32_a + a;
+  v4f32_a = v4f32_a + b;
+  v4f32_a = v4f32_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+  v4f32_a = v4f32_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+
+  v4f64_b = v4f64_b + a;
+  v4f64_b = v4f64_b + b;
+  v4f64_b = v4f64_b + c;
+  v4f64_b = v4f64_b + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v4f64' (vector of 4 'double' values) as implicit conversion would cause truncation}}
+}
+
+void floatTestSignedType(char a, short b, int c, long long d) {
+
+  v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+  v4f64 v4f64_b = {0.4, 0.4, 0.4, 0.4};
+
+  v4f32_a = v4f32_a + a;
+  v4f32_a = v4f32_a + b;
+  v4f32_a = v4f32_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+  v4f32_a = v4f32_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+
+  v4f64_b = v4f64_b + a;
+  v4f64_b = v4f64_b + b;
+  v4f64_b = v4f64_b + c;
+  v4f64_b = v4f64_b + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v4f64' (vector of 4 'double' values) as implicit conversion would cause truncation}}
+}
+
+void intTestType(char a, short b, int c, long long d) {
+
+  v2i64 v2i64_a = {1, 2};
+  v2i32 v2i32_a = {1, 2};
+  v2i16 v2i16_a = {1, 2};
+  v2i8 v2i8_a = {1, 2};
+
+  v2i64_a = v2i64_a + d;
+  v2i64_a = v2i64_a + c;
+  v2i64_a = v2i64_a + b;
+  v2i64_a = v2i64_a + a;
+
+  v2i32_a = v2i32_a + d; // expected-warning {{implicit conversion loses integer precision: 'long long' to 'v2i32' (vector of 2 'int' values)}}
+  v2i32_a = v2i32_a + c;
+  v2i32_a = v2i32_a + b;
+  v2i32_a = v2i32_a + a;
+
+  v2i16_a = v2i16_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+  v2i16_a = v2i16_a + c; // expected-warning {{implicit conversion loses integer precision: 'int' to 'v2i16' (vector of 2 'short' values)}}
+  v2i16_a = v2i16_a + b;
+  v2i16_a = v2i16_a + a;
+
+  v2i8_a = v2i8_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+  v2i8_a = v2i8_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+  v2i8_a = v2i8_a + b; // expected-warning {{implicit conversion loses integer precision: 'short' to 'v2i8' (vector of 2 'char' values)}}
+  v2i8_a = v2i8_a + a;
+}
+
+void intTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+                         unsigned long long d) {
+
+  v2i64 v2i64_a = {1, 2};
+  v2i32 v2i32_a = {1, 2};
+  v2i16 v2i16_a = {1, 2};
+  v2i8 v2i8_a = {1, 2};
+
+  v2i64_a = v2i64_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i64' (vector of 2 'long long' values) as implicit conversion would cause truncation}}
+
+  v2i64_a = v2i64_a + c;
+  v2i64_a = v2i64_a + b;
+  v2i64_a = v2i64_a + a;
+
+  v2i32_a = v2i32_a + d; // expected-warning {{implicit conversion loses integer precision: 'unsigned long long' to 'v2i32' (vector of 2 'int' values)}}
+  v2i32_a = v2i32_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2i32' (vector of 2 'int' values) as implicit conversion would cause truncation}}
+  v2i32_a = v2i32_a + b;
+  v2i32_a = v2i32_a + a;
+
+  v2i16_a = v2i16_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+  v2i16_a = v2i16_a + c; // expected-warning {{implicit conversion loses integer precision: 'unsigned int' to 'v2i16' (vector of 2 'short' values)}}
+  v2i16_a = v2i16_a + b; // expected-error {{cannot convert between scalar type 'unsigned short' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+  v2i16_a = v2i16_a + a;
+
+  v2i8_a = v2i8_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+  v2i8_a = v2i8_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+  v2i8_a = v2i8_a + b; // expected-warning {{implicit conversion loses integer precision: 'unsigned short' to 'v2i8' (vector of 2 'char' values)}}
+  v2i8_a = v2i8_a + a; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+}
+
+void uintTestType(char a, short b, int c, long long d) {
+
+  v2u64 v2u64_a = {1, 2};
+  v2u32 v2u32_a = {1, 2};
+  v2u16 v2u16_a = {1, 2};
+  v2u8 v2u8_a = {1, 2};
+
+  v2u64_a = v2u64_a + d; // expected-warning {{implicit conversion changes signedness: 'long long' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+  v2u64_a = v2u64_a + c; // expected-warning {{implicit conversion changes signedness: 'int' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+  v2u64_a = v2u64_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+  v2u64_a = v2u64_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+
+  v2u32_a = v2u32_a + d; // expected-warning {{implicit conversion loses integer precision: 'long long' to 'v2u32' (vector of 2 'unsigned int' values)}}
+  v2u32_a = v2u32_a + c; // expected-warning {{implicit conversion changes signedness: 'int' to 'v2u32' (vector of 2 'unsigned int' values)}}
+  v2u32_a = v2u32_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u32' (vector of 2 'unsigned int' values)}}
+  v2u32_a = v2u32_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u32' (vector of 2 'unsigned int' values)}}
+
+  v2u16_a = v2u16_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2u16' (vector of 2 'unsigned short' values) as implicit conversion would cause truncation}}
+  v2u16_a = v2u16_a + c; // expected-warning {{implicit conversion loses integer precision: 'int' to 'v2u16' (vector of 2 'unsigned short' values)}}
+  v2u16_a = v2u16_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u16' (vector of 2 'unsigned short' values)}}
+  v2u16_a = v2u16_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u16' (vector of 2 'unsigned short' values)}}
+
+  v2u8_a = v2u8_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+  v2u8_a = v2u8_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+  v2u8_a = v2u8_a + b; // expected-warning {{implicit conversion loses integer precision: 'short' to 'v2u8' (vector of 2 'unsigned char' values)}}
+  v2u8_a = v2u8_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u8' (vector of 2 'unsigned char' values)}}
+}
+
+void uintTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+                          unsigned long long d) {
+
+  v2u64 v2u64_a = {1, 2};
+  v2u32 v2u32_a = {1, 2};
+  v2u16 v2u16_a = {1, 2};
+  v2u8 v2u8_a = {1, 2};
+
+  v2u64_a = v2u64_a + d;
+  v2u64_a = v2u64_a + c;
+  v2u64_a = v2u64_a + b;
+  v2u64_a = v2u64_a + a;
+
+  v2u32_a = v2u32_a + d; // expected-warning {{implicit conversion loses integer precision: 'unsigned long long' to 'v2u32' (vector of 2 'unsigned int' values)}}
+  v2u32_a = v2u32_a + c;
+  v2u32_a = v2u32_a + b;
+  v2u32_a = v2u32_a + a;
+
+  v2u16_a = v2u16_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2u16' (vector of 2 'unsigned short' values) as implicit conversion would cause truncation}}
+  v2u16_a = v2u16_a + c; // expected-warning {{implicit conversion loses integer precision: 'unsigned int' to 'v2u16' (vector of 2 'unsigned short' values)}}
+  v2u16_a = v2u16_a + b;
+  v2u16_a = v2u16_a + a;
+
+  v2u8_a = v2u8_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+  v2u8_a = v2u8_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+  v2u8_a = v2u8_a + b; // expected-warning {{implicit conversion loses integer precision: 'unsigned short' to 'v2u8' (vector of 2 'unsigned char' values)}}
+  v2u8_a = v2u8_a + a;
+}
+
+void uintTestConstant(v2u64 v2u64_a, v2u32 v2u32_a, v2u16 v2u16_a,
+                      v2u8 v2u8_a) {
+
+  v2u64_a = v2u64_a + 0xFFFFFFFFFFFFFFFF;
+  v2u32_a = v2u32_a + 0xFFFFFFFF;
+  v2u16_a = v2u16_a + 0xFFFF;
+  v2u8_a = v2u8_a + 0xFF;
+
+  v2u32_a = v2u32_a + 0x1FFFFFFFF; // expected-warning {{implicit conversion from 'long' to 'v2u32' (vector of 2 'unsigned int' values) changes value from 8589934591 to 4294967295}}
+  v2u16_a = v2u16_a + 0x1FFFF;     // expected-warning {{implicit conversion from 'int' to 'v2u16' (vector of 2 'unsigned short' values) changes value from 131071 to 65535}}
+  v2u8_a = v2u8_a + 0x1FF;         // expected-error {{cannot convert between scalar type 'int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+}
+
+void intTestConstant(v2i64 v2i64_a, v2i32 v2i32_a, v2i16 v2i16_a, v2i8 v2i8_a) {
+
+  // Legal upper bounds.
+  v2i64_a = v2i64_a + (long long)0x7FFFFFFFFFFFFFFF;
+  v2i32_a = v2i32_a + (int)0x7FFFFFFF;
+  v2i16_a = v2i16_a + (short)0x7FFF;
+  v2i8_a = v2i8_a + (char)0x7F;
+
+  // Legal lower bounds.
+  v2i64_a = v2i64_a + (-9223372036854775807);
+  v2i32_a = v2i32_a + (-2147483648);
+  v2i16_a = v2i16_a + (-32768);
+  v2i8_a = v2i8_a + (-128);
+
+  // One increment/decrement more than the type can hold
+  v2i32_a = v2i32_a + 2147483648; // expected-warning {{implicit conversion from 'long' to 'v2i32' (vector of 2 'int' values) changes value from 2147483648 to -2147483648}}
+  v2i16_a = v2i16_a + 32768;      // expected-warning {{implicit conversion from 'int' to 'v2i16' (vector of 2 'short' values) changes value from 32768 to -32768}}
+  v2i8_a = v2i8_a + 128;          // expected-warning {{implicit conversion from 'int' to 'v2i8' (vector of 2 'char' values) changes value from 128 to -128}}
+
+  v2i32_a = v2i32_a + (-2147483649); // expected-warning {{implicit conversion from 'long' to 'v2i32' (vector of 2 'int' values) changes value from -2147483649 to 2147483647}}
+  v2i16_a = v2i16_a + (-32769);      // expected-warning {{implicit conversion from 'int' to 'v2i16' (vector of 2 'short' values) changes value from -32769 to 32767}}
+  v2i8_a = v2i8_a + (-129);          // expected-error {{cannot convert between scalar type 'int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+}
Index: test/Sema/vector-cast.c
===================================================================
--- test/Sema/vector-cast.c
+++ test/Sema/vector-cast.c
@@ -53,9 +53,8 @@
   float2 f2;
   double d, a, b, c;
   float64x2_t v = {0.0, 1.0};
-  // FIXME: These diagnostics are inaccurate: should complain that 'double' to vector 'float2' involves truncation
-  f2 += d; // expected-error {{cannot convert between vector values of different size ('float2' (vector of 2 'float' values) and 'double')}}
-  d += f2; // expected-error {{cannot convert between vector values of different size}}
+  f2 += d; // expected-error {{cannot convert between scalar type 'double' and vector type 'float2' (vector of 2 'float' values) as implicit conversion would cause truncation}}
+  d += f2; // expected-error {{cannot convert between scalar type 'double' and vector type 'float2' (vector of 2 'float' values) as implicit conversion would cause truncation}}
   a = 3.0 + vget_low_f64(v);
   b = vget_low_f64(v) + 3.0;
   c = vget_low_f64(v);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -7957,6 +7957,139 @@
   return false;
 }
 
+/// Attempt to convert and splat Scalar into a vector whose types matches
+/// Vector following GCC conversion rules. The main rule is that implicit
+/// conversion occurs when Scalar can be casted to match Vector's element type
+/// without causing truncation of Scalar.
+static bool tryGCCVectorConvertAndSpalt(Sema &S, ExprResult *Scalar,
+                                        ExprResult *Vector) {
+  QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType();
+  QualType VectorTy = Vector->get()->getType().getUnqualifiedType();
+  const VectorType *VT = VectorTy->getAs<VectorType>();
+  QualType VectorEltTy = VT->getElementType();
+
+  // Reject cases where the vector element type or the scalar element type are
+  // not integral or floating point types.
+  if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType())
+    return true;
+
+  // The conversion to apply to the scalar before splatting it,
+  // if necessary.
+  CastKind ScalarCast = CK_Invalid;
+
+  // Accept cases where the vector elements are integers and the scalar is
+  // an integer.
+  // FIXME: Notionally if the scalar was a floating point value with a precise
+  //        integral representation, we could cast it to an appropriate integer
+  //        type and then perform the rest of the checks here. GCC as of
+  //        pre-release 7.0 does not accept this though.
+  if (VectorEltTy->isIntegralType(S.Context) &&
+      ScalarTy->isIntegralType(S.Context) &&
+      S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy)) {
+
+    // Reject cases where the value of the scalar is unknown as that would
+    // possibly cause truncation, but accept cases where the scalar can be
+    // demoted without loss of precision.
+    llvm::APSInt Result;
+    bool CstScalar = Scalar->get()->EvaluateAsInt(Result, S.Context);
+    int Order = S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy);
+    bool ScalarSigned = ScalarTy->hasSignedIntegerRepresentation();
+    bool VectorSigned = VectorTy->hasSignedIntegerRepresentation();
+
+    if (CstScalar) {
+      // If the scalar is constant and is of a higher order and has more active
+      // bits that the vector element type, reject it.
+      unsigned NumBits = ScalarSigned
+                             ? (Result.isNegative() ? Result.getMinSignedBits()
+                                                    : Result.getActiveBits())
+                             : Result.getActiveBits();
+      if (Order < 0 && S.Context.getIntWidth(VectorEltTy) < NumBits)
+        return true;
+
+      // If the signedness of the scalar type and the vector element type
+      // differs and the number of bits is greater than that of the vector
+      // element reject it.
+      if (ScalarSigned != VectorSigned &&
+          NumBits > S.Context.getIntWidth(VectorEltTy))
+        return true;
+    } else {
+
+      // Reject cases where the value of the scalar is not constant and it's
+      // order is greater than that of the vector element type.
+      if (Order < 0)
+        return true;
+    }
+
+    ScalarCast = CK_IntegralCast;
+  } else if (VectorEltTy->isRealFloatingType()) {
+    if (ScalarTy->isRealFloatingType()) {
+
+      // Reject cases where the scalar type is not a constant and has a higher
+      // Order than the vector element type.
+      llvm::APFloat Result(0.0);
+      bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context);
+      int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
+      if (!CstScalar && Order < 0)
+        return true;
+
+      // If the scalar cannot be safely casted to the vector element type,
+      // reject it.
+      if (CstScalar) {
+        bool Truncated = false;
+        Result.convert(S.Context.getFloatTypeSemantics(VectorEltTy),
+                       llvm::APFloat::rmNearestTiesToEven, &Truncated);
+        if (Truncated)
+          return true;
+      }
+
+      ScalarCast = CK_FloatingCast;
+    } else if (ScalarTy->isIntegralType(S.Context)) {
+      // Determine if the integer constant can be expressed as a floating point
+      // number of the appropiate type.
+      llvm::APSInt Result;
+      bool CstScalar = Scalar->get()->EvaluateAsInt(Result, S.Context);
+      uint64_t Bits = 0;
+      if (CstScalar) {
+        // Reject constants that would be truncated if they were converted to
+        // the floating point type. Test by simple to/from conversion.
+        // FIXME: Ideally the conversion to an APFloat and from an APFloat
+        //        could be avoided if there was a convertFromAPInt method
+        //        which could signal back if implicit truncation occurred.
+        llvm::APFloat Float(S.Context.getFloatTypeSemantics(VectorEltTy));
+        Float.convertFromAPInt(Result,
+                               ScalarTy->hasSignedIntegerRepresentation(),
+                               llvm::APFloat::rmTowardZero);
+        llvm::APSInt ConvertBack(S.Context.getIntWidth(ScalarTy),
+                                 !ScalarTy->hasSignedIntegerRepresentation());
+        bool ignored = false;
+        Float.convertToInteger(
+            ConvertBack, llvm::APFloat::rmNearestTiesToEven, &ignored);
+        if (Result != ConvertBack)
+          return true;
+      } else {
+        // Reject types that cannot be fully encoded into the mantissa of
+        // the float.
+        Bits = S.Context.getTypeSize(ScalarTy);
+        unsigned FloatPrec = llvm::APFloat::semanticsPrecision(
+            S.Context.getFloatTypeSemantics(VectorEltTy));
+        if (Bits > FloatPrec)
+          return true;
+      }
+
+      ScalarCast = CK_IntegralToFloating;
+    } else
+      return true;
+  }
+
+  // Adjust scalar if desired.
+  if (Scalar) {
+    if (ScalarCast != CK_Invalid)
+      *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast);
+    *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat);
+  }
+  return false;
+}
+
 QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
                                    SourceLocation Loc, bool IsCompAssign,
                                    bool AllowBothBool,
@@ -8025,19 +8158,28 @@
     }
   }
 
-  // If there's an ext-vector type and a scalar, try to convert the scalar to
+  // If there's an vector type and a scalar, try to convert the scalar to
   // the vector element type and splat.
-  // FIXME: this should also work for regular vector types as supported in GCC.
-  if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) {
-    if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
-                                  LHSVecType->getElementType(), LHSType))
-      return LHSType;
+  if (!RHSVecType) {
+    if (isa<ExtVectorType>(LHSVecType)) {
+      if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
+                                    LHSVecType->getElementType(), LHSType))
+        return LHSType;
+    } else {
+      if (!tryGCCVectorConvertAndSpalt(*this, &RHS, &LHS))
+        return LHSType;
+    }
   }
-  if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) {
-    if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
-                                  LHSType, RHSVecType->getElementType(),
-                                  RHSType))
-      return RHSType;
+  if (!LHSVecType) {
+    if (isa<ExtVectorType>(RHSVecType)) {
+      if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
+                                    LHSType, RHSVecType->getElementType(),
+                                    RHSType))
+        return RHSType;
+    } else {
+      if (!tryGCCVectorConvertAndSpalt(*this, &LHS, &RHS))
+        return RHSType;
+    }
   }
 
   // FIXME: The code below also handles convertion between vectors and
@@ -8090,6 +8232,22 @@
     return QualType();
   }
 
+
+  // If there is a vector type that is not a ExtVector and a sclar, we reach
+  // this point if scalar could not be converted to the vector's element type
+  // without truncation.
+  if ((RHSVecType && !isa<ExtVectorType>(RHSVecType)) ||
+      (LHSVecType && !isa<ExtVectorType>(LHSVecType))) {
+    QualType Scalar = LHSVecType ? RHSType : LHSType;
+    QualType Vector = LHSVecType ? LHSType : RHSType;
+    unsigned ScalarOrVector = LHSVecType && RHSVecType ? 1 : 0;
+    Diag(Loc,
+         diag::err_typecheck_vector_not_convertable_implict_truncation)
+        << ScalarOrVector << Scalar << Vector;
+
+    return QualType();
+  }
+
   // Otherwise, use the generic diagnostic.
   Diag(Loc, diag::err_typecheck_vector_not_convertable)
     << LHSType << RHSType
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2322,6 +2322,9 @@
   "vector size not an integral multiple of component size">;
 def err_attribute_zero_size : Error<"zero vector size">;
 def err_attribute_size_too_large : Error<"vector size too large">;
+def err_typecheck_vector_not_convertable_implict_truncation : Error<
+   "cannot convert between %select{scalar|vector}0 type %1 and vector type"
+   " %2 as implicit conversion would cause truncation">;
 def err_typecheck_vector_not_convertable : Error<
   "cannot convert between vector values of different size (%0 and %1)">;
 def err_typecheck_vector_not_convertable_non_scalar : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to