public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Scalar vector binary operation
@ 2011-08-09 23:54 Artem Shinkarov
  2011-08-10  0:00 ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2011-08-09 23:54 UTC (permalink / raw)
  To: gcc-patches, Richard Guenther

This is a patch that was approved a long time ago here:
http://gcc.gnu.org/ml/gcc-patches/2011-01/msg01833.html
but was never submitted.

2011-08-09  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

 /gcc
 * c-typeck.c (scalar_to_vector): New function. Try scalar to
vector conversion.
 (stv_conv): New enum for scalar_to_vector return type.
 (build_binary_op): Adjust.
 * doc/extend.texi: Description of scalar to vector expansion.

 /gcc/c-family
 * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to
 convert an expression to the type.
 (conversion_warning): Adjust, use unsafe_conversion_p.
 * c-common.h (unsafe_conversion_p): New function declaration.

 /gcc/testsuite
 * gcc.c-torture/execute/scal-to-vec1.c: New test.
 * gcc.c-torture/execute/scal-to-vec2.c: New test.
 * gcc.c-torture/execute/scal-to-vec3.c: New test.
 * gcc.dg/scal-to-vec1.c: New test.
 * gcc.dg/scal-to-vec2.c: New test.

bootstrapped and tested on x86_64_unknown-linux



Thanks,
Artem.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-08-09 23:54 Scalar vector binary operation Artem Shinkarov
@ 2011-08-10  0:00 ` Artem Shinkarov
  2011-08-10 15:02   ` Richard Guenther
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2011-08-10  0:00 UTC (permalink / raw)
  To: gcc-patches, Richard Guenther

[-- Attachment #1: Type: text/plain, Size: 81 bytes --]

Sorry, I didn't attach the patch itself.
Here we go, in the attachment.


Artem.

[-- Attachment #2: scal-to-vec.c.v13.diff --]
[-- Type: text/plain, Size: 30731 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 177589)
+++ gcc/doc/extend.texi	(working copy)
@@ -6526,18 +6526,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 177589)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1922,143 +1922,92 @@ shorten_binary_op (tree result_type, tre
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Checks if expression EXPR of real/integer type cannot be converted 
+   to the real/integer type TYPE. Function returns true when:
+	* EXPR is a constant which cannot be exactly converted to TYPE 
+	* EXPR is not a constant and size of EXPR's type > than size of TYPE, 
+	  for EXPR type and TYPE being both integers or both real.
+	* EXPR is not a constant of real type and TYPE is an integer.  
+	* EXPR is not a constant of integer type which cannot be 
+	  exactly converted to real type.  
+   Function allows conversions between types of different signedness and
+   does not return true in that case.  Function can produce signedness
+   warnings if PRODUCE_WARNS is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
-    {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
-         to integer type.  */
+	 to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        {
-          if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
-            give_warning = true;
-        }
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	{
+	  if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
+	    give_warning = true;
+	}
       /* Warn for an integer constant that does not fit into integer type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE
-               && !int_fits_type_p (expr, type))
-        {
-          if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
+	       && TREE_CODE (type) == INTEGER_TYPE
+	       && !int_fits_type_p (expr, type))
+	{
+	  if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
-          else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "negative integer"
+			    " implicitly converted to unsigned type");
+	    }
+	  else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+	    }
 	  else
 	    give_warning = true;
-        }
+	}
       else if (TREE_CODE (type) == REAL_TYPE)
-        {
-          /* Warn for an integer constant that does not fit into real type.  */
-          if (TREE_CODE (expr_type) == INTEGER_TYPE)
-            {
-              REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-          /* Warn for a real constant that does not fit into a smaller
-             real type.  */
-          else if (TREE_CODE (expr_type) == REAL_TYPE
-                   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-            {
-              REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-        }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+	{
+	  /* Warn for an integer constant that does not fit into real type.  */
+	  if (TREE_CODE (expr_type) == INTEGER_TYPE)
+	    {
+	      REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	  /* Warn for a real constant that does not fit into a smaller
+	     real type.  */
+	  else if (TREE_CODE (expr_type) == REAL_TYPE
+		   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	    {
+	      REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	}
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        give_warning = true;
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	give_warning = true;
 
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE)
-        {
+	       && TREE_CODE (type) == INTEGER_TYPE)
+	{
 	  /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2085,7 +2034,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2094,58 +2043,136 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
-          /* Warn for integer types converted to smaller integer types.  */
+	  /* Warn for integer types converted to smaller integer types.  */
 	  if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
 	    give_warning = true;
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
-        }
+	}
 
       /* Warn for integer types converted to real types if and only if
-         all the range of values of the integer type cannot be
-         represented by the real type.  */
+	 all the range of values of the integer type cannot be
+	 represented by the real type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == REAL_TYPE)
-        {
+	       && TREE_CODE (type) == REAL_TYPE)
+	{
 	  tree type_low_bound, type_high_bound;
-          REAL_VALUE_TYPE real_low_bound, real_high_bound;
+	  REAL_VALUE_TYPE real_low_bound, real_high_bound;
 
 	  /* Don't warn about char y = 0xff; float x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
-          type_low_bound = TYPE_MIN_VALUE (expr_type);
-          type_high_bound = TYPE_MAX_VALUE (expr_type);
-          real_low_bound = real_value_from_int_cst (0, type_low_bound);
-          real_high_bound = real_value_from_int_cst (0, type_high_bound);
-
-          if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
-              || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
-            give_warning = true;
-        }
+	  type_low_bound = TYPE_MIN_VALUE (expr_type);
+	  type_high_bound = TYPE_MAX_VALUE (expr_type);
+	  real_low_bound = real_value_from_int_cst (0, type_low_bound);
+	  real_high_bound = real_value_from_int_cst (0, type_high_bound);
+
+	  if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
+	      || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
+	    give_warning = true;
+	}
 
       /* Warn for real types converted to smaller real types.  */
       else if (TREE_CODE (expr_type) == REAL_TYPE
-               && TREE_CODE (type) == REAL_TYPE
-               && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-        give_warning = true;
+	       && TREE_CODE (type) == REAL_TYPE
+	       && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	give_warning = true;
+    }
+
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
+
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
+
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
+
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
 
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
 
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
     }
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 177589)
+++ gcc/c-family/c-common.h	(working copy)
@@ -742,6 +742,7 @@ extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern void c_common_init_ts (void);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+extern long long sll;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "conversion of scalar to vector" } */
+    f1 = 1.3 + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = sll + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do compile } */   
+
+/* Test for C_MAYBE_CONST are folded correctly when 
+   expanding an expression to vector.  */
+
+int 			f(void);
+unsigned int 		g(void);
+unsigned int 		h;
+
+typedef unsigned int vec __attribute__((vector_size(16)));
+
+vec i;
+
+
+vec fv1(void) { return i + (h ? f() : g()); }
+vec fv2(void) { return (h ? f() : g()) + i; }
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 177589)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* The level of nesting inside "__alignof__".  */
 int in_alignof;
 
@@ -9323,6 +9331,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+	      || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    else
+	      return stv_firstarg;
+	  }
+	break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+	integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+	if (TREE_CODE (type0) == VECTOR_TYPE)
+	  {
+	    tree tmp;
+	    ret = stv_secondarg;
+	    /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+	    tmp = type0; type0 = type1; type1 = tmp;
+	    tmp = op0; op0 = op1; op1 = tmp;
+	  }
+
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+	else if (!integer_only_op
+		    /* Allow integer --> real conversion if safe.  */
+		 && (TREE_CODE (type0) == REAL_TYPE 
+		     || TREE_CODE (type0) == INTEGER_TYPE)
+		 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+      default:
+	break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9434,7 +9524,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+	   != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9506,6 +9599,51 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+      
+      switch (convert_flag)
+	{
+	  case stv_error:
+	    return error_mark_node;
+	  case stv_firstarg:
+	    {
+              bool maybe_const = true;
+              tree sc;
+              sc = c_fully_fold (op0, false, &maybe_const);
+              sc = save_expr (sc);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              if (!maybe_const)
+                op0 = c_wrap_maybe_const (op0, true);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+	    }
+	  case stv_secondarg:
+	    {
+	      bool maybe_const = true;
+	      tree sc;
+	      sc = c_fully_fold (op1, false, &maybe_const);
+	      sc = save_expr (sc);
+	      sc = convert (TREE_TYPE (type0), sc);
+	      op1 = build_vector_from_val (type0, sc);
+	      if (!maybe_const)
+		op0 = c_wrap_maybe_const (op1, true);
+	      orig_type1 = type1 = TREE_TYPE (op1);
+	      code1 = TREE_CODE (type1);
+	      converted = 1;
+	      break;
+	    }
+	  default:
+	    break;
+	}
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-08-10  0:00 ` Artem Shinkarov
@ 2011-08-10 15:02   ` Richard Guenther
  2011-09-28 14:33     ` Ian Lance Taylor
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Guenther @ 2011-08-10 15:02 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: gcc-patches

On Tue, Aug 9, 2011 at 10:23 PM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> Sorry, I didn't attach the patch itself.
> Here we go, in the attachment.

I have committed the patch after re-bootstrapping and testing it
on x86_64-unknown-linux-gnu with {,-m32}.

Richard.

>
> Artem.
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-08-10 15:02   ` Richard Guenther
@ 2011-09-28 14:33     ` Ian Lance Taylor
  2011-09-28 14:55       ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Ian Lance Taylor @ 2011-09-28 14:33 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Artem Shinkarov, gcc-patches

On Wed, Aug 10, 2011 at 7:44 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
>
> On Tue, Aug 9, 2011 at 10:23 PM, Artem Shinkarov
> <artyom.shinkaroff@gmail.com> wrote:
> > Sorry, I didn't attach the patch itself.
> > Here we go, in the attachment.
>
> I have committed the patch after re-bootstrapping and testing it
> on x86_64-unknown-linux-gnu with {,-m32}.

This is new functionality for gcc's vector extension, and I think it
should be mentioned at http://gcc.gnu.org/gcc-4.7/changes.html.  Does
somebody want to take care of that?

Ian

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-09-28 14:33     ` Ian Lance Taylor
@ 2011-09-28 14:55       ` Artem Shinkarov
  2011-09-28 15:48         ` Ian Lance Taylor
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2011-09-28 14:55 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Richard Guenther, gcc-patches

Ian

I can try to put a description in the document. I am not sure that I
have rights to commit to the svn, but at least I can try to write the
text.

There are also pending patches for vector-comparison (almost
submitted) and vector shuffling (still under discussion), but I hope
to finish both of them until the new release is coming.

Could you point out where the cnhanges.html is located in svn?


Thanks,
Artem.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-09-28 14:55       ` Artem Shinkarov
@ 2011-09-28 15:48         ` Ian Lance Taylor
  2011-09-28 20:46           ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Ian Lance Taylor @ 2011-09-28 15:48 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Richard Guenther, gcc-patches

Artem Shinkarov <artyom.shinkaroff@gmail.com> writes:

> I can try to put a description in the document. I am not sure that I
> have rights to commit to the svn, but at least I can try to write the
> text.
>
> There are also pending patches for vector-comparison (almost
> submitted) and vector shuffling (still under discussion), but I hope
> to finish both of them until the new release is coming.
>
> Could you point out where the cnhanges.html is located in svn?

It's actually still in CVS, at gcc.gnu.org:/cvs/gcc.

Ian

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-09-28 15:48         ` Ian Lance Taylor
@ 2011-09-28 20:46           ` Artem Shinkarov
  2011-12-05 11:27             ` Gerald Pfeifer
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2011-09-28 20:46 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 970 bytes --]

Hi

In the attachment there is a patch with the changes. I don't have
rights to commit to the cvs.

If we write about vector-related stuff, may be it would make sense to
mention that from now on we can make vector shifts and we can index
vector. These are changes from 4.6 (I guess), but they were never
mentioned in any changes.


Thanks,
Artem.


On Wed, Sep 28, 2011 at 3:46 PM, Ian Lance Taylor <iant@google.com> wrote:
> Artem Shinkarov <artyom.shinkaroff@gmail.com> writes:
>
>> I can try to put a description in the document. I am not sure that I
>> have rights to commit to the svn, but at least I can try to write the
>> text.
>>
>> There are also pending patches for vector-comparison (almost
>> submitted) and vector shuffling (still under discussion), but I hope
>> to finish both of them until the new release is coming.
>>
>> Could you point out where the cnhanges.html is located in svn?
>
> It's actually still in CVS, at gcc.gnu.org:/cvs/gcc.
>
> Ian
>

[-- Attachment #2: scalar-op.diff --]
[-- Type: text/plain, Size: 914 bytes --]

Index: htdocs/gcc-4.7/changes.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/gcc-4.7/changes.html,v
retrieving revision 1.38
diff -u -r1.38 changes.html
--- htdocs/gcc-4.7/changes.html	27 Sep 2011 18:42:56 -0000	1.38
+++ htdocs/gcc-4.7/changes.html	28 Sep 2011 18:52:33 -0000
@@ -150,6 +150,18 @@
       through which the compiler can be hinted about pointer alignment
       and can use it to improve generated code.
   </li>
+  <li>When a binary operation performed on vector types and one of the operands
+      is a uniform vector it is possible to replace the vector with the
+      generating element. For example:
+      <pre>
+typedef int v4si __attribute__ ((vector_size (16)));
+v4si res, a = {1,2,3,4};
+int x;
+
+res = 2 + a;  /* means {2,2,2,2} + a  */
+res = a - x;  /* means a - {x,x,x,x}  */
+      </pre>
+  </li>
 </ul>
 
 <h3>C++</h3>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-09-28 20:46           ` Artem Shinkarov
@ 2011-12-05 11:27             ` Gerald Pfeifer
  0 siblings, 0 replies; 28+ messages in thread
From: Gerald Pfeifer @ 2011-12-05 11:27 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Ian Lance Taylor, Richard Guenther, gcc-patches

On Wed, 28 Sep 2011, Artem Shinkarov wrote:
> In the attachment there is a patch with the changes. I don't have
> rights to commit to the cvs.

Thanks, Michael.  I have applied the patch on your behalf.

Gerald

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-01-26  1:13                           ` Joseph S. Myers
@ 2011-02-09 17:09                             ` Artem Shinkarov
  0 siblings, 0 replies; 28+ messages in thread
From: Artem Shinkarov @ 2011-02-09 17:09 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2262 bytes --]

I have tested the version Joseph proposed and currently it works fine.
But there certainly was a problem which is gone away by now. As you
can see from the previous mail Richard has discovered the problem as
well. Anyway, currently it is Joseph's original version in the patch.



2011-02-09  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

 /gcc
 * c-typeck.c (scalar_to_vector): New function. Try scalar to
vector conversion.
 (stv_conv): New enum for scalar_to_vector return type.
 (build_binary_op): Adjust.
 * doc/extend.texi: Description of scalar to vector expansion.

 /gcc/c-family
 * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to
 convert an expression to the type.
 (conversion_warning): Adjust, use unsafe_conversion_p.
 * c-common.h (unsafe_conversion_p): New function declaration.

 /gcc/testsuite
 * gcc.c-torture/execute/scal-to-vec1.c: New test.
 * gcc.c-torture/execute/scal-to-vec2.c: New test.
 * gcc.c-torture/execute/scal-to-vec3.c: New test.
 * gcc.dg/scal-to-vec1.c: New test.
 * gcc.dg/scal-to-vec2.c: New test.

bootstrapped and tested on x86_64_unknown-linux

Can we please submit it at last?


Thank you,
Artem.

On Wed, Jan 26, 2011 at 12:03 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Fri, 21 Jan 2011, Richard Guenther wrote:
>
>> Joseph, the updated patch now uses
>>
>> +         case stv_firstarg:
>> +           {
>> +             bool maybe_const = true;
>> +             tree sc = c_save_expr (op0);
>> +             sc = convert (TREE_TYPE (type1), sc);
>> +             sc = c_fully_fold (sc, false, &maybe_const);
>> +             op0 = build_vector_from_val (type1, sc);
>> +             if (!maybe_const)
>> +               op0 = c_wrap_maybe_const (op0, true);
>> +             orig_type0 = type0 = TREE_TYPE (op0);
>> +             code0 = TREE_CODE (type0);
>> +             converted = 1;
>> +             break;
>> +           }
>>
>> as your suggested ordering of c_fully_fold and c_save_expr didn't work.
>
> I thought I'd tested my code - for my testcase at least, not with a
> bootstrap.  Note that my proposed code used save_expr, not c_save_expr.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

[-- Attachment #2: scal-to-vec.c.v12.diff --]
[-- Type: text/x-diff, Size: 30735 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 169969)
+++ gcc/doc/extend.texi	(working copy)
@@ -6530,18 +6530,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 169969)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1864,143 +1864,92 @@ tree shorten_binary_op (tree result_type
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Checks if expression EXPR of real/integer type cannot be converted 
+   to the real/integer type TYPE. Function returns true when:
+	* EXPR is a constant which cannot be exactly converted to TYPE 
+	* EXPR is not a constant and size of EXPR's type > than size of TYPE, 
+	  for EXPR type and TYPE being both integers or both real.
+	* EXPR is not a constant of real type and TYPE is an integer.  
+	* EXPR is not a constant of integer type which cannot be 
+	  exactly converted to real type.  
+   Function allows conversions between types of different signedness and
+   does not return true in that case.  Function can produce signedness
+   warnings if PRODUCE_WARNS is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
-    {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
-         to integer type.  */
+	 to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        {
-          if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
-            give_warning = true;
-        }
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	{
+	  if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
+	    give_warning = true;
+	}
       /* Warn for an integer constant that does not fit into integer type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE
-               && !int_fits_type_p (expr, type))
-        {
-          if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
+	       && TREE_CODE (type) == INTEGER_TYPE
+	       && !int_fits_type_p (expr, type))
+	{
+	  if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
-          else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "negative integer"
+			    " implicitly converted to unsigned type");
+	    }
+	  else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+	    }
 	  else
 	    give_warning = true;
-        }
+	}
       else if (TREE_CODE (type) == REAL_TYPE)
-        {
-          /* Warn for an integer constant that does not fit into real type.  */
-          if (TREE_CODE (expr_type) == INTEGER_TYPE)
-            {
-              REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-          /* Warn for a real constant that does not fit into a smaller
-             real type.  */
-          else if (TREE_CODE (expr_type) == REAL_TYPE
-                   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-            {
-              REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-        }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+	{
+	  /* Warn for an integer constant that does not fit into real type.  */
+	  if (TREE_CODE (expr_type) == INTEGER_TYPE)
+	    {
+	      REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	  /* Warn for a real constant that does not fit into a smaller
+	     real type.  */
+	  else if (TREE_CODE (expr_type) == REAL_TYPE
+		   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	    {
+	      REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	}
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        give_warning = true;
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	give_warning = true;
 
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE)
-        {
+	       && TREE_CODE (type) == INTEGER_TYPE)
+	{
 	  /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2027,7 +1976,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2036,58 +1985,136 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
-          /* Warn for integer types converted to smaller integer types.  */
+	  /* Warn for integer types converted to smaller integer types.  */
 	  if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
 	    give_warning = true;
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
-        }
+	}
 
       /* Warn for integer types converted to real types if and only if
-         all the range of values of the integer type cannot be
-         represented by the real type.  */
+	 all the range of values of the integer type cannot be
+	 represented by the real type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == REAL_TYPE)
-        {
+	       && TREE_CODE (type) == REAL_TYPE)
+	{
 	  tree type_low_bound, type_high_bound;
-          REAL_VALUE_TYPE real_low_bound, real_high_bound;
+	  REAL_VALUE_TYPE real_low_bound, real_high_bound;
 
 	  /* Don't warn about char y = 0xff; float x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
-          type_low_bound = TYPE_MIN_VALUE (expr_type);
-          type_high_bound = TYPE_MAX_VALUE (expr_type);
-          real_low_bound = real_value_from_int_cst (0, type_low_bound);
-          real_high_bound = real_value_from_int_cst (0, type_high_bound);
-
-          if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
-              || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
-            give_warning = true;
-        }
+	  type_low_bound = TYPE_MIN_VALUE (expr_type);
+	  type_high_bound = TYPE_MAX_VALUE (expr_type);
+	  real_low_bound = real_value_from_int_cst (0, type_low_bound);
+	  real_high_bound = real_value_from_int_cst (0, type_high_bound);
+
+	  if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
+	      || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
+	    give_warning = true;
+	}
 
       /* Warn for real types converted to smaller real types.  */
       else if (TREE_CODE (expr_type) == REAL_TYPE
-               && TREE_CODE (type) == REAL_TYPE
-               && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-        give_warning = true;
+	       && TREE_CODE (type) == REAL_TYPE
+	       && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	give_warning = true;
+    }
 
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
 
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
+
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
+
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
+
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
+
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
     }
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 169969)
+++ gcc/c-family/c-common.h	(working copy)
@@ -708,6 +708,7 @@ extern tree c_common_unsigned_type (tree
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+extern long long sll;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "conversion of scalar to vector" } */
+    f1 = 1.3 + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = sll + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do compile } */   
+
+/* Test for C_MAYBE_CONST are folded correctly when 
+   expanding an expression to vector.  */
+
+int 			f(void);
+unsigned int 		g(void);
+unsigned int 		h;
+
+typedef unsigned int vec __attribute__((vector_size(16)));
+
+vec i;
+
+
+vec fv1(void) { return i + (h ? f() : g()); }
+vec fv2(void) { return (h ? f() : g()) + i; }
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 169969)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* The level of nesting inside "__alignof__".  */
 int in_alignof;
 
@@ -9315,6 +9323,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+	      || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    else
+	      return stv_firstarg;
+	  }
+	break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+	integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+	if (TREE_CODE (type0) == VECTOR_TYPE)
+	  {
+	    tree tmp;
+	    ret = stv_secondarg;
+	    /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+	    tmp = type0; type0 = type1; type1 = tmp;
+	    tmp = op0; op0 = op1; op1 = tmp;
+	  }
+
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+	else if (!integer_only_op
+		    /* Allow integer --> real conversion if safe.  */
+		 && (TREE_CODE (type0) == REAL_TYPE 
+		     || TREE_CODE (type0) == INTEGER_TYPE)
+		 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+      default:
+	break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9426,7 +9516,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+	   != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9498,6 +9591,51 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+      
+      switch (convert_flag)
+	{
+	  case stv_error:
+	    return error_mark_node;
+	  case stv_firstarg:
+	    {
+              bool maybe_const = true;
+              tree sc;
+              sc = c_fully_fold (op0, false, &maybe_const);
+              sc = save_expr (sc);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              if (!maybe_const)
+                op0 = c_wrap_maybe_const (op0, true);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+	    }
+	  case stv_secondarg:
+	    {
+	      bool maybe_const = true;
+	      tree sc;
+	      sc = c_fully_fold (op1, false, &maybe_const);
+	      sc = save_expr (sc);
+	      sc = convert (TREE_TYPE (type0), sc);
+	      op1 = build_vector_from_val (type0, sc);
+	      if (!maybe_const)
+		op0 = c_wrap_maybe_const (op1, true);
+	      orig_type1 = type1 = TREE_TYPE (op1);
+	      code1 = TREE_CODE (type1);
+	      converted = 1;
+	      break;
+	    }
+	  default:
+	    break;
+	}
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2011-01-21 15:24                         ` Richard Guenther
@ 2011-01-26  1:13                           ` Joseph S. Myers
  2011-02-09 17:09                             ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Joseph S. Myers @ 2011-01-26  1:13 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Artem Shinkarov, gcc-patches

On Fri, 21 Jan 2011, Richard Guenther wrote:

> Joseph, the updated patch now uses
> 
> +         case stv_firstarg:
> +           {
> +             bool maybe_const = true;
> +             tree sc = c_save_expr (op0);
> +             sc = convert (TREE_TYPE (type1), sc);
> +             sc = c_fully_fold (sc, false, &maybe_const);
> +             op0 = build_vector_from_val (type1, sc);
> +             if (!maybe_const)
> +               op0 = c_wrap_maybe_const (op0, true);
> +             orig_type0 = type0 = TREE_TYPE (op0);
> +             code0 = TREE_CODE (type0);
> +             converted = 1;
> +             break;
> +           }
> 
> as your suggested ordering of c_fully_fold and c_save_expr didn't work.

I thought I'd tested my code - for my testcase at least, not with a 
bootstrap.  Note that my proposed code used save_expr, not c_save_expr.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-12-17 16:16                       ` Artem Shinkarov
@ 2011-01-21 15:24                         ` Richard Guenther
  2011-01-26  1:13                           ` Joseph S. Myers
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Guenther @ 2011-01-21 15:24 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Joseph S. Myers, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4115 bytes --]

On Fri, Dec 17, 2010 at 4:17 PM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> Thank you for pointing out an issue with the c_maybe_const. It is solved now.
>
> 2010-12-17  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
>
>  /gcc
>  * c-typeck.c (scalar_to_vector): New function. Try scalar to
> vector conversion.
>  (stv_conv): New enum for scalar_to_vector return type.
>  (build_binary_op): Adjust.
>  * doc/extend.texi: Description of scalar to vector expansion.
>
>  /gcc/c-family
>  * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to
>  convert an expression to the type.
>  (conversion_warning): Adjust, use unsafe_conversion_p.
>  * c-common.h (unsafe_conversion_p): New function declaration.
>
>  /gcc/testsuite
>  * gcc.c-torture/execute/scal-to-vec1.c: New test.
>  * gcc.c-torture/execute/scal-to-vec2.c: New test.
>  * gcc.c-torture/execute/scal-to-vec3.c: New test.
>  * gcc.dg/scal-to-vec1.c: New test.
>  * gcc.dg/scal-to-vec2.c: New test.
>
> bootstrapped and tested on x86_64_unknown-linux
>
> If everyone is happy, may be then Richard could take care about the
> submission to svn.

Joseph, the updated patch now uses

+         case stv_firstarg:
+           {
+             bool maybe_const = true;
+             tree sc = c_save_expr (op0);
+             sc = convert (TREE_TYPE (type1), sc);
+             sc = c_fully_fold (sc, false, &maybe_const);
+             op0 = build_vector_from_val (type1, sc);
+             if (!maybe_const)
+               op0 = c_wrap_maybe_const (op0, true);
+             orig_type0 = type0 = TREE_TYPE (op0);
+             code0 = TREE_CODE (type0);
+             converted = 1;
+             break;
+           }

as your suggested ordering of c_fully_fold and c_save_expr didn't work.
I investigated the situation and it is not exactly clear what we want to
end up with.  For your testcase

+int                    f(void);
+unsigned int           g(void);
+unsigned int           h;
+
+typedef unsigned int vec __attribute__((vector_size(16)));
+
+vec i;
+vec fv2(void) { return (h ? f() : g()) + i; }

we start with building the plus for

(gdb) call debug_generic_expr (arg1.value)
<<< Unknown tree: c_maybe_const_expr

  h >>> != 0 ? (unsigned int) <<< Unknown tree: c_maybe_const_expr

  f () >>> : <<< Unknown tree: c_maybe_const_expr

  g () >>>
(gdb) call debug_generic_expr (arg2.value)
i

so we know i is not maybe-const but the cond-expr and its args
are.  Calling c_fully_fold on arg1 produces

h != 0 ? (unsigned int) f () : g ()

with all maybe-consts stripped (as expected) and maybe_const set
to false.  Calling c_save_expr on that result will wrap
it inside a c-surely-not-const tree.

As we don't want that c-surely-not-const tree inside the save-expr(?)
we are about to create (nor inside the vector arguments) we probably
want to open-code c_save_expr here and use

              bool maybe_const = true;
              tree sc = op0;
              sc = c_fully_fold (sc, false, &maybe_const);
              sc = convert (TREE_TYPE (type1), sc);
              sc = save_expr (sc);
              op0 = build_vector_from_val (type1, sc);
              if (!maybe_const)
                op0 = c_wrap_maybe_const (op0, true);

instead.  Now the thing I don't know is whether we are sure that
a really constant maybe-const-expr will be folded to a constant
by c_fully_fold always, so that we never need to wrap the
resulting vector inside a c-maybe-const expression.

With the above we will end up with

(gdb) call debug_generic_expr (op0)
<<< Unknown tree: c_maybe_const_expr

  {SAVE_EXPR <h != 0 ? (unsigned int) f () : g ()>, SAVE_EXPR <h != 0
? (unsigned int) f () : g ()>, SAVE_EXPR <h != 0 ? (unsigned int) f ()
: g ()>, SAVE_EXPR <h != 0 ? (unsigned int) f () : g ()>} >>>

for the vector which looks ok to me (and it also passes your testcase).

I am now re-testing the patch with the above change (patch attached).

Joseph, is the patch still ok at this stage?

Thanks,
Richard.

