diff mbox

Scalar vector binary operation

Message ID AANLkTimt1Agn0zjsOK5V4NmOJ+DW2hkUB7s6v7e5e-Cv@mail.gmail.com
State New
Headers show

Commit Message

Richard Biener Jan. 21, 2011, 3:04 p.m. UTC
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.

Comments

Joseph Myers Jan. 26, 2011, 12:03 a.m. UTC | #1
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.
diff mbox

Patch

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;
+}
 
 /* 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: