diff mbox

Vector shifting patch

Message ID AANLkTi=FFVHrHtft0H_+U-qR86tG4TMEFRDL7ojzN1-J@mail.gmail.com
State New
Headers show

Commit Message

Artem Shinkarov Oct. 25, 2010, 5:15 p.m. UTC
Here is a version with improved build_vector_from val.

ChangeLog:

2010-10-25  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
  Andrew Pinski <pinskia@gmail.com>

  gcc/
  * tree.h (build_vector_from_val): Declare.
  * tree.c (build_vector_from_val): New function.
  * c-typeck.c (build_binary_op): Handle vector shifting.

  gcc/testsuite/
  * gcc.c-torture/execute/vector-shift.c: Likewise.
  * gcc.c-torture/execute/vector-shift1.c: New testcase.
  * gcc.c-torture/execute/vector-shift2.c: New testcase.
  * gcc.dg/vector-shift.c: New testcase.
  * gcc.dg/vector-shift1.c: New testcase.
  * gcc.dg/vector-shift2.c: New testcase.
  * gcc.dg/vector-shift3.c: New testcase.
  * gcc.dg/vector-shift4.c: New testcase.

bootstrapped and tested on x86_64_unknown-linux

OK?


On Mon, Oct 25, 2010 at 4:27 PM, Nathan Froyd <froydnj@codesourcery.com> wrote:
> On Mon, Oct 25, 2010 at 04:21:47PM +0100, Artem Shinkarov wrote:
>> Does it look better now:
>>
>> tree
>> build_vector_from_val (const tree sc, const tree vectype)
>> {
>>   int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
>>   VEC(constructor_elt, gc) *v;
>>
>>   if (sc == error_mark_node)
>>     return sc;
>>
>>   gcc_assert (TREE_TYPE (sc) == TREE_TYPE (vectype));
>>
>>   v = VEC_alloc (constructor_elt, gc, nunits);
>>   for (i = 0; i < nunits; ++i)
>>     CONSTRUCTOR_APPEND_ELT (v, size_int (i), sc);
>                                 ^^^^^^^^^^^^
>
> You can just pass NULL_TREE here and the Right Thing will happen.
>
> I think the logic looks fine.  For consistency's sake, it would probably
> be good to have the argument order reversed, i.e.:
>
> tree
> build_vector_from_val (const_tree vectype, const_tree sc)
>
> as that would more closely match the existing build_vector* functions.
>
> Please also note that you want const_tree instead of 'const tree' (note
> underscore).  If there are other instances of that in your patch, you'll
> want to fix those too.
>
> -Nathan
>

Comments

Joseph Myers Oct. 26, 2010, 3:15 p.m. UTC | #1
On Mon, 25 Oct 2010, Artem Shinkarov wrote:

> Index: gcc/doc/extend.texi
> ===================================================================
> --- gcc/doc/extend.texi	(revision 165913)
> +++ gcc/doc/extend.texi	(working copy)
> @@ -6309,6 +6309,23 @@ v4si a, b, c;
>  c = a + b;
>  @end smallexample
>  
> +In C it is possible to use shifting operators @code{<<, >>} on integer-type
> +vectors. The operation is defined as following: @code{@{a0, a1, ..., an@} >> @{b0, b1,
> +..., bn@} == @{a0 >> b0, a1 >> b1, ..., an >> bn@}}@.  Additionally one of the

The "..." here should be @dots{} since it is not the literal C token 
"...".

> +operands can be a scalar integer in which case the scalar is converted to the
> +type used by the vector operand and each element of this new vector is the
> +scalar's value.  Consider the following code.

Most of my comments relate to the scalar case which seems more potentially 
problematic than the case where both operands are vectors.  But in the 
case where both operands are vectors I note you say nothing about 
permitted types of the two operands.  Are they required to be exactly the 
same?  Or can they differ in signedness?  In the width of elements of the 
vector?

In normal C without vectors, the types of the two operands of a shift are 
independent.  This would tend to suggest that this should be the case for 
vectors - they must have the same number of elements, but why constrain 
things further?  I didn't see any such constraint in the OpenCL 
specification, although I note that OpenCL doesn't permit scalar << vector 
or scalar >> vector.

Say one operand is a scalar.  There doesn't appear to be much coverage of 
this case in the testcases added.  If there is a scalar shift amount, 
where you say:

> +  /* For 'vector <shift> scalar' or 'scalar <shift> vector', we convert 
> +     a scalar to a vector. Truncating the shift amount is ok.  */

then indeed this truncation is OK, because the only times the value will 
be affected are cases where the shift amount would be out of range and 
there would be undefined behavior (in C).  But if you are shifting a 
scalar by a vector, say 0x12345678 << (vector unsigned char){1,1,1,1}, 
then converting the scalar to the type of the vector elements seems 
inappropriate and risky.  It would at least require the use of 
convert_and_check so appropriate warnings can be given, but it would seem 
better to disallow this case, as in OpenCL.  If allowed then you'd want 
the result to be a vector whose element type is the type of the LHS of the 
shift - but C promotions would prevent the LHS from having types such as 
char and short.

> +  if ((code0 == VECTOR_TYPE || code1 == VECTOR_TYPE)
> +      && (code0 != code1))
> +    {
> +      switch (code)
> +        {
> +          case RSHIFT_EXPR:
> +          case LSHIFT_EXPR:
> +            if (code0 == INTEGER_TYPE)
> +              {
> +                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);
> +              }
> +            break;

If you do disallow such shifts this code could go away - but why are you 
allowing in this particular place only for scalars shifted by a vector 
amount and not for vectors shifted by a scalar amount?  Where is the code 
handling vectors shifted by scalars?
Artem Shinkarov Oct. 27, 2010, 11:35 a.m. UTC | #2
On Tue, Oct 26, 2010 at 4:15 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Mon, 25 Oct 2010, Artem Shinkarov wrote:
>
>> Index: gcc/doc/extend.texi
>> ===================================================================
>> --- gcc/doc/extend.texi       (revision 165913)
>> +++ gcc/doc/extend.texi       (working copy)
>> @@ -6309,6 +6309,23 @@ v4si a, b, c;
>>  c = a + b;
>>  @end smallexample
>>
>> +In C it is possible to use shifting operators @code{<<, >>} on integer-type
>> +vectors. The operation is defined as following: @code{@{a0, a1, ..., an@} >> @{b0, b1,
>> +..., bn@} == @{a0 >> b0, a1 >> b1, ..., an >> bn@}}@.  Additionally one of the
>
> The "..." here should be @dots{} since it is not the literal C token
> "...".

Thanks, fixed.

>
>> +operands can be a scalar integer in which case the scalar is converted to the
>> +type used by the vector operand and each element of this new vector is the
>> +scalar's value.  Consider the following code.
>
> Most of my comments relate to the scalar case which seems more potentially
> problematic than the case where both operands are vectors.  But in the
> case where both operands are vectors I note you say nothing about
> permitted types of the two operands.  Are they required to be exactly the
> same?  Or can they differ in signedness?  In the width of elements of the
> vector?

In case when both operands are vectors my patch requires that they are
both integer-typed and that the number of elements is the same. On the
other hand, the existing code c-typeck.c:(build_binary_op):10048

  if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
      && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
	  || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
						    TREE_TYPE (type1))))
    {
      binary_op_error (location, code, type0, type1);
      return error_mark_node;
    }