[-- Attachment #2: scal-to-vec.c.v11.diff --]
[-- Type: text/x-patch, Size: 31609 bytes --]

2011-01-21  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

	* c-typeck.c (scalar_to_vector): New function. Try scalar to
	vector conversion.
	(stv_conv): New enum for scalar_to_vector return type.
	(build_binary_op): Adjust.
	* doc/extend.texi: Description of scalar to vector expansion.

	c-family/
	* c-common.c (unsafe_conversion_p): New function. Check if it is unsafe
	to convert an expression to the type.
	(conversion_warning): Adjust, use unsafe_conversion_p.
	* c-common.h (unsafe_conversion_p): New function declaration.

	testsuite/
	* gcc.c-torture/execute/scal-to-vec1.c: New test.
	* gcc.c-torture/execute/scal-to-vec2.c: New test.
	* gcc.c-torture/execute/scal-to-vec3.c: New test.
	* gcc.dg/scal-to-vec1.c: New test.
	* gcc.dg/scal-to-vec2.c: New test.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi.orig	2011-01-19 11:28:20.000000000 +0100
+++ gcc/doc/extend.texi	2011-01-21 15:55:29.000000000 +0100
@@ -6525,18 +6525,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements.
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c.orig	2011-01-10 16:57:23.000000000 +0100
+++ gcc/c-family/c-common.c	2011-01-21 15:57:29.000000000 +0100
@@ -1864,143 +1864,92 @@ tree shorten_binary_op (tree result_type
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Checks if expression EXPR of real/integer type cannot be converted
+   to the real/integer type TYPE. Function returns true when:
+	* EXPR is a constant which cannot be exactly converted to TYPE EXPR
+	* is not a constant and size of EXPR's type > than size of TYPE,
+	  for EXPR type and TYPE being both integers or both real.
+	* EXPR is not a constant of real type and TYPE is an integer.  EXPR
+	* is not a constant of integer type which cannot be
+	  exactly converted to real type.
+   Function allows conversions between types of different signedness and
+   does not return true in that case.  Function can produce signedness
+   warnings if PRODUCE_WARNS is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
-    {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
-         to integer type.  */
+	 to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        {
-          if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
-            give_warning = true;
-        }
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	{
+	  if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
+	    give_warning = true;
+	}
       /* Warn for an integer constant that does not fit into integer type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE
-               && !int_fits_type_p (expr, type))
-        {
-          if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
+	       && TREE_CODE (type) == INTEGER_TYPE
+	       && !int_fits_type_p (expr, type))
+	{
+	  if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
-          else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "negative integer"
+			    " implicitly converted to unsigned type");
+	    }
+	  else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+	    }
 	  else
 	    give_warning = true;
-        }
+	}
       else if (TREE_CODE (type) == REAL_TYPE)
-        {
-          /* Warn for an integer constant that does not fit into real type.  */
-          if (TREE_CODE (expr_type) == INTEGER_TYPE)
-            {
-              REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-          /* Warn for a real constant that does not fit into a smaller
-             real type.  */
-          else if (TREE_CODE (expr_type) == REAL_TYPE
-                   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-            {
-              REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-        }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+	{
+	  /* Warn for an integer constant that does not fit into real type.  */
+	  if (TREE_CODE (expr_type) == INTEGER_TYPE)
+	    {
+	      REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	  /* Warn for a real constant that does not fit into a smaller
+	     real type.  */
+	  else if (TREE_CODE (expr_type) == REAL_TYPE
+		   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	    {
+	      REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	}
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        give_warning = true;
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	give_warning = true;
 
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE)
-        {
+	       && TREE_CODE (type) == INTEGER_TYPE)
+	{
 	  /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2027,7 +1976,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2036,58 +1985,136 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
-          /* Warn for integer types converted to smaller integer types.  */
+	  /* Warn for integer types converted to smaller integer types.  */
 	  if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
 	    give_warning = true;
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
-        }
+	}
 
       /* Warn for integer types converted to real types if and only if
-         all the range of values of the integer type cannot be
-         represented by the real type.  */
+	 all the range of values of the integer type cannot be
+	 represented by the real type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == REAL_TYPE)
-        {
+	       && TREE_CODE (type) == REAL_TYPE)
+	{
 	  tree type_low_bound, type_high_bound;
-          REAL_VALUE_TYPE real_low_bound, real_high_bound;
+	  REAL_VALUE_TYPE real_low_bound, real_high_bound;
 
 	  /* Don't warn about char y = 0xff; float x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
-          type_low_bound = TYPE_MIN_VALUE (expr_type);
-          type_high_bound = TYPE_MAX_VALUE (expr_type);
-          real_low_bound = real_value_from_int_cst (0, type_low_bound);
-          real_high_bound = real_value_from_int_cst (0, type_high_bound);
-
-          if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
-              || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
-            give_warning = true;
-        }
+	  type_low_bound = TYPE_MIN_VALUE (expr_type);
+	  type_high_bound = TYPE_MAX_VALUE (expr_type);
+	  real_low_bound = real_value_from_int_cst (0, type_low_bound);
+	  real_high_bound = real_value_from_int_cst (0, type_high_bound);
+
+	  if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
+	      || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
+	    give_warning = true;
+	}
 
       /* Warn for real types converted to smaller real types.  */
       else if (TREE_CODE (expr_type) == REAL_TYPE
-               && TREE_CODE (type) == REAL_TYPE
-               && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-        give_warning = true;
+	       && TREE_CODE (type) == REAL_TYPE
+	       && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	give_warning = true;
+    }
+
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
+
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
+
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
+
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
 
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
 
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
     }
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h.orig	2011-01-10 12:30:19.000000000 +0100
+++ gcc/c-family/c-common.h	2011-01-21 15:28:35.000000000 +0100
@@ -708,6 +708,7 @@ extern tree c_common_unsigned_type (tree
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	2011-01-21 15:28:35.000000000 +0100
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	2011-01-21 15:28:35.000000000 +0100
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	2011-01-21 15:58:15.000000000 +0100
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	2011-01-21 15:57:46.000000000 +0100
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+extern long long sll;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "conversion of scalar to vector" } */
+    f1 = 1.3 + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = sll + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/scal-to-vec2.c	2011-01-21 15:57:58.000000000 +0100
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+
+/* Test for C_MAYBE_CONST are folded correctly when
+   expanding an expression to vector.  */
+
+int 			f(void);
+unsigned int 		g(void);
+unsigned int 		h;
+
+typedef unsigned int vec __attribute__((vector_size(16)));
+
+vec i;
+
+vec fv1(void) { return i + (h ? f() : g()); }
+vec fv2(void) { return (h ? f() : g()) + i; }
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c.orig	2011-01-10 12:31:21.000000000 +0100
+++ gcc/c-typeck.c	2011-01-21 15:56:59.000000000 +0100
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* The level of nesting inside "__alignof__".  */
 int in_alignof;
 
@@ -9315,6 +9323,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE
+	      || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    else
+	      return stv_firstarg;
+	  }
+	break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+	integer_only_op = true;
+	/* ... fall through ...  */
+
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+	if (TREE_CODE (type0) == VECTOR_TYPE)
+	  {
+	    tree tmp;
+	    ret = stv_secondarg;
+	    /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+	    tmp = type0; type0 = type1; type1 = tmp;
+	    tmp = op0; op0 = op1; op1 = tmp;
+	  }
+
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+	else if (!integer_only_op
+		    /* Allow integer --> real conversion if safe.  */
+		 && (TREE_CODE (type0) == REAL_TYPE
+		     || TREE_CODE (type0) == INTEGER_TYPE)
+		 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+      default:
+	break;
+    }
+
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9426,7 +9516,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE)
+	   != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9498,6 +9591,51 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+
+      switch (convert_flag)
+	{
+	  case stv_error:
+	    return error_mark_node;
+	  case stv_firstarg:
+	    {
+	      bool maybe_const = true;
+	      tree sc = op0;
+	      sc = c_fully_fold (sc, false, &maybe_const);
+	      sc = convert (TREE_TYPE (type1), sc);
+	      sc = save_expr (sc);
+	      op0 = build_vector_from_val (type1, sc);
+	      if (!maybe_const)
+		op0 = c_wrap_maybe_const (op0, true);
+	      orig_type0 = type0 = TREE_TYPE (op0);
+	      code0 = TREE_CODE (type0);
+	      converted = 1;
+	      break;
+	    }
+	  case stv_secondarg:
+	    {
+	      bool maybe_const = true;
+	      tree sc = op1;
+	      sc = c_fully_fold (sc, false, &maybe_const);
+	      sc = convert (TREE_TYPE (type0), sc);
+	      sc = save_expr (sc);
+	      op1 = build_vector_from_val (type0, sc);
+	      if (!maybe_const)
+		op1 = c_wrap_maybe_const (op1, true);
+	      orig_type1 = type1 = TREE_TYPE (op1);
+	      code1 = TREE_CODE (type1);
+	      converted = 1;
+	      break;
+	    }
+	  default:
+	    break;
+	}
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-12-03 18:00                     ` Joseph S. Myers
@ 2010-12-17 16:16                       ` Artem Shinkarov
  2011-01-21 15:24                         ` Richard Guenther
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2010-12-17 16:16 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3711 bytes --]

Thank you for pointing out an issue with the c_maybe_const. It is solved now.

2010-12-17  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

  /gcc
  * c-typeck.c (scalar_to_vector): New function. Try scalar to
vector conversion.
  (stv_conv): New enum for scalar_to_vector return type.
  (build_binary_op): Adjust.
  * doc/extend.texi: Description of scalar to vector expansion.

  /gcc/c-family
  * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to
  convert an expression to the type.
  (conversion_warning): Adjust, use unsafe_conversion_p.
  * c-common.h (unsafe_conversion_p): New function declaration.

  /gcc/testsuite
  * gcc.c-torture/execute/scal-to-vec1.c: New test.
  * gcc.c-torture/execute/scal-to-vec2.c: New test.
  * gcc.c-torture/execute/scal-to-vec3.c: New test.
  * gcc.dg/scal-to-vec1.c: New test.
  * gcc.dg/scal-to-vec2.c: New test.

bootstrapped and tested on x86_64_unknown-linux

If everyone is happy, may be then Richard could take care about the
submission to svn.



Thanks,
Artem.


On Fri, Dec 3, 2010 at 6:00 PM, Joseph S. Myers <joseph@codesourcery.com> wrote:
> On Mon, 22 Nov 2010, Artem Shinkarov wrote:
>
>> +          case stv_firstarg:
>> +            {
>> +              tree sc = save_expr (op0);
>> +              sc = convert (TREE_TYPE (type1), sc);
>> +              op0 = build_vector_from_val (type1, sc);
>> +              orig_type0 = type0 = TREE_TYPE (op0);
>> +              code0 = TREE_CODE (type0);
>> +              converted = 1;
>> +              break;
>> +            }
>> +          case stv_secondarg:
>> +            {
>> +              tree sc = save_expr (op1);
>> +              sc = convert (TREE_TYPE (type0), sc);
>> +              op1 = build_vector_from_val (type0, sc);
>> +              orig_type1 = type1 = TREE_TYPE (op1);
>> +              code1 = TREE_CODE (type1);
>> +              converted = 1;
>> +              break;
>> +            }
>
> (Watch your indentation; here and elsewhere in the patch you add new code
> indented by eight or more spaces when TABs should be used.  You also have
> a bogus patch hunk in conversion_warning that changes a TAB to spaces and
> does nothing else.)
>
> This code has the problem that it can call save_expr on something
> containing a C_MAYBE_CONST_EXPR without passing it through c_fully_fold
> first.  Simply using c_save_expr instead of save_expr isn't enough because
> that can result in a C_MAYBE_CONST_EXPR inside a vector.  Instead you want
> something like
>
> +         case stv_firstarg:
> +           {
> +             bool maybe_const = true;
> +             tree sc;
> +             sc = c_fully_fold (op0, false, &maybe_const);
> +             sc = save_expr (sc);
> +             sc = convert (TREE_TYPE (type1), sc);
> +             op0 = build_vector_from_val (type1, sc);
> +             if (!maybe_const)
> +               op0 = c_wrap_maybe_const (op0, true);
> +             orig_type0 = type0 = TREE_TYPE (op0);
> +             code0 = TREE_CODE (type0);
> +             converted = 1;
> +             break;
> +           }
>
> and similarly for the second case.  Testcase (that ICEs with your
> original patch):
>
> int f(void);
> unsigned int g(void);
> unsigned int h;
> typedef unsigned int vec __attribute__((vector_size(16)));
> vec i;
> vec fv1(void) { return i + (h ? f() : g()); }
> vec fv2(void) { return (h ? f() : g()) + i; }
>
> The patch is OK modified as indicated and with that testcase added to the
> testsuite (presuming it still passes bootstrap with no regressions).
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

[-- Attachment #2: scal-to-vec.c.v11.diff --]
[-- Type: text/x-diff, Size: 30622 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 167814)
+++ gcc/doc/extend.texi	(working copy)
@@ -6511,18 +6511,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 167814)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1864,143 +1864,92 @@ tree shorten_binary_op (tree result_type
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Checks if expression EXPR of real/integer type cannot be converted 
+   to the real/integer type TYPE. Function returns true when:
+	* EXPR is a constant which cannot be exactly converted to TYPE EXPR
+	* is not a constant and size of EXPR's type > than size of TYPE, 
+	  for EXPR type and TYPE being both integers or both real.
+	* EXPR is not a constant of real type and TYPE is an integer.  EXPR
+	* is not a constant of integer type which cannot be 
+	  exactly converted to real type.  
+   Function allows conversions between types of different signedness and
+   does not return true in that case.  Function can produce signedness
+   warnings if PRODUCE_WARNS is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
-    {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
-         to integer type.  */
+	 to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        {
-          if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
-            give_warning = true;
-        }
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	{
+	  if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
+	    give_warning = true;
+	}
       /* Warn for an integer constant that does not fit into integer type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE
-               && !int_fits_type_p (expr, type))
-        {
-          if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
+	       && TREE_CODE (type) == INTEGER_TYPE
+	       && !int_fits_type_p (expr, type))
+	{
+	  if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
-          else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "negative integer"
+			    " implicitly converted to unsigned type");
+	    }
+	  else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
+	    {
+	      if (produce_warns)
+		warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+	    }
 	  else
 	    give_warning = true;
-        }
+	}
       else if (TREE_CODE (type) == REAL_TYPE)
-        {
-          /* Warn for an integer constant that does not fit into real type.  */
-          if (TREE_CODE (expr_type) == INTEGER_TYPE)
-            {
-              REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-          /* Warn for a real constant that does not fit into a smaller
-             real type.  */
-          else if (TREE_CODE (expr_type) == REAL_TYPE
-                   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-            {
-              REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
-              if (!exact_real_truncate (TYPE_MODE (type), &a))
-                give_warning = true;
-            }
-        }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+	{
+	  /* Warn for an integer constant that does not fit into real type.  */
+	  if (TREE_CODE (expr_type) == INTEGER_TYPE)
+	    {
+	      REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	  /* Warn for a real constant that does not fit into a smaller
+	     real type.  */
+	  else if (TREE_CODE (expr_type) == REAL_TYPE
+		   && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	    {
+	      REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
+	      if (!exact_real_truncate (TYPE_MODE (type), &a))
+		give_warning = true;
+	    }
+	}
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
-          && TREE_CODE (type) == INTEGER_TYPE)
-        give_warning = true;
+	  && TREE_CODE (type) == INTEGER_TYPE)
+	give_warning = true;
 
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == INTEGER_TYPE)
-        {
+	       && TREE_CODE (type) == INTEGER_TYPE)
+	{
 	  /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2027,7 +1976,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2036,58 +1985,136 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
-          /* Warn for integer types converted to smaller integer types.  */
+	  /* Warn for integer types converted to smaller integer types.  */
 	  if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
 	    give_warning = true;
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
-        }
+	}
 
       /* Warn for integer types converted to real types if and only if
-         all the range of values of the integer type cannot be
-         represented by the real type.  */
+	 all the range of values of the integer type cannot be
+	 represented by the real type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
-               && TREE_CODE (type) == REAL_TYPE)
-        {
+	       && TREE_CODE (type) == REAL_TYPE)
+	{
 	  tree type_low_bound, type_high_bound;
-          REAL_VALUE_TYPE real_low_bound, real_high_bound;
+	  REAL_VALUE_TYPE real_low_bound, real_high_bound;
 
 	  /* Don't warn about char y = 0xff; float x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
 	  expr_type = TREE_TYPE (expr);
 
-          type_low_bound = TYPE_MIN_VALUE (expr_type);
-          type_high_bound = TYPE_MAX_VALUE (expr_type);
-          real_low_bound = real_value_from_int_cst (0, type_low_bound);
-          real_high_bound = real_value_from_int_cst (0, type_high_bound);
-
-          if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
-              || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
-            give_warning = true;
-        }
+	  type_low_bound = TYPE_MIN_VALUE (expr_type);
+	  type_high_bound = TYPE_MAX_VALUE (expr_type);
+	  real_low_bound = real_value_from_int_cst (0, type_low_bound);
+	  real_high_bound = real_value_from_int_cst (0, type_high_bound);
+
+	  if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
+	      || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
+	    give_warning = true;
+	}
 
       /* Warn for real types converted to smaller real types.  */
       else if (TREE_CODE (expr_type) == REAL_TYPE
-               && TREE_CODE (type) == REAL_TYPE
-               && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-        give_warning = true;
+	       && TREE_CODE (type) == REAL_TYPE
+	       && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
+	give_warning = true;
+    }
 
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
 
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
+
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
+
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
+
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
+
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
+	warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
     }
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 167814)
+++ gcc/c-family/c-common.h	(working copy)
@@ -708,6 +708,7 @@ extern tree c_common_unsigned_type (tree
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+extern long long sll;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "conversion of scalar to vector" } */
+    f1 = 1.3 + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = sll + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do compile } */   
+
+/* Test for C_MAYBE_CONST are folded correctly when 
+   expanding an expression to vector.  */
+
+int 			f(void);
+unsigned int 		g(void);
+unsigned int 		h;
+
+typedef unsigned int vec __attribute__((vector_size(16)));
+
+vec i;
+
+
+vec fv1(void) { return i + (h ? f() : g()); }
+vec fv2(void) { return (h ? f() : g()) + i; }
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 167814)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* The level of nesting inside "__alignof__".  */
 int in_alignof;
 
@@ -9313,6 +9321,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+	      || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    else
+	      return stv_firstarg;
+	  }
+	break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+	integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+	if (TREE_CODE (type0) == VECTOR_TYPE)
+	  {
+	    tree tmp;
+	    ret = stv_secondarg;
+	    /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+	    tmp = type0; type0 = type1; type1 = tmp;
+	    tmp = op0; op0 = op1; op1 = tmp;
+	  }
+
+	if (TREE_CODE (type0) == INTEGER_TYPE
+	    && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+	else if (!integer_only_op
+		    /* Allow integer --> real conversion if safe.  */
+		 && (TREE_CODE (type0) == REAL_TYPE 
+		     || TREE_CODE (type0) == INTEGER_TYPE)
+		 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+	  {
+	    if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+	      {
+		error_at (loc, "conversion of scalar to vector "
+			       "involves truncation");
+		return stv_error;
+	      }
+	    return ret;
+	  }
+      default:
+	break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9424,7 +9514,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+	   != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9496,6 +9589,49 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+      
+      switch (convert_flag)
+	{
+	  case stv_error:
+	    return error_mark_node;
+	  case stv_firstarg:
+	    {
+	      bool maybe_const = true;
+	      tree sc = c_save_expr (op0);
+	      sc = convert (TREE_TYPE (type1), sc);
+	      sc = c_fully_fold (sc, false, &maybe_const);
+	      op0 = build_vector_from_val (type1, sc);
+	      if (!maybe_const)
+		op0 = c_wrap_maybe_const (op0, true);
+	      orig_type0 = type0 = TREE_TYPE (op0);
+	      code0 = TREE_CODE (type0);
+	      converted = 1;
+	      break;
+	    }
+	  case stv_secondarg:
+	    {
+	      bool maybe_const = true;
+	      tree sc = c_save_expr (op1);
+	      sc = convert (TREE_TYPE (type0), sc);
+	      sc = c_fully_fold (sc, false, &maybe_const);
+	      op1 = build_vector_from_val (type0, sc);
+	      if (!maybe_const)
+		op1 = c_wrap_maybe_const (op1, true);
+	      orig_type1 = type1 = TREE_TYPE (op1);
+	      code1 = TREE_CODE (type1);
+	      converted = 1;
+	      break;
+	    }
+	  default:
+	    break;
+	}
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-22 16:26                   ` Artem Shinkarov
@ 2010-12-03 18:00                     ` Joseph S. Myers
  2010-12-17 16:16                       ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Joseph S. Myers @ 2010-12-03 18:00 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Richard Guenther, gcc-patches

On Mon, 22 Nov 2010, Artem Shinkarov wrote:

> +          case stv_firstarg:
> +            {
> +              tree sc = save_expr (op0);
> +              sc = convert (TREE_TYPE (type1), sc);
> +              op0 = build_vector_from_val (type1, sc);
> +              orig_type0 = type0 = TREE_TYPE (op0);
> +              code0 = TREE_CODE (type0);
> +              converted = 1;
> +              break;
> +            }
> +          case stv_secondarg:
> +            {
> +              tree sc = save_expr (op1);
> +              sc = convert (TREE_TYPE (type0), sc);
> +              op1 = build_vector_from_val (type0, sc);
> +              orig_type1 = type1 = TREE_TYPE (op1);
> +              code1 = TREE_CODE (type1);
> +              converted = 1;
> +              break;
> +            }

(Watch your indentation; here and elsewhere in the patch you add new code 
indented by eight or more spaces when TABs should be used.  You also have 
a bogus patch hunk in conversion_warning that changes a TAB to spaces and 
does nothing else.)

This code has the problem that it can call save_expr on something 
containing a C_MAYBE_CONST_EXPR without passing it through c_fully_fold 
first.  Simply using c_save_expr instead of save_expr isn't enough because 
that can result in a C_MAYBE_CONST_EXPR inside a vector.  Instead you want 
something like

+         case stv_firstarg:
+           {
+             bool maybe_const = true;
+             tree sc;
+             sc = c_fully_fold (op0, false, &maybe_const);
+             sc = save_expr (sc);
+             sc = convert (TREE_TYPE (type1), sc);
+             op0 = build_vector_from_val (type1, sc);
+             if (!maybe_const)
+               op0 = c_wrap_maybe_const (op0, true);
+             orig_type0 = type0 = TREE_TYPE (op0);
+             code0 = TREE_CODE (type0);
+             converted = 1;
+             break;
+           }

and similarly for the second case.  Testcase (that ICEs with your 
original patch):

int f(void);
unsigned int g(void);
unsigned int h;
typedef unsigned int vec __attribute__((vector_size(16)));
vec i;
vec fv1(void) { return i + (h ? f() : g()); }
vec fv2(void) { return (h ? f() : g()) + i; }

The patch is OK modified as indicated and with that testcase added to the 
testsuite (presuming it still passes bootstrap with no regressions).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-19 22:44                 ` Joseph S. Myers
@ 2010-11-22 16:26                   ` Artem Shinkarov
  2010-12-03 18:00                     ` Joseph S. Myers
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-22 16:26 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 627 bytes --]

On Fri, Nov 19, 2010 at 9:59 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Thu, 18 Nov 2010, Artem Shinkarov wrote:
>
>> Fixed. New function description is written, test is covering the case
>> with integer to float conversion.
>
> I do not see a testcase here that covers the case of converting an integer
> constant, not exactly representable in float, to a float vector.

Ok, there were no constant-check because the example with "extern long
long sll" uses the same mechanism of checking. It checks not the value
itself but the type boundaries.

Now there is an example with integer constant as well.



Artem.

[-- Attachment #2: scal-to-vec.c.v10.diff --]
[-- Type: text/x-diff, Size: 26271 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166433)
+++ gcc/doc/extend.texi	(working copy)
@@ -6333,18 +6333,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 166433)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1852,56 +1852,26 @@ tree shorten_binary_op (tree result_type
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Checks if expression EXPR of real/integer type cannot be converted 
+   to the real/integer type TYPE. Function returns true when:
+        * EXPR is a constant which cannot be exactly converted to TYPE EXPR
+        * is not a constant and size of EXPR's type > than size of TYPE, 
+          for EXPR type and TYPE being both integers or both real.
+        * EXPR is not a constant of real type and TYPE is an integer.  EXPR
+        * is not a constant of integer type which cannot be 
+          exactly converted to real type.  
+   Function allows conversions between types of different signedness and
+   does not return true in that case.  Function can produce signedness
+   warnings if PRODUCE_WARNS is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
-    {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
          to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
@@ -1917,11 +1887,17 @@ conversion_warning (tree type, tree expr
         {
           if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
+            {
+              if (produce_warns)
+	        warning_at (loc, OPT_Wsign_conversion, "negative integer"
+		            " implicitly converted to unsigned type");
+            }
           else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+            {
+              if (produce_warns)
+	        warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+            }
 	  else
 	    give_warning = true;
         }
@@ -1944,36 +1920,9 @@ conversion_warning (tree type, tree expr
                 give_warning = true;
             }
         }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
           && TREE_CODE (type) == INTEGER_TYPE)
@@ -1988,7 +1937,7 @@ conversion_warning (tree type, tree expr
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2015,7 +1964,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2024,7 +1973,7 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
           /* Warn for integer types converted to smaller integer types.  */
@@ -2033,12 +1982,13 @@ conversion_warning (tree type, tree expr
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+                   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
@@ -2072,9 +2022,86 @@ conversion_warning (tree type, tree expr
                && TREE_CODE (type) == REAL_TYPE
                && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
         give_warning = true;
+    }
+
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
+
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
 
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+        warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
 
-      if (give_warning)
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
+
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
+
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
         warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 166433)
+++ gcc/c-family/c-common.h	(working copy)
@@ -706,6 +706,7 @@ extern tree c_common_unsigned_type (tree
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+extern long long sll;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "conversion of scalar to vector" } */
+    f1 = 1.3 + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = sll + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 166433)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* Whether we are building a boolean conversion inside
    convert_for_assignment, or some other late binary operation.  If
    build_binary_op is called (from code shared with C++) in this case,
@@ -9387,6 +9395,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+              || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            else
+              return stv_firstarg;
+          }
+        break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+        integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (TREE_CODE (type0) == VECTOR_TYPE)
+          {
+            tree tmp;
+            ret = stv_secondarg;
+            /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+            tmp = type0; type0 = type1; type1 = tmp;
+            tmp = op0; op0 = op1; op1 = tmp;
+          }
+
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            return ret;
+          }
+        else if (!integer_only_op
+                    /* Allow integer --> real conversion if safe.  */
+                 && (TREE_CODE (type0) == REAL_TYPE 
+                     || TREE_CODE (type0) == INTEGER_TYPE)
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            return ret;
+          }
+      default:
+        break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9498,7 +9588,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+           != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9570,6 +9663,41 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+      
+      switch (convert_flag)
+        {
+          case stv_error:
+            return error_mark_node;
+          case stv_firstarg:
+            {
+              tree sc = save_expr (op0);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+            }
+          case stv_secondarg:
+            {
+              tree sc = save_expr (op1);
+              sc = convert (TREE_TYPE (type0), sc);
+              op1 = build_vector_from_val (type0, sc);
+              orig_type1 = type1 = TREE_TYPE (op1);
+              code1 = TREE_CODE (type1);
+              converted = 1;
+              break;
+            }
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-18 14:01               ` Artem Shinkarov
@ 2010-11-19 22:44                 ` Joseph S. Myers
  2010-11-22 16:26                   ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Joseph S. Myers @ 2010-11-19 22:44 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Richard Guenther, gcc-patches

On Thu, 18 Nov 2010, Artem Shinkarov wrote:

> Fixed. New function description is written, test is covering the case
> with integer to float conversion.

I do not see a testcase here that covers the case of converting an integer 
constant, not exactly representable in float, to a float vector.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-16 17:10             ` Joseph S. Myers
@ 2010-11-18 14:01               ` Artem Shinkarov
  2010-11-19 22:44                 ` Joseph S. Myers
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-18 14:01 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3836 bytes --]

Fixed. New function description is written, test is covering the case
with integer to float conversion.

2010-11-18  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

   /gcc
   * c-typeck.c (scalar_to_vector): New function. Try scalar to
vector conversion.
   (stv_conv): New enum for scalar_to_vector return type.
   (build_binary_op): Adjust.
   * doc/extend.texi: Description of scalar to vector expansion.

   /gcc/c-family
   * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to
   convert an expression to the type.
   (conversion_warning): Adjust, use unsafe_conversion_p.
   * c-common.h (unsafe_conversion_p): New function declaration.

   /gcc/testsuite
   * gcc.c-torture/execute/scal-to-vec1.c: New test.
   * gcc.c-torture/execute/scal-to-vec2.c: New test.
   * gcc.c-torture/execute/scal-to-vec3.c: New test.
   * gcc.dg/scal-to-vec1.c: New test.

bootstrapped and tested on x86_64_unknown-linux



On Tue, Nov 16, 2010 at 4:39 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Mon, 15 Nov 2010, Artem Shinkarov wrote:
>
>> -/* Warns if the conversion of EXPR to TYPE may alter a value.
>> -   This is a helper function for warnings_for_convert_and_check.  */
>> -
>> -static void
>> -conversion_warning (tree type, tree expr)
>> +/* Return true if expression EXPR cannot be converted to the type TYPE
>> +   preserving its value. Funtion will produce warnings if PRODUCE_WARNS
>
> "Function"
>
>> +   is true.  */
>> +bool
>> +unsafe_conversion_p (tree type, tree expr, bool produce_warns)
>
> Are you sure the comment accurately describes the semantics?  The
> impression I get is that the new function is deliberately more restricted
> in the expressions it takes and the intelligence it applies to them than
> the old one - so the comment should say so (the point of the function
> being to give warnings according to some well-defined semantics and *not*
> to be smart in ways that may change unpredictably; the comment should make
> the semantics clear) - and that some cases may not return true even when
> you give a warning if produce_warns.
>
>> @@ -1917,11 +1879,17 @@ conversion_warning (tree type, tree expr
>>          {
>>            if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
>>             && tree_int_cst_sgn (expr) < 0)
>> -         warning_at (loc, OPT_Wsign_conversion, "negative integer"
>> -                     " implicitly converted to unsigned type");
>> +            {
>> +              if (produce_warns)
>> +             warning_at (loc, OPT_Wsign_conversion, "negative integer"
>> +                         " implicitly converted to unsigned type");
>
> Here for example.  If this returns true, what logic causes it to do so?
> If not, why not?  (This sort of thing should best be made clear by
> comments in the code.)
>
>> +        else if (!integer_only_op
>> +                    /* Allow integer --> real conversion if safe.  */
>> +                 && (TREE_CODE (type0) == REAL_TYPE
>> +                     || TREE_CODE (type0) == INTEGER_TYPE)
>> +                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
>> +          {
>> +            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
>> +              {
>> +                error_at (loc, "truncating floating point constant to "
>> +                               "vector precision does not preserve value");
>
> "floating-point" when used as an adjective.
>
> If you have an int constant that cannot be exactly converted to float,
> what error do you get for converting it to a float vector?  This one
> (which would be inappropriate since it's not a floating-point constant),
> or another one?  And is there a testcase for this?
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

[-- Attachment #2: scal-to-vec.c.v9.diff --]
[-- Type: text/x-diff, Size: 26188 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166433)
+++ gcc/doc/extend.texi	(working copy)
@@ -6333,18 +6333,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 166433)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1852,56 +1852,26 @@ tree shorten_binary_op (tree result_type
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Checks if expression EXPR of real/integer type cannot be converted 
+   to the real/integer type TYPE. Function returns true when:
+        * EXPR is a constant which cannot be exactly converted to TYPE EXPR
+        * is not a constant and size of EXPR's type > than size of TYPE, 
+          for EXPR type and TYPE being both integers or both real.
+        * EXPR is not a constant of real type and TYPE is an integer.  EXPR
+        * is not a constant of integer type which cannot be 
+          exactly converted to real type.  
+   Function allows conversions between types of different signedness and
+   does not return true in that case.  Function can produce signedness
+   warnings if PRODUCE_WARNS is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
-    {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
          to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
@@ -1917,11 +1887,17 @@ conversion_warning (tree type, tree expr
         {
           if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
+            {
+              if (produce_warns)
+	        warning_at (loc, OPT_Wsign_conversion, "negative integer"
+		            " implicitly converted to unsigned type");
+            }
           else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+            {
+              if (produce_warns)
+	        warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+            }
 	  else
 	    give_warning = true;
         }
@@ -1944,36 +1920,9 @@ conversion_warning (tree type, tree expr
                 give_warning = true;
             }
         }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
           && TREE_CODE (type) == INTEGER_TYPE)
@@ -1988,7 +1937,7 @@ conversion_warning (tree type, tree expr
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2015,7 +1964,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2024,7 +1973,7 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
           /* Warn for integer types converted to smaller integer types.  */
@@ -2033,12 +1982,13 @@ conversion_warning (tree type, tree expr
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+                   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
@@ -2072,9 +2022,86 @@ conversion_warning (tree type, tree expr
                && TREE_CODE (type) == REAL_TYPE
                && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
         give_warning = true;
+    }
+
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
+
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
 
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+        warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
 
-      if (give_warning)
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
+
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
+
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
         warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 166433)
+++ gcc/c-family/c-common.h	(working copy)
@@ -706,6 +706,7 @@ extern tree c_common_unsigned_type (tree
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+extern long long sll;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "conversion of scalar to vector" } */
+    f1 = 1.3 + f0;      /* { dg-error "conversion of scalar to vector" } */
+    f1 = sll + f0;      /* { dg-error "conversion of scalar to vector" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 166433)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* Whether we are building a boolean conversion inside
    convert_for_assignment, or some other late binary operation.  If
    build_binary_op is called (from code shared with C++) in this case,
@@ -9387,6 +9395,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+              || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            else
+              return stv_firstarg;
+          }
+        break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+        integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (TREE_CODE (type0) == VECTOR_TYPE)
+          {
+            tree tmp;
+            ret = stv_secondarg;
+            /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+            tmp = type0; type0 = type1; type1 = tmp;
+            tmp = op0; op0 = op1; op1 = tmp;
+          }
+
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            return ret;
+          }
+        else if (!integer_only_op
+                    /* Allow integer --> real conversion if safe.  */
+                 && (TREE_CODE (type0) == REAL_TYPE 
+                     || TREE_CODE (type0) == INTEGER_TYPE)
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            return ret;
+          }
+      default:
+        break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9498,7 +9588,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+           != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9570,6 +9663,41 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+      
+      switch (convert_flag)
+        {
+          case stv_error:
+            return error_mark_node;
+          case stv_firstarg:
+            {
+              tree sc = save_expr (op0);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+            }
+          case stv_secondarg:
+            {
+              tree sc = save_expr (op1);
+              sc = convert (TREE_TYPE (type0), sc);
+              op1 = build_vector_from_val (type0, sc);
+              orig_type1 = type1 = TREE_TYPE (op1);
+              code1 = TREE_CODE (type1);
+              converted = 1;
+              break;
+            }
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-15 18:00           ` Artem Shinkarov
@ 2010-11-16 17:10             ` Joseph S. Myers
  2010-11-18 14:01               ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Joseph S. Myers @ 2010-11-16 17:10 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Richard Guenther, gcc-patches

On Mon, 15 Nov 2010, Artem Shinkarov wrote:

> -/* Warns if the conversion of EXPR to TYPE may alter a value.
> -   This is a helper function for warnings_for_convert_and_check.  */
> -
> -static void
> -conversion_warning (tree type, tree expr)
> +/* Return true if expression EXPR cannot be converted to the type TYPE
> +   preserving its value. Funtion will produce warnings if PRODUCE_WARNS

"Function"

> +   is true.  */
> +bool
> +unsafe_conversion_p (tree type, tree expr, bool produce_warns)

Are you sure the comment accurately describes the semantics?  The 
impression I get is that the new function is deliberately more restricted 
in the expressions it takes and the intelligence it applies to them than 
the old one - so the comment should say so (the point of the function 
being to give warnings according to some well-defined semantics and *not* 
to be smart in ways that may change unpredictably; the comment should make 
the semantics clear) - and that some cases may not return true even when 
you give a warning if produce_warns.

> @@ -1917,11 +1879,17 @@ conversion_warning (tree type, tree expr
>          {
>            if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
>  	      && tree_int_cst_sgn (expr) < 0)
> -	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
> -			" implicitly converted to unsigned type");
> +            {
> +              if (produce_warns)
> +	        warning_at (loc, OPT_Wsign_conversion, "negative integer"
> +		            " implicitly converted to unsigned type");

Here for example.  If this returns true, what logic causes it to do so?  
If not, why not?  (This sort of thing should best be made clear by 
comments in the code.)

> +        else if (!integer_only_op
> +                    /* Allow integer --> real conversion if safe.  */
> +                 && (TREE_CODE (type0) == REAL_TYPE 
> +                     || TREE_CODE (type0) == INTEGER_TYPE)
> +                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
> +          {
> +            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
> +              {
> +                error_at (loc, "truncating floating point constant to "
> +                               "vector precision does not preserve value");

"floating-point" when used as an adjective.

If you have an int constant that cannot be exactly converted to float, 
what error do you get for converting it to a float vector?  This one 
(which would be inappropriate since it's not a floating-point constant), 
or another one?  And is there a testcase for this?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-12 21:39         ` Joseph S. Myers
@ 2010-11-15 18:00           ` Artem Shinkarov
  2010-11-16 17:10             ` Joseph S. Myers
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-15 18:00 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2973 bytes --]

Fine, now the logic that is used in c-common:conversion_warning is
separated into the function and is used in both places.

We allow conversions from int to real, if value is preserved, so it
means that an expression "v4f = 5 + v4f" is valid.
We disallow conversion from real to int, it means that an expression
"v4i = 2. + v4i" is invalid.

2010-11-15  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

    /gcc
    * c-typeck.c (scalar_to_vector): New function. Try scalar to
vector conversion.
    (stv_conv): New enum for scalar_to_vector return type.
    (build_binary_op): Adjust.
    * doc/extend.texi: Description of scalar to vector expansion.

    /gcc/c-family
    * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to
    convert an expression to the type.
    (conversion_warning): Adjust, use unsafe_conversion_p.
    * c-common.h (unsafe_conversion_p): New function declaration.

    /gcc/testsuite
    * gcc.c-torture/execute/scal-to-vec1.c: New test.
    * gcc.c-torture/execute/scal-to-vec2.c: New test.
    * gcc.c-torture/execute/scal-to-vec3.c: New test.
    * gcc.dg/scal-to-vec1.c: New test.

bootstrapped and tested on x86_64_unknown-linux

OK?

On Fri, Nov 12, 2010 at 9:22 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Mon, 8 Nov 2010, Artem Shinkarov wrote:
>
>> +/* Possibe cases of scalar_to_vector conversion.  */
>> +enum stv_conv {
>> +  stv_error,
>> +  stv_nothing,
>> +  stv_firstarg,
>> +  stv_secondarg
>> +};
>
> The description of the semantics of the individual enum values should go
> here, not on the function scalar_to_vector.
>
>> @@ -2156,7 +2164,7 @@ build_component_ref (location_t loc, tre
>>        /* Chain the COMPONENT_REFs if necessary down to the FIELD.
>>        This might be better solved in future the way the C++ front
>>        end does it - by giving the anonymous entities each a
>> -      separate name and type, and then have build_component_ref
>> +      /edseparate name and type, and then have build_component_ref
>>        recursively call itself.  We can't do that here.  */
>>        do
>>       {
>
> This change seems bogus.
>
>> +/* Return true if expression EXPR can be converted to the
>> +   vector type TYPE preserving its value.  */
>
> I don't see anything here that checks whether integers can safely be
> converted to floating-point types (thus, any short value can be converted
> to float, but some int values cannot, for example).
>
> Such logic exists in c-common.c:conversion_warning.  It would be good to
> share as much code as possible with that function.
>
>> +  else if (TREE_CODE (expr) == REAL_CST)
>> +    {
>> +      REAL_VALUE_TYPE c, c1;
>> +      c = TREE_REAL_CST (expr);
>> +      real_convert (&c1, mode, &c);
>> +      return real_identical (&c, &c1);
>
> conversion_warning uses exact_real_truncate....
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

[-- Attachment #2: scal-to-vec.c.v8.diff --]
[-- Type: text/x-diff, Size: 25501 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166433)
+++ gcc/doc/extend.texi	(working copy)
@@ -6333,18 +6333,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 166433)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1852,56 +1852,18 @@ tree shorten_binary_op (tree result_type
   return result_type;
 }
 
-/* Warns if the conversion of EXPR to TYPE may alter a value.
-   This is a helper function for warnings_for_convert_and_check.  */
-
-static void
-conversion_warning (tree type, tree expr)
+/* Return true if expression EXPR cannot be converted to the type TYPE
+   preserving its value. Funtion will produce warnings if PRODUCE_WARNS
+   is true.  */
+bool
+unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
   bool give_warning = false;
-
-  int i;
-  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
-  if (!warn_conversion && !warn_sign_conversion)
-    return;
-
-  /* If any operand is artificial, then this expression was generated
-     by the compiler and we do not warn.  */
-  for (i = 0; i < expr_num_operands; i++)
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
-      tree op = TREE_OPERAND (expr, i);
-      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
-	return;
-    }
-
-  switch (TREE_CODE (expr))
-    {
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_NOT_EXPR:
-      /* Conversion from boolean to a signed:1 bit-field (which only
-	 can hold the values 0 and -1) doesn't lose information - but
-	 it does change the value.  */
-      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
-	warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT from boolean expression", type);
-      return;
-
-    case REAL_CST:
-    case INTEGER_CST:
-
       /* Warn for real constant that is not an exact integer converted
          to integer type.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
@@ -1917,11 +1879,17 @@ conversion_warning (tree type, tree expr
         {
           if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
 	      && tree_int_cst_sgn (expr) < 0)
-	    warning_at (loc, OPT_Wsign_conversion, "negative integer"
-			" implicitly converted to unsigned type");
+            {
+              if (produce_warns)
+	        warning_at (loc, OPT_Wsign_conversion, "negative integer"
+		            " implicitly converted to unsigned type");
+            }
           else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type))
-	    warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
-			" constant value to negative integer");
+            {
+              if (produce_warns)
+	        warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned"
+			    " constant value to negative integer");
+            }
 	  else
 	    give_warning = true;
         }
@@ -1944,36 +1912,9 @@ conversion_warning (tree type, tree expr
                 give_warning = true;
             }
         }
-
-      if (give_warning)
-        warning_at (loc, OPT_Wconversion,
-		    "conversion to %qT alters %qT constant value",
-		    type, expr_type);
-
-      return;
-
-    case COND_EXPR:
-      {
-	/* In case of COND_EXPR, if both operands are constants or
-	   COND_EXPR, then we do not care about the type of COND_EXPR,
-	   only about the conversion of each operand.  */
-	tree op1 = TREE_OPERAND (expr, 1);
-	tree op2 = TREE_OPERAND (expr, 2);
-
-	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
-	     || TREE_CODE (op1) == COND_EXPR)
-	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
-		|| TREE_CODE (op2) == COND_EXPR))
-	  {
-	    conversion_warning (type, op1);
-	    conversion_warning (type, op2);
-	    return;
-	  }
-	/* Fall through.  */
-      }
-
-    default: /* 'expr' is not a constant.  */
-
+    }
+  else
+    {
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
           && TREE_CODE (type) == INTEGER_TYPE)
@@ -1988,7 +1929,7 @@ conversion_warning (tree type, tree expr
 
 	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
 	  if (TREE_CODE (expr) == BIT_AND_EXPR
-		|| TREE_CODE (expr) == BIT_IOR_EXPR
+	      || TREE_CODE (expr) == BIT_IOR_EXPR
 	      || TREE_CODE (expr) == BIT_XOR_EXPR)
 	    {
 	      /* If both args were extended from a shortest type,
@@ -2015,7 +1956,7 @@ conversion_warning (tree type, tree expr
 			  && int_fits_type_p (op1, c_common_signed_type (type))
 			  && int_fits_type_p (op1,
 					      c_common_unsigned_type (type))))
-		    return;
+		    return false;
 		  /* If constant is unsigned and fits in the target
 		     type, then the result will also fit.  */
 		  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2024,7 +1965,7 @@ conversion_warning (tree type, tree expr
 			   || (TREE_CODE (op1) == INTEGER_CST
 			       && unsigned1
 			       && int_fits_type_p (op1, type)))
-		    return;
+		    return false;
 		}
 	    }
           /* Warn for integer types converted to smaller integer types.  */
@@ -2033,12 +1974,13 @@ conversion_warning (tree type, tree expr
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
+	  else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type)
 		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+		    || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
