diff mbox

Scalar vector binary operation

Message ID AANLkTimnBQpigzjjh=tjHEWZsRhqOU-P0HgiQ7cLbjzX@mail.gmail.com
State New
Headers show

Commit Message

Artem Shinkarov Nov. 15, 2010, 4:55 p.m. UTC
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
>

Comments

Joseph Myers Nov. 16, 2010, 4:39 p.m. UTC | #1
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?
diff mbox

Patch

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