From patchwork Mon Oct 25 17:15:40 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Artem Shinkarov X-Patchwork-Id: 69179 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id DF889B70B8 for ; Tue, 26 Oct 2010 17:15:49 +1100 (EST) Received: (qmail 30793 invoked by alias); 26 Oct 2010 06:15:46 -0000 Received: (qmail 30776 invoked by uid 22791); 26 Oct 2010 06:15:40 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, TW_BJ, TW_VF X-Spam-Check-By: sourceware.org Received: from mail-qw0-f47.google.com (HELO mail-qw0-f47.google.com) (209.85.216.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 26 Oct 2010 06:15:33 +0000 Received: by qwd6 with SMTP id 6so2212940qwd.20 for ; Mon, 25 Oct 2010 23:15:31 -0700 (PDT) Received: by 10.229.213.212 with SMTP id gx20mr6249994qcb.60.1288026960670; Mon, 25 Oct 2010 10:16:00 -0700 (PDT) MIME-Version: 1.0 Received: by 10.229.182.207 with HTTP; Mon, 25 Oct 2010 10:15:40 -0700 (PDT) In-Reply-To: <20101025152737.GD2806@nightcrawler> References: <20101025144714.GZ2806@nightcrawler> <20101025150704.GC2806@nightcrawler> <20101025152737.GD2806@nightcrawler> From: Artem Shinkarov Date: Mon, 25 Oct 2010 18:15:40 +0100 Message-ID: Subject: Re: Vector shifting patch To: Nathan Froyd Cc: gcc-patches@gcc.gnu.org, Richard Guenther , "Joseph S. Myers" X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Here is a version with improved build_vector_from val. ChangeLog: 2010-10-25 Artjoms Sinkarovs Andrew Pinski 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 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 > 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 scalar' or 'scalar 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;