+                   && produce_warns)
 	    warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
 			"may change the sign of the result",
 			type, expr_type);
@@ -2072,9 +2014,86 @@ conversion_warning (tree type, tree expr
                && TREE_CODE (type) == REAL_TYPE
                && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
         give_warning = true;
+    }
+
+  return give_warning;
+}
+
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This is a helper function for warnings_for_convert_and_check.  */
+
+static void
+conversion_warning (tree type, tree expr)
+{
+  int i;
+  const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
+  tree expr_type = TREE_TYPE (expr);
+  location_t loc = EXPR_LOC_OR_HERE (expr);
+
+  if (!warn_conversion && !warn_sign_conversion)
+    return;
+
+  /* If any operand is artificial, then this expression was generated
+     by the compiler and we do not warn.  */
+  for (i = 0; i < expr_num_operands; i++)
+    {
+      tree op = TREE_OPERAND (expr, i);
+      if (op && DECL_P (op) && DECL_ARTIFICIAL (op))
+	return;
+    }
+
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      /* Conversion from boolean to a signed:1 bit-field (which only
+	 can hold the values 0 and -1) doesn't lose information - but
+	 it does change the value.  */
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT from boolean expression", type);
+      return;
 
+    case REAL_CST:
+    case INTEGER_CST:
+      if (unsafe_conversion_p (type, expr, true))
+        warning_at (loc, OPT_Wconversion,
+		    "conversion to %qT alters %qT constant value",
+		    type, expr_type);
+      return;
 
-      if (give_warning)
+    case COND_EXPR:
+      {
+	/* In case of COND_EXPR, if both operands are constants or
+	   COND_EXPR, then we do not care about the type of COND_EXPR,
+	   only about the conversion of each operand.  */
+	tree op1 = TREE_OPERAND (expr, 1);
+	tree op2 = TREE_OPERAND (expr, 2);
+
+	if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST
+	     || TREE_CODE (op1) == COND_EXPR)
+	    && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST
+		|| TREE_CODE (op2) == COND_EXPR))
+	  {
+	    conversion_warning (type, op1);
+	    conversion_warning (type, op2);
+	    return;
+	  }
+	/* Fall through.  */
+      }
+
+    default: /* 'expr' is not a constant.  */
+      if (unsafe_conversion_p (type, expr, true))
         warning_at (loc, OPT_Wconversion,
 		    "conversion to %qT from %qT may alter its value",
 		    type, expr_type);
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 166433)
+++ gcc/c-family/c-common.h	(working copy)
@@ -706,6 +706,7 @@ extern tree c_common_unsigned_type (tree
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
+extern bool unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c	(revision 0)
@@ -0,0 +1,48 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+    f1 = 2 + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2 - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2 * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2 / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2 + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2 - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2 * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2 / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "truncating floating point" } */
+    f1 = 1.3 + f0;      /* { dg-error "truncating floating point" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 166433)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,        /* Error occured.  */
+  stv_nothing,      /* Nothing happened.  */
+  stv_firstarg,     /* First argument must be expanded.  */
+  stv_secondarg     /* Second argument must be expanded.  */
+};
+
 /* Whether we are building a boolean conversion inside
    convert_for_assignment, or some other late binary operation.  If
    build_binary_op is called (from code shared with C++) in this case,
@@ -9387,6 +9395,88 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Convert scalar to vector for the range of operations.  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  gcc_assert (TREE_CODE (type0) == VECTOR_TYPE 
+              || TREE_CODE (type1) == VECTOR_TYPE);
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            else
+              return stv_firstarg;
+          }
+        break;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+        integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (TREE_CODE (type0) == VECTOR_TYPE)
+          {
+            tree tmp;
+            ret = stv_secondarg;
+            /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+            tmp = type0; type0 = type1; type1 = tmp;
+            tmp = op0; op0 = op1; op1 = tmp;
+          }
+
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            return ret;
+          }
+        else if (!integer_only_op
+                    /* Allow integer --> real conversion if safe.  */
+                 && (TREE_CODE (type0) == REAL_TYPE 
+                     || TREE_CODE (type0) == INTEGER_TYPE)
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (unsafe_conversion_p (TREE_TYPE (type1), op0, false))
+              {
+                error_at (loc, "truncating floating point constant to "
+                               "vector precision does not preserve value");
+                return stv_error;
+              }
+            return ret;
+          }
+      default:
+        break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9498,7 +9588,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+           != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9570,6 +9663,41 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+      
+      switch (convert_flag)
+        {
+          case stv_error:
+            return error_mark_node;
+          case stv_firstarg:
+            {
+              tree sc = save_expr (op0);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+            }
+          case stv_secondarg:
+            {
+              tree sc = save_expr (op1);
+              sc = convert (TREE_TYPE (type0), sc);
+              op1 = build_vector_from_val (type0, sc);
+              orig_type1 = type1 = TREE_TYPE (op1);
+              code1 = TREE_CODE (type1);
+              converted = 1;
+              break;
+            }
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-08 17:49       ` Artem Shinkarov
@ 2010-11-12 21:39         ` Joseph S. Myers
  2010-11-15 18:00           ` Artem Shinkarov
  0 siblings, 1 reply; 28+ messages in thread
From: Joseph S. Myers @ 2010-11-12 21:39 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Richard Guenther, gcc-patches

On Mon, 8 Nov 2010, Artem Shinkarov wrote:

> +/* Possibe cases of scalar_to_vector conversion.  */
> +enum stv_conv {
> +  stv_error,
> +  stv_nothing,
> +  stv_firstarg,
> +  stv_secondarg
> +};

The description of the semantics of the individual enum values should go 
here, not on the function scalar_to_vector.

> @@ -2156,7 +2164,7 @@ build_component_ref (location_t loc, tre
>        /* Chain the COMPONENT_REFs if necessary down to the FIELD.
>  	 This might be better solved in future the way the C++ front
>  	 end does it - by giving the anonymous entities each a
> -	 separate name and type, and then have build_component_ref
> +	 /edseparate name and type, and then have build_component_ref
>  	 recursively call itself.  We can't do that here.  */
>        do
>  	{

This change seems bogus.

> +/* Return true if expression EXPR can be converted to the
> +   vector type TYPE preserving its value.  */

I don't see anything here that checks whether integers can safely be 
converted to floating-point types (thus, any short value can be converted 
to float, but some int values cannot, for example).

Such logic exists in c-common.c:conversion_warning.  It would be good to 
share as much code as possible with that function.

> +  else if (TREE_CODE (expr) == REAL_CST)
> +    {
> +      REAL_VALUE_TYPE c, c1;
> +      c = TREE_REAL_CST (expr);
> +      real_convert (&c1, mode, &c);
> +      return real_identical (&c, &c1);

conversion_warning uses exact_real_truncate....

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-06 18:07     ` Joseph S. Myers
@ 2010-11-08 17:49       ` Artem Shinkarov
  2010-11-12 21:39         ` Joseph S. Myers
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-08 17:49 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3142 bytes --]