requires that the base type of the vector has the same width.

>
> In normal C without vectors, the types of the two operands of a shift are
> independent.  This would tend to suggest that this should be the case for
> vectors - they must have the same number of elements, but why constrain
> things further?  I didn't see any such constraint in the OpenCL
> specification, although I note that OpenCL doesn't permit scalar << vector
> or scalar >> vector.

Again, I agree, but then we should do the same stuff for operations +,
-, *, /, ...
because we can have an expression in C like: <int> + <char> * <short>
and the type inference would do the job.
On the other hand if we allow that, then most likely most of our
vector operations will be expanded and would not reach the hardware.
And I think that one of the purpose of these vector extensions is to
build an interface for CPU SIMD instructions. So this is a sort of
political decision we want to make.

My thinking here was that we leave the patch as is, and if later we
will decide that we want to support vector(8) char <op> vector(8)
short, we would just remove the constraint and my patch would still
work.

>
> Say one operand is a scalar.  There doesn't appear to be much coverage of
> this case in the testcases added.  If there is a scalar shift amount,
> where you say:
>
>> +  /* For 'vector <shift> scalar' or 'scalar <shift> vector', we convert
>> +     a scalar to a vector. Truncating the shift amount is ok.  */
>
> then indeed this truncation is OK, because the only times the value will
> be affected are cases where the shift amount would be out of range and
> there would be undefined behavior (in C).  But if you are shifting a
> scalar by a vector, say 0x12345678 << (vector unsigned char){1,1,1,1},
> then converting the scalar to the type of the vector elements seems
> inappropriate and risky.  It would at least require the use of
> convert_and_check so appropriate warnings can be given, but it would seem
> better to disallow this case, as in OpenCL.  If allowed then you'd want
> the result to be a vector whose element type is the type of the LHS of the
> shift - but C promotions would prevent the LHS from having types such as
> char and short.

