diff mbox

Vector shifting patch

Message ID AANLkTinnbz+gtcbBmzG0FiFdniLdAbgr_ojdX3wWLOTW@mail.gmail.com
State New
Headers show

Commit Message

Artem Shinkarov Oct. 28, 2010, 10:22 a.m. UTC
On Wed, Oct 27, 2010 at 10:14 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Wed, 27 Oct 2010, Artem Shinkarov wrote:
>
>> Ok, then here are vector shifts only.
>
> This version is getting closer:
>
>> +In C it is possible to use shifting operators @code{<<, >>} on integer-type
>
> The comma should be outside @code: @code{<<}, @code{>>}.

Fixed.

>
>> 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 */
>
> dg- directives have no effect in gcc.c-torture/execute, and if they were
> to have an effect they'd need to be properly marked up: { dg-do run }.

Fixed. That was the copying issue.

>
>> 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" } */
>
> Why this option?  It seems to have no relation to the test.

This option is because of the bug:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44569

If you compile the code from gcc/testsuite/gcc.dg/vector-shift2.c with
combination "-g -O3" then you will have a compiler internal error. But
this error has nothing to do with this patch.

>
> Apart from that the C front-end changes seem OK.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

Richard, could you please submit the patch?



Artem.

Comments

Richard Biener Oct. 29, 2010, 3:07 p.m. UTC | #1
On Thu, Oct 28, 2010 at 12:22 PM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> On Wed, Oct 27, 2010 at 10:14 PM, Joseph S. Myers
> <joseph@codesourcery.com> wrote:
>> On Wed, 27 Oct 2010, Artem Shinkarov wrote:
>>
>>> Ok, then here are vector shifts only.
>>
>> This version is getting closer:
>>
>>> +In C it is possible to use shifting operators @code{<<, >>} on integer-type
>>
>> The comma should be outside @code: @code{<<}, @code{>>}.
>
> Fixed.
>
>>
>>> 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 */
>>
>> dg- directives have no effect in gcc.c-torture/execute, and if they were
>> to have an effect they'd need to be properly marked up: { dg-do run }.
>
> Fixed. That was the copying issue.
>
>>
>>> 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" } */
>>
>> Why this option?  It seems to have no relation to the test.
>
> This option is because of the bug:
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44569
>
> If you compile the code from gcc/testsuite/gcc.dg/vector-shift2.c with
> combination "-g -O3" then you will have a compiler internal error. But
> this error has nothing to do with this patch.
>
>>
>> Apart from that the C front-end changes seem OK.
>>
>> --
>> Joseph S. Myers
>> joseph@codesourcery.com
>>
>
> Richard, could you please submit the patch?

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied as rev. 166061.

I had to fix gcc.dg/simd-1b.c which was testing for error on a now valid
vector - vector shift.  I also removed the -fno-var-tracking-assignments flag
and moved the testcase to the torture.

As of mixed shifts I think vector <<>> scalar is an obvious thing to support
as we do have both direct middle-end and target support for these.  For
scalar <<>> vector shifts we can't really allow truncation for scalar.
 So I think
with mixed scalar vector operations we have a third thing similar to
C integer promotions and C usual arithmetic conversions, namely vector
promotion rules which basically would say that for mixed scalar, vector
operands this promotion promotes the scalar to a vector with the same
number of elements as the other vector.  Now the question is whether
(and where) we would need to enforce that the resulting vector mode
is of the same size.  Considering

char c;
int i;
c << (vector int){1, 2, 3, 4};

which either would produce v4qi << v4si giving a v4qi result or
v4si << v4si giving a v4si result.  I _think_ the former makes more
sense from a language point of view (but is not nice to the target
support code which would prefer a v4si result).

I think we should deal with scalar <<>> vector and vector <<>> scalar
separately.

Richard.
diff mbox

Patch

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 165913)
+++ gcc/doc/extend.texi	(working copy)
@@ -6315,6 +6315,24 @@  minus or complement operators on a vecto
 elements are the negative or complemented values of the corresponding
 elements in the operand.
 
+In C it is possible to use shifting operators @code{<<}, @code{>>} on
+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.
+Consider the following code.
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a, b;
+
+b = a >> 1;     /* b = a >> @{1,1,1,1@}; */
+@end smallexample
+
 In C vectors can be subscripted as if the vector were an array with
 the same number of elements and base type.  Out of bound accesses
 invoke undefined behavior at runtime.  Warnings for out of bound
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, NULL_TREE, 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,59 @@ 
+#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 = v0 >> 1;
+
+  r3 = v0 << v1;
+  r4 = v0 >> v1;
+
+  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)
@@ -9727,7 +9727,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 +9768,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 +9779,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 +9815,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;