Thanks for the comments.

default_conversion is switched off for the vector/scalar case.
bitwise operations are added.
new testcase is created.

2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

     /gcc
     * c-typeck.c (expr_fits_type_p): New function. Check if expression
     fits into the type considering constants.
     (scalar_to_vector): New function. Try scalar to vector conversion.
     (build_binary_op): Adjust.
     * doc/extend.texi: Description of scalar to vector expansion.

     /gcc/testsuite
     * gcc.c-torture/execute/scal-to-vec1.c: New test.
     * gcc.c-torture/execute/scal-to-vec2.c: New test.
     * gcc.dg/scal-to-vec1.c: New test.

bootstrapped and tested on x86_64_unknown-linux

OK?

On Sat, Nov 6, 2010 at 5:44 PM, Joseph S. Myers <joseph@codesourcery.com> wrote:
> On Wed, 3 Nov 2010, Artem Shinkarov wrote:
>
>> @@ -9387,6 +9387,104 @@ push_cleanup (tree decl, tree cleanup, b
>>    TREE_OPERAND (stmt, 0) = list;
>>    STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
>>  }
>> +
>> +/* Return true if expression EXPR can be converted to the
>> +   vectortype TYPE preserving its value.  */
>
> "vector type" (two words)
>
>> +static bool
>> +expr_fits_type_p (tree expr, tree type)
>> +{
>
> I don't see anything here to handle removing widening conversions from
> expr.  Say you have a variable of type short - do you expect to be able to
> do a binary operation between that variable and a vector of shorts?
> Because the variable will have been converted to int.  I don't see any
> testcases in this area either.
>
> If you do want to allow that, rather than making this function smarter and
> so making the language definition depend on how smart the compiler is
> about seeing what conversions are safe I think it might be better to avoid
> having build_binary_op calling default_conversion on the scalar operand in
> a mixed vector/scalar operation.
>
>> +/* Convert scalar to vector for the range of operations.
>> +   Function can return:
>> +        -2  --  Error ocured
>
> "occurred"
>
>> +        -1  --  Nothing happened
>> +         0  --  First argument must be expanded
>> +         1  --  Second argument must be expanded  */
>
> Please define an enum giving symbolic names to the possible return values,
> rather than using magic constants.  */
>
>> +              error_at (loc, "Conversion of scalar to vector "
>> +                             "involves truncation");
>
> Diagnostics should not start with capital letters.  Likewise for all the
> other diagnostics in this function.
>
> The patch does not seem to include any testcases for bitwise operations
> (&^|).  If they are meant to work with mixed scalar/vector operations
> (which would be my expectation), then testcases are needed unless already
> in the testsuite; if not, testcases are still needed and the documentation
> needs to make clear they are not allowed.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>



-- 
Artem Shinkarov
Compiler Technology and Computer Architecture Group
University of Hertfordshire

[-- Attachment #2: scal-to-vec.c.v7.diff --]
[-- Type: text/x-diff, Size: 15128 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166433)
+++ gcc/doc/extend.texi	(working copy)
@@ -6333,18 +6333,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + @{1,1,1,1@}; */
+a = 2 * b;    /* a = @{2,2,2,2@} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,85 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 ^ v0;   check (short, 8, v0, v1, 2, ^, l);
+    v1 = 2 & v0;   check (short, 8, v0, v1, 2, &, l);
+    v1 = 2 | v0;   check (short, 8, v0, v1, 2, |, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+    v1 = v0 ^ 2;   check (short, 8, v0, v1, 2, ^, r);
+    v1 = v0 & 2;   check (short, 8, v0, v1, 2, &, r);
+    v1 = v0 | 2;   check (short, 8, v0, v1, 2, |, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c	(revision 0)
@@ -0,0 +1,62 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) (a op b)
+#define operr(a, b, op) (b op a)
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+long __attribute__ ((noinline)) vlng () {   return (long)42; }
+int  __attribute__ ((noinline)) vint () {   return (int) 43; }
+short __attribute__ ((noinline)) vsrt () {   return (short)42; }
+char __attribute__ ((noinline)) vchr () {    return (char)42; }
+
+
+int main (int argc, char *argv[]) {
+    vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7};
+    vector(16, char) c1;
+    
+    vector(8, short) s0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) s1;
+
+    vector(4, int) i0 = {argc, 1, 2, 3};
+    vector(4, int) i1;
+
+    vector(2, long) l0 = {argc, 1};
+    vector(2, long) l1;
+
+    c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l);
+    
+    s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l);
+    s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l);
+
+    i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l);
+    i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l);
+    i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l);
+
+    l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l);
+    l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l);
+    l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l);
+    l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "truncating floating point" } */
+    f1 = 1.3 + f0;      /* { dg-error "truncating floating point" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+    f1 = sint + f0;     /* { dg-error "can't convert between vector values of different size" } */
+
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 166433)
+++ gcc/c-typeck.c	(working copy)
@@ -51,6 +51,14 @@ enum impl_conv {
   ic_return
 };
 
+/* Possibe cases of scalar_to_vector conversion.  */
+enum stv_conv {
+  stv_error,
+  stv_nothing,
+  stv_firstarg,
+  stv_secondarg
+};
+
 /* Whether we are building a boolean conversion inside
    convert_for_assignment, or some other late binary operation.  If
    build_binary_op is called (from code shared with C++) in this case,
@@ -2156,7 +2164,7 @@ build_component_ref (location_t loc, tre
       /* Chain the COMPONENT_REFs if necessary down to the FIELD.
 	 This might be better solved in future the way the C++ front
 	 end does it - by giving the anonymous entities each a
-	 separate name and type, and then have build_component_ref
+	 /edseparate name and type, and then have build_component_ref
 	 recursively call itself.  We can't do that here.  */
       do
 	{
@@ -9387,6 +9395,112 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Return true if expression EXPR can be converted to the
+   vector type TYPE preserving its value.  */
+static bool
+expr_fits_type_p (tree expr, tree type)
+{
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (type));
+  if (TYPE_MODE (TREE_TYPE (expr)) == mode)
+    return true;
+
+  if (TREE_CODE (expr) == INTEGER_CST)
+    return int_fits_type_p (expr, TREE_TYPE (type));
+  else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+    return !tree_int_cst_lt 
+                (TYPE_SIZE (TREE_TYPE (type)),
+                 TYPE_SIZE (TREE_TYPE (expr)));
+  else if (TREE_CODE (expr) == REAL_CST)
+    {
+      REAL_VALUE_TYPE c, c1;
+      c = TREE_REAL_CST (expr);
+      real_convert (&c1, mode, &c);
+      return real_identical (&c, &c1);
+    }
+  else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+    return (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) 
+            <= GET_MODE_SIZE (mode));
+  return false;
+}
+
+/* Convert scalar to vector for the range of operations.  
+   Function can return:
+        stv_error      --  Error occured
+        stv_nothing    --  Nothing happened
+        stv_firstarg   --  First argument must be expanded
+        stv_secondarg  --  Second argument must be expanded  */
+static enum stv_conv
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool integer_only_op = false;
+  enum stv_conv ret = stv_firstarg;
+  
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (type0) == INTEGER_TYPE)
+          if (!expr_fits_type_p (op0, type1))
+            {
+              error_at (loc, "conversion of scalar to vector "
+                             "involves truncation");
+              return stv_error;
+            }
+          return stv_firstarg;
+
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case BIT_AND_EXPR:
+        integer_only_op = true;
+	/* ... fall through ...  */
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (TREE_CODE (type0) == VECTOR_TYPE)
+          {
+            tree tmp;
+            ret = stv_secondarg;
+            /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+            tmp = type0; type0 = type1; type1 = tmp;
+            tmp = op0; op0 = op1; op1 = tmp;
+          }
+
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (!expr_fits_type_p (op0, type1))
+              {
+                error_at (loc, "conversion of scalar to vector "
+                               "involves truncation");
+                return stv_error;
+              }
+            return ret;
+          }
+        else if (!integer_only_op
+                 && TREE_CODE (type0) == REAL_TYPE
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (!expr_fits_type_p (op0, type1))
+              {
+                error_at (loc, "truncating floating point constant to "
+                               "vector precision does not preserve value");
+                return stv_error;
+              }
+            return ret;
+          }
+      default:
+        break;
+    }
+ 
+  return stv_nothing;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9498,7 +9612,10 @@ build_binary_op (location_t location, en
   else
     int_const = int_const_or_overflow = false;
 
-  if (convert_p)
+  /* Do not apply default conversion in mixed vector/scalar expression.  */
+  if (convert_p 
+      && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) 
+           != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE)))
     {
       op0 = default_conversion (op0);
       op1 = default_conversion (op1);
@@ -9570,6 +9687,41 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1);
+       
+      switch (convert_flag)
+        {
+          case stv_error:
+            return error_mark_node;
+          case stv_firstarg:
+            {
+              tree sc = save_expr (op0);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+            }
+          case stv_secondarg:
+            {
+              tree sc = save_expr (op1);
+              sc = convert (TREE_TYPE (type0), sc);
+              op1 = build_vector_from_val (type0, sc);
+              orig_type1 = type1 = TREE_TYPE (op1);
+              code1 = TREE_CODE (type1);
+              converted = 1;
+              break;
+            }
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-03 14:23   ` Artem Shinkarov
  2010-11-04 21:15     ` Artem Shinkarov
@ 2010-11-06 18:07     ` Joseph S. Myers
  2010-11-08 17:49       ` Artem Shinkarov
  1 sibling, 1 reply; 28+ messages in thread
From: Joseph S. Myers @ 2010-11-06 18:07 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: Richard Guenther, gcc-patches

On Wed, 3 Nov 2010, Artem Shinkarov wrote:

> @@ -9387,6 +9387,104 @@ push_cleanup (tree decl, tree cleanup, b
>    TREE_OPERAND (stmt, 0) = list;
>    STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
>  }
> +
> +/* Return true if expression EXPR can be converted to the
> +   vectortype TYPE preserving its value.  */

"vector type" (two words)

> +static bool
> +expr_fits_type_p (tree expr, tree type)
> +{

I don't see anything here to handle removing widening conversions from 
expr.  Say you have a variable of type short - do you expect to be able to 
do a binary operation between that variable and a vector of shorts?  
Because the variable will have been converted to int.  I don't see any 
testcases in this area either.

If you do want to allow that, rather than making this function smarter and 
so making the language definition depend on how smart the compiler is 
about seeing what conversions are safe I think it might be better to avoid 
having build_binary_op calling default_conversion on the scalar operand in 
a mixed vector/scalar operation.

> +/* Convert scalar to vector for the range of operations.  
> +   Function can return:
> +        -2  --  Error ocured

"occurred"

> +        -1  --  Nothing happened
> +         0  --  First argument must be expanded
> +         1  --  Second argument must be expanded  */

Please define an enum giving symbolic names to the possible return values, 
rather than using magic constants.  */

> +              error_at (loc, "Conversion of scalar to vector "
> +                             "involves truncation");

Diagnostics should not start with capital letters.  Likewise for all the 
other diagnostics in this function.

The patch does not seem to include any testcases for bitwise operations 
(&^|).  If they are meant to work with mixed scalar/vector operations 
(which would be my expectation), then testcases are needed unless already 
in the testsuite; if not, testcases are still needed and the documentation 
needs to make clear they are not allowed.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-03 14:23   ` Artem Shinkarov
@ 2010-11-04 21:15     ` Artem Shinkarov
  2010-11-06 18:07     ` Joseph S. Myers
  1 sibling, 0 replies; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-04 21:15 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, Joseph S. Myers

Patch pinging.

On Wed, Nov 3, 2010 at 2:17 PM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> ChangeLog:
>
> 2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
>
>      /gcc
>      * c-typeck.c (expr_fits_type_p): New function. Check if expression
>      fits into the type considering constants.
>      (scalar_to_vector): New function. Try scalar to vector conversion.
>      (build_binary_op): Adjust.
>      * doc/extend.texi: Description of scalar to vector expansion.
>
>      /gcc/testsuite
>      * gcc.c-torture/execute/scal-to-vec1.c: New test.
>      * gcc.dg/scal-to-vec1.c: New test.
>
> bootstrapped and tested on x86_64_unknown-linux
>
>
> On Wed, Nov 3, 2010 at 1:25 PM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> On Mon, Nov 1, 2010 at 5:16 PM, Artem Shinkarov
>> <artyom.shinkaroff@gmail.com> wrote:
>>> This patch allows binary operations: "vector <op> scalar" and "scalar
>>> <op> vector" in which case scalar is converted into the vector type,
>>> if the scalar type fits in the vectors element type.
>>>
>>> ChangeLog:
>>>
>>> 2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
>>>
>>>       /gcc
>>>       * tree.c (build_vector_from_val): Build vector from scalar
>>>       * tree.h (build_vector_from_val): New declaration
>>
>> Those are no longer part of this patch.
>>
>>>       * c-typeck.c (expr_fits_type_p): New function. Check if expression
>>>       fits into the type considering constants.
>>>       (scalar_to_vector): New function. Try scalar to vector conversion.
>>>       (build_binary_op): Adjust.
>>>       * doc/extend.texi: Description of scalar to vector expansion.
>>>
>>>       /gcc/testsuite
>>>       * gcc.c-torture/execute/scal-to-vec1.c: New test.
>>>       * gcc.dg/scal-to-vec1.c: New test.
>>>
>>> bootstrapped and tested on x86_64_unknown-linux
>>
>> +/* Check whether expression EXPR can be converted to the
>> +   vectortype TYPE, considering the case when EXPR is a constant.  */
>> +static bool
>> +expr_fits_type_p (tree expr, tree type)
>>
>> "Return true if expression ..."
>>
>> also documents the return value.  I think the comment should be adjusted
>> to match the intent of the function, namely
>>
>> "... can be converted to TYPE preserving its value."
>>
>> Passing the element type as TYPE seems to be enough as well.
>>
>> The rationale is that OpenCL does not permit truncations to happen,
>> but people will write things like  float_vector + 2.0 (instead of 2.0f),
>> so we allow value-preserving truncations for QOI reasons.
>>
>> +#define SWAP(x, y) do { __typeof (x) __tmp = x; x = y; y = __tmp; } while (0)
>>
>> we don't usually define such thing but expand it everywhere needed.
>>
>> +            {
>> +              tree sc = save_expr(op0);
>>
>> space after save_expr, likewise below.
>>
>> Otherwise looks ok (but I've been looking at the patches before).  I can't
>> approve it though.
>>
>> Thanks,
>> Richard.
>>
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-03 13:27 ` Richard Guenther
@ 2010-11-03 14:23   ` Artem Shinkarov
  2010-11-04 21:15     ` Artem Shinkarov
  2010-11-06 18:07     ` Joseph S. Myers
  0 siblings, 2 replies; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-03 14:23 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 2838 bytes --]

ChangeLog:

2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

      /gcc
      * c-typeck.c (expr_fits_type_p): New function. Check if expression
      fits into the type considering constants.
      (scalar_to_vector): New function. Try scalar to vector conversion.
      (build_binary_op): Adjust.
      * doc/extend.texi: Description of scalar to vector expansion.

      /gcc/testsuite
      * gcc.c-torture/execute/scal-to-vec1.c: New test.
      * gcc.dg/scal-to-vec1.c: New test.

bootstrapped and tested on x86_64_unknown-linux


On Wed, Nov 3, 2010 at 1:25 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Mon, Nov 1, 2010 at 5:16 PM, Artem Shinkarov
> <artyom.shinkaroff@gmail.com> wrote:
>> This patch allows binary operations: "vector <op> scalar" and "scalar
>> <op> vector" in which case scalar is converted into the vector type,
>> if the scalar type fits in the vectors element type.
>>
>> ChangeLog:
>>
>> 2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
>>
>>       /gcc
>>       * tree.c (build_vector_from_val): Build vector from scalar
>>       * tree.h (build_vector_from_val): New declaration
>
> Those are no longer part of this patch.
>
>>       * c-typeck.c (expr_fits_type_p): New function. Check if expression
>>       fits into the type considering constants.
>>       (scalar_to_vector): New function. Try scalar to vector conversion.
>>       (build_binary_op): Adjust.
>>       * doc/extend.texi: Description of scalar to vector expansion.
>>
>>       /gcc/testsuite
>>       * gcc.c-torture/execute/scal-to-vec1.c: New test.
>>       * gcc.dg/scal-to-vec1.c: New test.
>>
>> bootstrapped and tested on x86_64_unknown-linux
>
> +/* Check whether expression EXPR can be converted to the
> +   vectortype TYPE, considering the case when EXPR is a constant.  */
> +static bool
> +expr_fits_type_p (tree expr, tree type)
>
> "Return true if expression ..."
>
> also documents the return value.  I think the comment should be adjusted
> to match the intent of the function, namely
>
> "... can be converted to TYPE preserving its value."
>
> Passing the element type as TYPE seems to be enough as well.
>
> The rationale is that OpenCL does not permit truncations to happen,
> but people will write things like  float_vector + 2.0 (instead of 2.0f),
> so we allow value-preserving truncations for QOI reasons.
>
> +#define SWAP(x, y) do { __typeof (x) __tmp = x; x = y; y = __tmp; } while (0)
>
> we don't usually define such thing but expand it everywhere needed.
>
> +            {
> +              tree sc = save_expr(op0);
>
> space after save_expr, likewise below.
>
> Otherwise looks ok (but I've been looking at the patches before).  I can't
> approve it though.
>
> Thanks,
> Richard.
>

[-- Attachment #2: scal-to-vec.c.v6.diff --]
[-- Type: text/x-diff, Size: 10868 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166126)
+++ gcc/doc/extend.texi	(working copy)
@@ -6319,18 +6319,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + {1,1,1,1}; */
+a = 2 * b;    /* a = {2,2,2,2} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,79 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) a op b
+#define operr(a, b, op) b op a
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "Conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "Conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "Truncating floating point" } */
+    f1 = 1.3 + f0;      /* { dg-error "Truncating floating point" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+    f1 = sint + f0;     /* { dg-error "can't convert between vector values of different size" } */
+
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 166126)
+++ gcc/c-typeck.c	(working copy)
@@ -9387,6 +9387,104 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Return true if expression EXPR can be converted to the
+   vectortype TYPE preserving its value.  */
+static bool
+expr_fits_type_p (tree expr, tree type)
+{
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (type));
+  if (TYPE_MODE (TREE_TYPE (expr)) == mode)
+    return true;
+
+  if (TREE_CODE (expr) == INTEGER_CST)
+    return int_fits_type_p (expr, TREE_TYPE (type));
+  else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+    return !tree_int_cst_lt 
+                (TYPE_SIZE (TREE_TYPE (type)),
+                 TYPE_SIZE (TREE_TYPE (expr)));
+  else if (TREE_CODE (expr) == REAL_CST)
+    {
+      REAL_VALUE_TYPE c, c1;
+      c = TREE_REAL_CST (expr);
+      real_convert (&c1, mode, &c);
+      return real_identical (&c, &c1);
+    }
+  else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+    return (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) 
+            <= GET_MODE_SIZE (mode));
+  return false;
+}
+
+/* Convert scalar to vector for the range of operations.  
+   Function can return:
+        -2  --  Error ocured
+        -1  --  Nothing happened
+         0  --  First argument must be expanded
+         1  --  Second argument must be expanded  */
+static int
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  int ret = 0;
+  
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (type0) == INTEGER_TYPE)
+          if (!expr_fits_type_p (op0, type1))
+            {
+              error_at (loc, "Conversion of scalar to vector "
+                             "involves truncation");
+              return -2;
+            }
+          return 0;
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (TREE_CODE (type0) == VECTOR_TYPE)
+          {
+            ret = 1;
+            tree tmp;
+            /* Swap TYPE0 with TYPE1 and OP0 with OP1  */
+            tmp = type0; type0 = type1; type1 = tmp;
+            tmp = op0; op0 = op1; op1 = tmp;
+          }
+
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (!expr_fits_type_p (op0, type1))
+              {
+                error_at (loc, "Conversion of scalar to vector "
+                               "involves truncation");
+                return -2;
+              }
+           return ret;
+          }
+        else if (TREE_CODE (type0) == REAL_TYPE
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (!expr_fits_type_p (op0, type1))
+              {
+                error_at (loc, "Truncating floating point constant to "
+                               "vector precision does not preserve value");
+                return -2;
+              }
+           return ret;
+          }
+      default:
+        break;
+    }
+ 
+  return -1;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9570,6 +9668,41 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      int convert_flag = scalar_to_vector (location, code, op0, op1);
+       
+      switch (convert_flag)
+        {
+          case -2:
+            return error_mark_node;
+          case  0:
+            {
+              tree sc = save_expr (op0);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+            }
+          case  1:
+            {
+              tree sc = save_expr (op1);
+              sc = convert (TREE_TYPE (type0), sc);
+              op1 = build_vector_from_val (type0, sc);
+              orig_type1 = type1 = TREE_TYPE (op1);
+              code1 = TREE_CODE (type1);
+              converted = 1;
+              break;
+            }
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-01 16:21 Artem Shinkarov
  2010-11-03 13:25 ` Artem Shinkarov
@ 2010-11-03 13:27 ` Richard Guenther
  2010-11-03 14:23   ` Artem Shinkarov
  1 sibling, 1 reply; 28+ messages in thread
From: Richard Guenther @ 2010-11-03 13:27 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: gcc-patches, Joseph S. Myers

On Mon, Nov 1, 2010 at 5:16 PM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> This patch allows binary operations: "vector <op> scalar" and "scalar
> <op> vector" in which case scalar is converted into the vector type,
> if the scalar type fits in the vectors element type.
>
> ChangeLog:
>
> 2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
>
>       /gcc
>       * tree.c (build_vector_from_val): Build vector from scalar
>       * tree.h (build_vector_from_val): New declaration

Those are no longer part of this patch.

>       * c-typeck.c (expr_fits_type_p): New function. Check if expression
>       fits into the type considering constants.
>       (scalar_to_vector): New function. Try scalar to vector conversion.
>       (build_binary_op): Adjust.
>       * doc/extend.texi: Description of scalar to vector expansion.
>
>       /gcc/testsuite
>       * gcc.c-torture/execute/scal-to-vec1.c: New test.
>       * gcc.dg/scal-to-vec1.c: New test.
>
> bootstrapped and tested on x86_64_unknown-linux

+/* Check whether expression EXPR can be converted to the
+   vectortype TYPE, considering the case when EXPR is a constant.  */
+static bool
+expr_fits_type_p (tree expr, tree type)

"Return true if expression ..."

also documents the return value.  I think the comment should be adjusted
to match the intent of the function, namely

"... can be converted to TYPE preserving its value."

Passing the element type as TYPE seems to be enough as well.

The rationale is that OpenCL does not permit truncations to happen,
but people will write things like  float_vector + 2.0 (instead of 2.0f),
so we allow value-preserving truncations for QOI reasons.

+#define SWAP(x, y) do { __typeof (x) __tmp = x; x = y; y = __tmp; } while (0)

we don't usually define such thing but expand it everywhere needed.

+            {
+              tree sc = save_expr(op0);

space after save_expr, likewise below.

Otherwise looks ok (but I've been looking at the patches before).  I can't
approve it though.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-11-01 16:21 Artem Shinkarov
@ 2010-11-03 13:25 ` Artem Shinkarov
  2010-11-03 13:27 ` Richard Guenther
  1 sibling, 0 replies; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-03 13:25 UTC (permalink / raw)
  To: gcc-patches; +Cc: Joseph S. Myers, Richard Guenther

Patch pinging.

Can someone approve this, cause there are other patches waiting that
depend on this one.


Thanks,
Artem.

On Mon, Nov 1, 2010 at 4:16 PM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> This patch allows binary operations: "vector <op> scalar" and "scalar
> <op> vector" in which case scalar is converted into the vector type,
> if the scalar type fits in the vectors element type.
>
> ChangeLog:
>
> 2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
>
>       /gcc
>       * tree.c (build_vector_from_val): Build vector from scalar
>       * tree.h (build_vector_from_val): New declaration
>       * c-typeck.c (expr_fits_type_p): New function. Check if expression
>       fits into the type considering constants.
>       (scalar_to_vector): New function. Try scalar to vector conversion.
>       (build_binary_op): Adjust.
>       * doc/extend.texi: Description of scalar to vector expansion.
>
>       /gcc/testsuite
>       * gcc.c-torture/execute/scal-to-vec1.c: New test.
>       * gcc.dg/scal-to-vec1.c: New test.
>
> bootstrapped and tested on x86_64_unknown-linux
>
> OK?
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Scalar vector binary operation
@ 2010-11-01 16:21 Artem Shinkarov
  2010-11-03 13:25 ` Artem Shinkarov
  2010-11-03 13:27 ` Richard Guenther
  0 siblings, 2 replies; 28+ messages in thread
From: Artem Shinkarov @ 2010-11-01 16:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: Joseph S. Myers, Richard Guenther

[-- Attachment #1: Type: text/plain, Size: 877 bytes --]

This patch allows binary operations: "vector <op> scalar" and "scalar
<op> vector" in which case scalar is converted into the vector type,
if the scalar type fits in the vectors element type.

ChangeLog:

2010-11-01  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

       /gcc
       * tree.c (build_vector_from_val): Build vector from scalar
       * tree.h (build_vector_from_val): New declaration
       * c-typeck.c (expr_fits_type_p): New function. Check if expression
       fits into the type considering constants.
       (scalar_to_vector): New function. Try scalar to vector conversion.
       (build_binary_op): Adjust.
       * doc/extend.texi: Description of scalar to vector expansion.

       /gcc/testsuite
       * gcc.c-torture/execute/scal-to-vec1.c: New test.
       * gcc.dg/scal-to-vec1.c: New test.

bootstrapped and tested on x86_64_unknown-linux

OK?

[-- Attachment #2: scal-to-vec.c.v5.diff --]
[-- Type: text/x-diff, Size: 10868 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166126)
+++ gcc/doc/extend.texi	(working copy)
@@ -6319,18 +6319,25 @@ In C it is possible to use shifting oper
 integer-type vectors. The operation is defined as following: @code{@{a0,
 a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
 @dots{}, an >> bn@}}@. Vector operands must have the same number of
-elements.  Additionally second operands can be a scalar integer in which
-case the scalar is converted to the type used by the vector operand (with
-possible truncation) and each element of this new vector is the scalar's
-value.
+elements. 
+
+For the convenience in C it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will transform
+the scalar operand into a vector where each element is the scalar from
+the operation. The transformation will happen only if the scalar could be
+safely converted to the vector-element type.
 Consider the following code.
 
 @smallexample
 typedef int v4si __attribute__ ((vector_size (16)));
 
-v4si a, b;
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + {1,1,1,1}; */
+a = 2 * b;    /* a = {2,2,2,2} * b; */
 
-b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+a = l + a;    /* Error, cannot convert long to int. */
 @end smallexample
 
 In C vectors can be subscripted as if the vector were an array with
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,79 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) a op b
+#define operr(a, b, op) b op a
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+    v1 = 2 << v0;   check (short, 8, v0, v1, 2, <<, l);
+    v1 = 2 >> v0;   check (short, 8, v0, v1, 2, >>, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+extern float sfl;
+extern int   sint;
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(4, int) i0 = {1,2,3,4};
+    vector(4, int) i1, i2;
+
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "Conversion of scalar to vector" } */
+    v1 = 99999 + v0;    /* { dg-error "Conversion of scalar to vector" } */
+
+    f1 = d + f0;        /* { dg-error "Truncating floating point" } */
+    f1 = 1.3 + f0;      /* { dg-error "Truncating floating point" } */
+
+    /* convert.c should take care of this.  */
+    i1 = sfl + i0;      /* { dg-error "can't convert value to a vector" } */
+    i1 = 1.5 + i0;      /* { dg-error "can't convert value to a vector" } */
+    v1 = d + v0;        /* { dg-error "can't convert value to a vector" } */
+    f1 = sint + f0;     /* { dg-error "can't convert between vector values of different size" } */
+
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 166126)
+++ gcc/c-typeck.c	(working copy)
@@ -9387,6 +9387,105 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Check whether expression EXPR can be converted to the
+   vectortype TYPE, considering the case when EXPR is a constant.  */
+static bool
+expr_fits_type_p (tree expr, tree type)
+{
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (type));
+  if (TYPE_MODE (TREE_TYPE (expr)) == mode)
+    return true;
+
+  if (TREE_CODE (expr) == INTEGER_CST)
+    return int_fits_type_p (expr, TREE_TYPE (type));
+  else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+    return !tree_int_cst_lt 
+                (TYPE_SIZE (TREE_TYPE (type)),
+                 TYPE_SIZE (TREE_TYPE (expr)));
+  else if (TREE_CODE (expr) == REAL_CST)
+    {
+      REAL_VALUE_TYPE c, c1;
+      c = TREE_REAL_CST (expr);
+      real_convert (&c1, mode, &c);
+      return real_identical (&c, &c1);
+    }
+  else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+    return (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) 
+            <= GET_MODE_SIZE (mode));
+  return false;
+}
+
+/* Convert scalar to vector for the range of operations.  
+   Function can return:
+        -2  --  Error ocured
+        -1  --  Nothing happened
+         0  --  First argument must be expanded
+         1  --  Second argument must be expanded  */
+static int
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+#define SWAP(x, y) do { __typeof (x) __tmp = x; x = y; y = __tmp; } while (0)
+  
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  int ret = 0;
+  
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (type0) == INTEGER_TYPE)
+          if (!expr_fits_type_p (op0, type1))
+            {
+              error_at (loc, "Conversion of scalar to vector "
+                             "involves truncation");
+              return -2;
+            }
+          return 0;
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (TREE_CODE (type0) == VECTOR_TYPE)
+          {
+            ret = 1;
+            SWAP (type0, type1);
+            SWAP (op0, op1);
+          }
+
+        if (TREE_CODE (type0) == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (!expr_fits_type_p (op0, type1))
+              {
+                error_at (loc, "Conversion of scalar to vector "
+                               "involves truncation");
+                return -2;
+              }
+           return ret;
+          }
+        else if (TREE_CODE (type0) == REAL_TYPE
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (!expr_fits_type_p (op0, type1))
+              {
+                error_at (loc, "Truncating floating point constant to "
+                               "vector precision does not preserve value");
+                return -2;
+              }
+           return ret;
+          }
+      default:
+        break;
+    }
+ 
+  return -1;
+#undef SWAP
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9570,6 +9669,41 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* In case when one of the operands of the binary operation is
+     a vector and another is a scalar -- convert scalar to vector.  */
+  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))
+    {
+      int convert_flag = scalar_to_vector (location, code, op0, op1);
+       
+      switch (convert_flag)
+        {
+          case -2:
+            return error_mark_node;
+          case  0:
+            {
+              tree sc = save_expr(op0);
+              sc = convert (TREE_TYPE (type1), sc);
+              op0 = build_vector_from_val (type1, sc);
+              orig_type0 = type0 = TREE_TYPE (op0);
+              code0 = TREE_CODE (type0);
+              converted = 1;
+              break;
+            }
+          case  1:
+            {
+              tree sc = save_expr(op1);
+              sc = convert (TREE_TYPE (type0), sc);
+              op1 = build_vector_from_val (type0, sc);
+              orig_type1 = type1 = TREE_TYPE (op1);
+              code1 = TREE_CODE (type1);
+              converted = 1;
+              break;
+            }
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Scalar vector binary operation
  2010-08-14 16:41 Artem Shinkarov
@ 2010-08-16 22:31 ` Richard Henderson
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2010-08-16 22:31 UTC (permalink / raw)
  To: Artem Shinkarov; +Cc: gcc-patches, Richard Guenther

On 08/14/2010 09:37 AM, Artem Shinkarov wrote:
> +/* Build a vector of type VECTYPE where all the elements are SCs.  */
> +tree
> +build_vector_from_val (const tree sc, const tree vectype) 
> +{
> +  tree t = NULL_TREE;
> +  int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
> +
> +  if (sc == error_mark_node)
> +    return sc;
> +
> +  gcc_assert (TREE_TYPE (sc) == TREE_TYPE (vectype));
> +
> +  for (i = 0; i < nunits; ++i)
> +    t = tree_cons (NULL_TREE, sc, t);
> +
> +  if (CONSTANT_CLASS_P (sc))
> +    return build_vector (vectype, t);
> +  else 
> +    return build_constructor_from_list (vectype, t);
> +}
> +

Better to use build_constructor and build_vector_from_ctor.
We've been trying to eliminate TREE_LIST.

> +static inline bool
> +expr_fits_type_p (const tree expr, const tree type )

No explicit inline marker.

This function doesn't handle real/integer type crosses.
I.e. v4sf * long or v4si * 2.0.  It will crash for some
of the combinations.

> +static inline int
> +scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)

No explicit inline marker.

> +#define MSG "Conversion of scalar to vector involves truncation"
> +#define MSG_FLOAT "Truncating floating point constant to vector " \
> +                  "precision does not preserve value"
> +#define ERROR(MSG, LOC, RET) { error_at (LOC, MSG); return RET; }

This is, frankly, gross.

> +      case RSHIFT_EXPR:
> +      case LSHIFT_EXPR:
> +        if (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE)
> +          return 0;

			  code0

I think you also want to check for vect << int, which is directly
supported by most cpus.  Also, you don't want a fallthru to the
real format checks.

You could probably simplify the code a bit for the arithmetic ops
if you first force op0 to be the vector operation.  Since we're not
actually emitting code here, it doesn't matter if we temporarily
"swap" non-commutative operands.

Some commentary that one of op0 or op1 is known to be vector type
and the other is known to be scalar type would also help here.

Using FP scalar types with integer vector types is probably suspect
and should generate an error.


> +  /* For 'vector <shift> scalar' or 'scalar <shift> vector', we convert 
> +     a scalar to a vector. Truncating the shift amount is ok.  */
> +  if ((code0 == VECTOR_TYPE || code1 == VECTOR_TYPE)
> +      && (code0 != code1))

  if ((code0 == VECTOR_TYPE) != (code1 == VECTOR_TYPE))

> +    {
> +        int convert_flag = scalar_to_vector (location, code, op0, op1);
> +        
> +        if (convert_flag == -2)

Definitely use a switch here.  Possibly better with an enum.


r~

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Scalar vector binary operation
@ 2010-08-14 16:41 Artem Shinkarov
  2010-08-16 22:31 ` Richard Henderson
  0 siblings, 1 reply; 28+ messages in thread
From: Artem Shinkarov @ 2010-08-14 16:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Guenther

[-- Attachment #1: Type: text/plain, Size: 1003 bytes --]

This patch allows to write a vector binary expression where one
operand is a scalar. This is done according to the OpenCL standard.

The scalar operand in the expression is converted to the vector where
each element is the scalar form the expression. We check whether the
scalar fits in the type of vector element.

ChangeLog:

2010-06-18  Artem Shinkarov <artyom.shinakroff@gmail.com>

        /gcc
        * tree.c (build_vector_from_val): Build vector from scalar
        * tree.h (build_vector_from_val): New declaration
        * c-typeck.c (expr_fits_type_p): New function. Check if expression
        fits into the type considering constants.
        (scalar_to_vector): New function. Try scalar to vector conversion.
        (build_binary_op): Adjust.

        /gcc/testsuite
        * gcc.c-torture/execute/scal-to-vec1.c: New test.
        * gcc.dg/scal-to-vec1.c: New test.

        /gcc/doc
        * extend.texi: Adjust


bootstrapped and tested on x86_64_unknown-linux




Artem Shinkarov

[-- Attachment #2: scal-to-vec.c.v3.diff --]
[-- Type: text/x-diff, Size: 11268 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 163244)
+++ gcc/doc/extend.texi	(working copy)
@@ -6135,6 +6135,25 @@ v4si a, b, c;
 c = a + b;
 @end smallexample
 
+For the convenience it is allowed to use a binary vector operation
+where one operand is a scalar. In that case the compiler will 
+transform the scalar operand into a vector where each element is the 
+scalar from the operation. The transformation will happen only 
+if the scalar could be safely converted to the vector-element type.
+Consider the following code.
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a, b, c;
+long l;
+
+a = b + 1;    /* a = b + {1,1,1,1}; */
+a = 2 * b;    /* a = {2,2,2,2} * b; */
+
+a = l + a;    /* Error, cannot convert long to int. */
+@end smallexample
+
 Subtraction, multiplication, division, and the logical operations
 operate in a similar manner.  Likewise, the result of using the unary
 minus or complement operators on a vector type is a vector whose
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 163244)
+++ gcc/tree.c	(working copy)
@@ -1358,6 +1358,28 @@ build_vector_from_ctor (tree type, VEC(c
   return build_vector (type, nreverse (list));
 }
 
+/* Build a vector of type VECTYPE where all the elements are SCs.  */
+tree
+build_vector_from_val (const tree sc, const tree vectype) 
+{
+  tree t = NULL_TREE;
+  int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
+
+  if (sc == error_mark_node)
+    return sc;
+
+  gcc_assert (TREE_TYPE (sc) == TREE_TYPE (vectype));
+
+  for (i = 0; i < nunits; ++i)
+    t = tree_cons (NULL_TREE, sc, t);
+
+  if (CONSTANT_CLASS_P (sc))
+    return build_vector (vectype, t);
+  else 
+    return build_constructor_from_list (vectype, t);
+}
+
+
 /* Return a new CONSTRUCTOR node whose type is TYPE and whose values
    are in the VEC pointed to by VALS.  */
 tree
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 163244)
+++ gcc/tree.h	(working copy)
@@ -4027,6 +4027,7 @@ extern tree build_int_cst_type (tree, HO
 extern tree build_int_cst_wide (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
 extern tree build_vector (tree, tree);
 extern tree build_vector_from_ctor (tree, VEC(constructor_elt,gc) *);
+extern tree build_vector_from_val (const tree, const tree);
 extern tree build_constructor (tree, VEC(constructor_elt,gc) *);
 extern tree build_constructor_single (tree, tree, tree);
 extern tree build_constructor_from_list (tree, tree);
Index: gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,77 @@
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+#define operl(a, b, op) a op b
+#define operr(a, b, op) b op a
+
+#define check(type, count, vec0, vec1, num, op, lr) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) {\
+        if (vidx (type, vec1, __i) != oper##lr (num, vidx (type, vec0, __i), op)) \
+            __builtin_abort (); \
+    }\
+} while (0)
+
+#define veccompare(type, count, v0, v1) \
+do {\
+    int __i; \
+    for (__i = 0; __i < count; __i++) { \
+        if (vidx (type, v0, __i) != vidx (type, v1, __i)) \
+            __builtin_abort (); \
+    } \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define fvec_2 (vector(4, float)){2., 2., 2., 2.}
+#define dvec_2 (vector(2, double)){2., 2.}
+
+
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+
+    vector(2, double) d0 = {1., 2.};
+    vector(2, double) d1, d2;
+
+
+
+    v1 = 2 + v0;   check (short, 8, v0, v1, 2, +, l);
+    v1 = 2 - v0;   check (short, 8, v0, v1, 2, -, l);
+    v1 = 2 * v0;   check (short, 8, v0, v1, 2, *, l);
+    v1 = 2 / v0;   check (short, 8, v0, v1, 2, /, l);
+    v1 = 2 % v0;   check (short, 8, v0, v1, 2, %, l);
+
+    v1 = v0 + 2;   check (short, 8, v0, v1, 2, +, r);
+    v1 = v0 - 2;   check (short, 8, v0, v1, 2, -, r);
+    v1 = v0 * 2;   check (short, 8, v0, v1, 2, *, r);
+    v1 = v0 / 2;   check (short, 8, v0, v1, 2, /, r);
+    v1 = v0 % 2;   check (short, 8, v0, v1, 2, %, r);
+
+    f1 = 2. + f0;  f2 = fvec_2 + f0; veccompare (float, 4, f1, f2);
+    f1 = 2. - f0;  f2 = fvec_2 - f0; veccompare (float, 4, f1, f2);
+    f1 = 2. * f0;  f2 = fvec_2 * f0; veccompare (float, 4, f1, f2);
+    f1 = 2. / f0;  f2 = fvec_2 / f0; veccompare (float, 4, f1, f2);
+
+    f1 = f0 + 2.;  f2 = f0 + fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 - 2.;  f2 = f0 - fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 * 2.;  f2 = f0 * fvec_2; veccompare (float, 4, f1, f2);
+    f1 = f0 / 2.;  f2 = f0 / fvec_2; veccompare (float, 4, f1, f2);
+
+    d1 = 2. + d0;  d2 = dvec_2 + d0; veccompare (double, 2, d1, d2);
+    d1 = 2. - d0;  d2 = dvec_2 - d0; veccompare (double, 2, d1, d2);
+    d1 = 2. * d0;  d2 = dvec_2 * d0; veccompare (double, 2, d1, d2);
+    d1 = 2. / d0;  d2 = dvec_2 / d0; veccompare (double, 2, d1, d2);
+
+    d1 = d0 + 2.;  d2 = d0 + dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 - 2.;  d2 = d0 - dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 * 2.;  d2 = d0 * dvec_2; veccompare (double, 2, d1, d2);
+    d1 = d0 / 2.;  d2 = d0 / dvec_2; veccompare (double, 2, d1, d2);
+
+    return 0;
+}
Index: gcc/testsuite/gcc.dg/scal-to-vec1.c
===================================================================
--- gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/scal-to-vec1.c	(revision 0)
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc, 1,2,3,4,5,6,7};
+    vector(8, short) v1;
+
+    vector(4, float) f0 = {1., 2., 3., 4.};
+    vector(4, float) f1, f2;
+    
+    int     i = 12;
+    double  d = 3.;
+
+    v1 = i + v0;        /* { dg-error "" } */
+    v1 = 99999 + v0;    /* { dg-error "" } */
+
+    f1 = d + f0;        /* { dg-error "" } */
+    f1 = 1.3 + f0;      /* { dg-error "" } */
+
+    return 0;
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 163244)
+++ gcc/c-typeck.c	(working copy)
@@ -9196,6 +9196,102 @@ push_cleanup (tree decl, tree cleanup, b
   TREE_OPERAND (stmt, 0) = list;
   STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
 }
+
+/* Check whether expression EXPR can be converted to the TYPE, 
+   considering the case when EXPR is a constant.  */
+static inline bool
+expr_fits_type_p (const tree expr, const tree type )
+{
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (type));
+  if (TYPE_MODE (TREE_TYPE (expr)) == mode)
+    return true;
+
+  if (TREE_CODE (expr) == INTEGER_CST)
+    return int_fits_type_p (expr, TREE_TYPE (type));
+  else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+    return !tree_int_cst_lt 
+                (TYPE_SIZE (TREE_TYPE (type)),
+                 TYPE_SIZE (TREE_TYPE (expr)));
+  else if (TREE_CODE (expr) == REAL_CST)
+    {
+      REAL_VALUE_TYPE c, c1;
+      c = TREE_REAL_CST (expr);
+      real_convert (&c1, mode, &c);
+      return real_identical (&c, &c1);
+    }
+  else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+    return (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) 
+            <= GET_MODE_SIZE (mode));
+  return false;
+}
+
+/* Convert scalar to vector for the range of operations.  
+   Function can return:
+        -2  --  Error ocured
+        -1  --  Nothing happened
+         0  --  First argument must be expanded
+         1  --  Second argument must be expanded  */
+static inline int
+scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1)
+{
+#define MSG "Conversion of scalar to vector involves truncation"
+#define MSG_FLOAT "Truncating floating point constant to vector " \
+                  "precision does not preserve value"
+#define ERROR(MSG, LOC, RET) { error_at (LOC, MSG); return RET; }
+  
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  enum tree_code code0 = TREE_CODE (type0);
+  enum tree_code code1 = TREE_CODE (type1);
+  
+  switch (code)
+    {
+      case RSHIFT_EXPR:
+      case LSHIFT_EXPR:
+        if (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE)
+          return 0;
+      
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+      case MULT_EXPR:
+      case TRUNC_DIV_EXPR:
+      case TRUNC_MOD_EXPR:
+      case RDIV_EXPR:
+        if (code0 == INTEGER_TYPE
+            && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) 
+          {
+            if (!expr_fits_type_p (op0, type1))
+              ERROR (MSG, loc, -2);
+            return 0;
+          }
+        else if (code1 == INTEGER_TYPE
+                 &&  TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+          {
+            if (!expr_fits_type_p (op1, type0))
+              ERROR (MSG, loc, -2);
+            return 1;
+          }
+
+        else if (code0 == REAL_TYPE
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1)))
+          {
+            if (!expr_fits_type_p (op0, type1))
+              ERROR (MSG_FLOAT, loc, -2);
+            return 0;
+          }
+        else if (code1 == REAL_TYPE
+                 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type0)))
+          {
+            if (!expr_fits_type_p (op1, type0))
+              ERROR (MSG_FLOAT, loc, -2);
+            return 1;
+          }
+      default:
+        break;
+    }
+ 
+  return -1;
+}
 \f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