OpenCL allows scalar <op> vector for most of the arithmetic
operations, so I thought that it would be nice to have this for shifts
as well, considering the fact that vector shift where the second
operator is a scalar is ok.

I don't see how the conversion of the expression 0x12345678 <<
{1,1,1,1} in compile time is different from the conversion of the
expression:
vector int x = (vector int){0x12345678, 0x123456778, ...} << {1,1,1,1}
which is allowed. Ok, in that case we will get warnings if -Woferflow
is on.

But in the case:
long long x;
vecor(8) short v0 = {...};
v0 = (vector(8) short){x,x,...} << v0;
we would not get any warnings and we will have the same behaviour as in my case.
And of course I can use convert_and_check instead of just convert.

>
>> +  if ((code0 == VECTOR_TYPE || code1 == VECTOR_TYPE)
>> +      && (code0 != code1))
>> +    {
>> +      switch (code)
>> +        {
>> +          case RSHIFT_EXPR:
>> +          case LSHIFT_EXPR:
>> +            if (code0 == INTEGER_TYPE)
>> +              {
>> +                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);
>> +              }
>> +            break;
>
> If you do disallow such shifts this code could go away - but why are you
> allowing in this particular place only for scalars shifted by a vector
> amount and not for vectors shifted by a scalar amount?  Where is the code
> handling vectors shifted by scalars?

The code is in the case  {RL}SHIFT_EXPR: branches. The thing is that
middleend happily accepts the expression vector >> scalar and vector
<< scalar. That is why I don't have to do anything there, just to
build that expression.

>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

So who is taking the political decision about the binary operation on
vectors of different width?
Nathan Froyd Oct. 27, 2010, 12:15 p.m. UTC | #3
On Mon, Oct 25, 2010 at 06:15:40PM +0100, Artem Shinkarov wrote:
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c	(revision 165913)
> +++ gcc/tree.c	(working copy)
> @@ -1366,6 +1366,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 (tree vectype, tree sc) 
> +{
> +  int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
> +  VEC(constructor_elt, gc) *v = NULL;
> +
> +  if (sc == error_mark_node)
> +    return sc;
> +
> +  gcc_assert (TREE_TYPE (sc) == TREE_TYPE (vectype));
> +
> +  v = VEC_alloc (constructor_elt, gc, nunits);
> +  for (i = 0; i < nunits; ++i)
> +    CONSTRUCTOR_APPEND_ELT (v, size_int (i), sc);
                                  ^^^^^^^^^^^^

Passing this is not necessary and is wrong when you would need to call
build_constructor.  Please pass NULL_TREE here.

-Nathan
Joseph Myers Oct. 27, 2010, 12:21 p.m. UTC | #4
On Wed, 27 Oct 2010, Artem Shinkarov wrote:

> > Most of my comments relate to the scalar case which seems more potentially
> > problematic than the case where both operands are vectors.  But in the
> > case where both operands are vectors I note you say nothing about
> > permitted types of the two operands.  Are they required to be exactly the
> > same?  Or can they differ in signedness?  In the width of elements of the
> > vector?
> 
> In case when both operands are vectors my patch requires that they are
> both integer-typed and that the number of elements is the same. On the
> other hand, the existing code c-typeck.c:(build_binary_op):10048
> 
>   if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
>       && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
> 	  || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
> 						    TREE_TYPE (type1))))
>     {
>       binary_op_error (location, code, type0, type1);
>       return error_mark_node;
>     }
> 
> requires that the base type of the vector has the same width.

But shouldn't the documentation make this explicit for shifts?

There's a general statement in the documentation already that both length 
and signedness must match - but you're describing shifts specially so it 
may not be clear what general statements apply to them.  And why is your 
paragraph about shifts going in between an example for addition, and a 
statement that "Subtraction, multiplication, division, and the logical 
operations operate in a similar manner." - that is, in a similar manner to 
addition?  The effect would seem to be to change the meaning of "similar" 
to refer to shifts rather than addition.  That doesn't seem to be a good 
idea.  Work out what the documentation should look like for the extension 
as a coherent whole, and it might be clearer what if any new statement 
about types is needed.

> > In normal C without vectors, the types of the two operands of a shift are
> > independent.  This would tend to suggest that this should be the case for
> > vectors - they must have the same number of elements, but why constrain
> > things further?  I didn't see any such constraint in the OpenCL
> > specification, although I note that OpenCL doesn't permit scalar << vector
> > or scalar >> vector.
> 
> Again, I agree, but then we should do the same stuff for operations +,
> -, *, /, ...
> because we can have an expression in C like: <int> + <char> * <short>
> and the type inference would do the job.

In C, the integer promotions apply to operands of both + and <<.  For 
vector operations they are deliberately excluded - you can operate on 
vector char, but not directly on char.

However, in C the *usual arithmetic conversions* (a superset of the 
integer promotions) apply for + but not <<; there is no requirement to 
form a common type as there is for arithmetic operations.  So the general 
vector rules appear to be being expanded to say:

* no integer promotions

* no usual arithmetic conversions

* must have a common type for vectors (without such promotions / 
conversions) even for shifts when ISO C doesn't require a common type for 
scalars

> OpenCL allows scalar <op> vector for most of the arithmetic
> operations, so I thought that it would be nice to have this for shifts
> as well, considering the fact that vector shift where the second
> operator is a scalar is ok.
> 
> I don't see how the conversion of the expression 0x12345678 <<
> {1,1,1,1} in compile time is different from the conversion of the
> expression:
> vector int x = (vector int){0x12345678, 0x123456778, ...} << {1,1,1,1}
> which is allowed. Ok, in that case we will get warnings if -Woferflow
> is on.

The point I had was when the shift amount was vector char - so if you 
convert the LHS to the type of the RHS then you have (vector char){0x78, 
0x78, 0x78, 0x78}.  Truncating a scalar like that seems a further step 
beyond the rules listed above, and it doesn't seem a particularly 
desirable step to me.
diff mbox

Patch

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 165913)
+++ gcc/doc/extend.texi	(working copy)
@@ -6309,6 +6309,23 @@  v4si a, b, c;
 c = a + b;
 @end smallexample
 