@@ -9375,6 +9471,35 @@ build_binary_op (location_t location, en
 
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
+  /* For 'vector <shift> scalar' or 'scalar <shift> vector', we convert 
+     a scalar to a vector. Truncating the shift amount is ok.  */
+  if ((code0 == VECTOR_TYPE || code1 == VECTOR_TYPE)
+      && (code0 != code1))
+    {
+        int convert_flag = scalar_to_vector (location, code, op0, op1);
+        
+        if (convert_flag == -2)
+          return error_mark_node;
+        else if (convert_flag == 0)
+          {
+            tree sc = save_expr(op0);
+            sc = convert (TREE_TYPE (type1), sc);
+            op0 = build_vector_from_val (sc, type1);
+            orig_type0 = type0 = TREE_TYPE (op0);
+            code0 = TREE_CODE (type0);
+            converted = 1;
+          }
+        else if (convert_flag == 1)
+          {
+            tree sc = save_expr(op1);
+            sc = convert (TREE_TYPE (type0), sc);
+            op1 = build_vector_from_val (sc, type0);
+            orig_type1 = type1 = TREE_TYPE (op1);
+            code1 = TREE_CODE (type1);
+            converted = 1;
+          }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2011-12-05 11:27 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-09 23:54 Scalar vector binary operation Artem Shinkarov
2011-08-10  0:00 ` Artem Shinkarov
2011-08-10 15:02   ` Richard Guenther
2011-09-28 14:33     ` Ian Lance Taylor
2011-09-28 14:55       ` Artem Shinkarov
2011-09-28 15:48         ` Ian Lance Taylor
2011-09-28 20:46           ` Artem Shinkarov
2011-12-05 11:27             ` Gerald Pfeifer
  -- strict thread matches above, loose matches on Subject: below --
2010-11-01 16:21 Artem Shinkarov
2010-11-03 13:25 ` Artem Shinkarov
2010-11-03 13:27 ` Richard Guenther
2010-11-03 14:23   ` Artem Shinkarov
2010-11-04 21:15     ` Artem Shinkarov
2010-11-06 18:07     ` Joseph S. Myers
2010-11-08 17:49       ` Artem Shinkarov
2010-11-12 21:39         ` Joseph S. Myers
2010-11-15 18:00           ` Artem Shinkarov
2010-11-16 17:10             ` Joseph S. Myers
2010-11-18 14:01               ` Artem Shinkarov
2010-11-19 22:44                 ` Joseph S. Myers
2010-11-22 16:26                   ` Artem Shinkarov
2010-12-03 18:00                     ` Joseph S. Myers
2010-12-17 16:16                       ` Artem Shinkarov
2011-01-21 15:24                         ` Richard Guenther
2011-01-26  1:13                           ` Joseph S. Myers
2011-02-09 17:09                             ` Artem Shinkarov
2010-08-14 16:41 Artem Shinkarov
2010-08-16 22:31 ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).