+In C it is possible to use shifting operators @code{<<, >>} on integer-type
+vectors. The operation is defined as following: @code{@{a0, a1, ..., an@} >> @{b0, b1,
+..., bn@} == @{a0 >> b0, a1 >> b1, ..., an >> bn@}}@.  Additionally one of the
+operands can be a scalar integer in which case the scalar is converted to the
+type used by the vector operand and each element of this new vector is the
+scalar's value.  Consider the following code.
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a, b, c;
+int i = 1;
+
+b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+c = 1 << a;     /* c = @{1,1,1,1@} << a; */
+@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 165913)
+++ gcc/tree.c	(working copy)
@@ -1366,6 +1366,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 (tree vectype, tree sc) 
+{
+  int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
+  VEC(constructor_elt, gc) *v = NULL;
+
+  if (sc == error_mark_node)
+    return sc;
+
+  gcc_assert (TREE_TYPE (sc) == TREE_TYPE (vectype));
+
+  v = VEC_alloc (constructor_elt, gc, nunits);
+  for (i = 0; i < nunits; ++i)
+    CONSTRUCTOR_APPEND_ELT (v, size_int (i), sc);
+
+  if (CONSTANT_CLASS_P (sc))
+    return build_vector_from_ctor (vectype, v);
+  else 
+    return build_constructor (vectype, v);
+}
+
 /* 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 165913)
+++ gcc/tree.h	(working copy)
@@ -4034,6 +4034,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 (tree, 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/vector-shift2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-shift2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-shift2.c	(revision 0)
@@ -0,0 +1,60 @@ 
+/* dg-do run */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+#define uint unsigned int
+
+int main (int argc, char *argv[]) {
+    vector(4, uint) vuint  = { 1,  2,  3,  4};
+    vector(4,  int) vint0  = { 1,  1,  1,  1};
+    vector(4,  int) vint1  = {-1, -1, -1, -1};
+
+    vector(4,  int) i1, i2, i3;
+    vector(4, uint) u1, u2, u3;
+
+    i1 = vint1<< vint0;
+    
+    if (vidx(int, i1, 0) != ((int)-1 << (int)1))
+        __builtin_abort ();
+    if (vidx(int, i1, 1) != ((int)-1 << (int)1))
+        __builtin_abort ();
+    if (vidx(int, i1, 2) != ((int)-1 << (int)1))
+        __builtin_abort ();
+    if (vidx(int, i1, 3) != ((int)-1 << (int)1))
+        __builtin_abort ();
+
+    u1 = vuint << vint0;
+
+    if (vidx(int, u1, 0) != ((uint)1  << (int)1))
+        __builtin_abort ();
+    if (vidx(int, u1, 1) != ((uint)2  << (int)1))
+        __builtin_abort ();
+    if (vidx(int, u1, 2) != ((uint)3  << (int)1))
+        __builtin_abort ();
+    if (vidx(int, u1, 3) != ((uint)4  << (int)1))
+        __builtin_abort ();
+
+    
+    i2 = vint1 >> vuint;
+
+    if (vidx(int, i2, 0) != ((int)-1  >> (uint)1))
+        __builtin_abort ();
+    if (vidx(int, i2, 1) != ((int)-1  >> (uint)2))
+        __builtin_abort ();
+    if (vidx(int, i2, 2) != ((int)-1  >> (uint)3))
+        __builtin_abort ();
+    if (vidx(int, i2, 3) != ((int)-1  >> (uint)4))
+        __builtin_abort ();
+
+
+    vint1 >>= vuint;
+    
+    vuint <<= vint0;
+    vuint <<= vint1;
+
+
+    return 0;
+}
+
+
Index: gcc/testsuite/gcc.c-torture/execute/vector-shift.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-shift.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-shift.c	(revision 0)
@@ -0,0 +1,48 @@ 
+
+#define vector __attribute__((vector_size(sizeof(int)*4) ))
+
+static vector int allones = {1, 1, 1, 1};
+static vector int allzeros = {0, 0, 0, 0};
+static vector int numbers = {0, 1, 2, 3};
+static vector int numbersleftshiftallones = {0, 2, 4, 6};
+static vector int numbersrightshiftallones = {0, 0, 1, 1};
+
+
+static vector unsigned int uallones = {1, 1, 1, 1};
+static vector unsigned int uallzeros = {0, 0, 0, 0};
+static vector unsigned int unumbers = {0, 1, 2, 3};
+static vector unsigned int unumbersleftshiftallones = {0, 2, 4, 6};
+static vector unsigned int unumbersrightshiftallones = {0, 0, 1, 1};
+
+#define TEST(result, expected) \
+do { \
+  typeof(result) result1 = result; \
+  if(sizeof (result1) != sizeof (expected)) \
+    __builtin_abort (); \
+  if (__builtin_memcmp (&result1, &expected, sizeof(result1)) != 0) \
+    __builtin_abort (); \
+}while (0);
+
+int main(void)
+{
+  vector int result;
+  TEST ((numbers << allzeros), numbers);
+  TEST ((numbers >> allzeros), numbers);
+  TEST((numbers << allones), numbersleftshiftallones);
+  TEST((numbers >> allones), numbersrightshiftallones);
+  /* Test left shift followed by a right shift, numbers should be back as
+     numbers are all small numbers and no lose of precision happens.   */
+  TEST((numbers << allones) >> allones, numbers);
+  
+  
+  
+  TEST ((unumbers << uallzeros), unumbers);
+  TEST ((unumbers >> uallzeros), unumbers);
+  TEST((unumbers << uallones), unumbersleftshiftallones);
+  TEST((unumbers >> uallones), unumbersrightshiftallones);
+  /* Test left shift followed by a right shift, numbers should be back as
+     numbers are all small numbers and no lose of precision happens.   */
+  TEST((unumbers << uallones) >> uallones, unumbers);
+
+  return 0;  
+}
Index: gcc/testsuite/gcc.c-torture/execute/vector-shift1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-shift1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-shift1.c	(revision 0)
@@ -0,0 +1,17 @@ 
+#define vector __attribute__((vector_size(8*sizeof(short))))
+
+int main (int argc, char *argv[]) {
+  vector short v0 = {argc,2,3,4,5,6,7};
+  vector short v1 = {2,2,2,2,2,2,2};
+  vector short r1,r2,r3,r4;
+  int i = 8;
+
+  r1 = v0 << 1;
+  r2 = 1 << v0;
+
+  r3 = v0 << v1;
+  r4 = v0 >> v1;
+
+  return 0;
+}
+
Index: gcc/testsuite/gcc.dg/vector-shift4.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-shift4.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vector-shift4.c	(revision 0)
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc,2,3,4,5,6,7};
+    short sc;
+
+    v0 >>= scalar0; /* { dg-error ".*scalar0.*undeclared" } */
+    
+    return 0;
+}
+
Index: gcc/testsuite/gcc.dg/vector-shift.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-shift.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vector-shift.c	(revision 0)
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+int main (int argc, char *argv[]) {
+    vector(4,char) vchar = {1,2,3,4};
+    vector(4, int) vint  = {1,1,1,1};
+    
+    vint <<= vchar;  /* { dg-error "nvalid operands to binary <<" } */
+    vchar >>= vint;  /* { dg-error "nvalid operands to binary >>" } */
+
+    return 0;
+}
+
Index: gcc/testsuite/gcc.dg/vector-shift1.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-shift1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vector-shift1.c	(revision 0)
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+int main (int argc, char *argv[]) {
+    vector(4, float) vfloat0 = {1., 2., 3., 4.};
+    vector(4, float) vfloat1 = {1., 2., 3., 4.};
+    
+    vector(4,   int) vint   = {1,  1,  1,  1 };
+    
+    vint <<= vfloat0;  /* { dg-error "nvalid operands to binary <<" } */
+    vfloat0 >>= vint;  /* { dg-error "nvalid operands to binary >>" } */
+
+    vfloat0 <<= vfloat1;  /* { dg-error "nvalid operands to binary <<" } */
+
+    return 0;
+}
+
Index: gcc/testsuite/gcc.dg/vector-shift2.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-shift2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vector-shift2.c	(revision 0)
@@ -0,0 +1,61 @@ 
+/* { dg-do run } */
+/* { dg-options "-fno-var-tracking-assignments" } */
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*((type *) &(vec) + idx))
+#define uchar unsigned char
+
+#define ch14 1,2,3,4
+#define ch1  1,1,1,1
+#define chm1 -1,-1,-1,-1
+
+int main (int argc, char *argv[]) {
+    vector(16, uchar) vuchar  = { ch14, ch14, ch14, ch14};
+    vector(16,  char) vchar0  = { ch1, ch1, ch1, ch1};
+    vector(16,  char) vchar1  = { chm1, chm1, chm1, chm1};
+
+    vector(16,  char) i1, i2, i3;
+    vector(16, uchar) u1, u2, u3;
+
+    i1 = vchar1<< vchar0;
+    
+    if (vidx(char, i1, 0) != ((char)-1 << (char)1))
+        __builtin_abort ();
+    if (vidx(char, i1, 1) != ((char)-1 << (char)1))
+        __builtin_abort ();
+    if (vidx(char, i1, 2) != ((char)-1 << (char)1))
+        __builtin_abort ();
+    if (vidx(char, i1, 3) != ((char)-1 << (char)1))
+        __builtin_abort ();
+    u1 = vuchar << vchar0;
+
+    if (vidx(char, u1, 0) != ((uchar)1  << (char)1))
+        __builtin_abort ();
+    if (vidx(char, u1, 1) != ((uchar)2  << (char)1))
+        __builtin_abort ();
+    if (vidx(char, u1, 2) != ((uchar)3  << (char)1))
+        __builtin_abort ();
+    if (vidx(char, u1, 3) != ((uchar)4  << (char)1))
+        __builtin_abort ();
+
+    
+    i2 = vchar1 >> vuchar;
+
+    if (vidx(char, i2, 0) != ((char)-1  >> (uchar)1))
+        __builtin_abort ();
+    if (vidx(char, i2, 1) != ((char)-1  >> (uchar)2))
+        __builtin_abort ();
+    if (vidx(char, i2, 2) != ((char)-1  >> (uchar)3))
+        __builtin_abort ();
+    if (vidx(char, i2, 3) != ((char)-1  >> (uchar)4))
+        __builtin_abort ();
+    
+    vchar1 >>= vuchar;
+    vuchar <<= vchar0;
+    vuchar <<= vchar1;
+
+    return 0;
+}
+
Index: gcc/testsuite/gcc.dg/vector-shift3.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-shift3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vector-shift3.c	(revision 0)
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+
+int main (int argc, char *argv[]) {
+    vector(8, short) v0 = {argc,2,3,4,5,6,7};
+    short sc;
+
+    
+    scalar1 <<= v0; /* { dg-error ".*scalar1.*undeclared" } */
+   
+    return 0;
+}
+
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 165913)
+++ gcc/c-typeck.c	(working copy)
@@ -9565,6 +9565,30 @@  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))
+    {
+      switch (code)
+        {
+          case RSHIFT_EXPR:
+          case LSHIFT_EXPR:
+            if (code0 == INTEGER_TYPE)
+              {
+                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);
+              }
+            break;
+
+          default:
+            break;
+        }
+    }
+
   switch (code)
     {
     case PLUS_EXPR:
@@ -9727,7 +9751,21 @@  build_binary_op (location_t location, en
 	 Also set SHORT_SHIFT if shifting rightward.  */
 
     case RSHIFT_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+      if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+        {
+          result_type = type0;
+          converted = 1;
+        }
+      else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+          && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+	{
+	  result_type = type0;
+	  converted = 1;
+	}
+      else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
 	  && code1 == INTEGER_TYPE)
 	{
 	  if (TREE_CODE (op1) == INTEGER_CST)
@@ -9754,9 +9792,10 @@  build_binary_op (location_t location, en
 
 	  /* Use the type of the value to be shifted.  */
 	  result_type = type0;
-	  /* Convert the shift-count to an integer, regardless of size
-	     of value being shifted.  */
-	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+	  /* Convert the non vector shift-count to an integer, regardless
+	     of size of value being shifted.  */
+	  if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+	      && TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
 	    op1 = convert (integer_type_node, op1);
 	  /* Avoid converting op1 to result_type later.  */
 	  converted = 1;
@@ -9764,7 +9803,21 @@  build_binary_op (location_t location, en
       break;
 
     case LSHIFT_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+      if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
+        {
+          result_type = type0;
+          converted = 1;
+        }
+      else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+          && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+	{
+	  result_type = type0;
+	  converted = 1;
+	}
+      else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
 	  && code1 == INTEGER_TYPE)
 	{
 	  if (TREE_CODE (op1) == INTEGER_CST)
@@ -9786,9 +9839,10 @@  build_binary_op (location_t location, en
 
 	  /* Use the type of the value to be shifted.  */
 	  result_type = type0;
-	  /* Convert the shift-count to an integer, regardless of size
-	     of value being shifted.  */
-	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+	  /* Convert the non vector shift-count to an integer, regardless
+	     of size of value being shifted.  */
+	  if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+	      && TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
 	    op1 = convert (integer_type_node, op1);
 	  /* Avoid converting op1 to result_type later.  */
 	  converted = 1;