From patchwork Wed Nov 3 14:17:06 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Artem Shinkarov X-Patchwork-Id: 70007 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 D5389B70FC for ; Thu, 4 Nov 2010 01:17:44 +1100 (EST) Received: (qmail 346 invoked by alias); 3 Nov 2010 14:17:41 -0000 Received: (qmail 308 invoked by uid 22791); 3 Nov 2010 14:17:36 -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 X-Spam-Check-By: sourceware.org Received: from mail-qy0-f182.google.com (HELO mail-qy0-f182.google.com) (209.85.216.182) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 03 Nov 2010 14:17:28 +0000 Received: by qyk7 with SMTP id 7so15089qyk.20 for ; Wed, 03 Nov 2010 07:17:26 -0700 (PDT) Received: by 10.229.191.130 with SMTP id dm2mr9043234qcb.256.1288793846624; Wed, 03 Nov 2010 07:17:26 -0700 (PDT) MIME-Version: 1.0 Received: by 10.229.4.25 with HTTP; Wed, 3 Nov 2010 07:17:06 -0700 (PDT) In-Reply-To: References: From: Artem Shinkarov Date: Wed, 3 Nov 2010 14:17:06 +0000 Message-ID: Subject: Re: Scalar vector binary operation To: Richard Guenther Cc: gcc-patches@gcc.gnu.org, "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 ChangeLog: 2010-11-01 Artjoms Sinkarovs /gcc * c-typeck.c (expr_fits_type_p): New function. Check if expression fits into the type considering constants. (scalar_to_vector): New function. Try scalar to vector conversion. (build_binary_op): Adjust. * doc/extend.texi: Description of scalar to vector expansion. /gcc/testsuite * gcc.c-torture/execute/scal-to-vec1.c: New test. * gcc.dg/scal-to-vec1.c: New test. bootstrapped and tested on x86_64_unknown-linux On Wed, Nov 3, 2010 at 1:25 PM, Richard Guenther wrote: > On Mon, Nov 1, 2010 at 5:16 PM, Artem Shinkarov > wrote: >> This patch allows binary operations: "vector scalar" and "scalar >> vector" in which case scalar is converted into the vector type, >> if the scalar type fits in the vectors element type. >> >> ChangeLog: >> >> 2010-11-01  Artjoms Sinkarovs >> >>       /gcc >>       * tree.c (build_vector_from_val): Build vector from scalar >>       * tree.h (build_vector_from_val): New declaration > > Those are no longer part of this patch. > >>       * c-typeck.c (expr_fits_type_p): New function. Check if expression >>       fits into the type considering constants. >>       (scalar_to_vector): New function. Try scalar to vector conversion. >>       (build_binary_op): Adjust. >>       * doc/extend.texi: Description of scalar to vector expansion. >> >>       /gcc/testsuite >>       * gcc.c-torture/execute/scal-to-vec1.c: New test. >>       * gcc.dg/scal-to-vec1.c: New test. >> >> bootstrapped and tested on x86_64_unknown-linux > > +/* Check whether expression EXPR can be converted to the > +   vectortype TYPE, considering the case when EXPR is a constant.  */ > +static bool > +expr_fits_type_p (tree expr, tree type) > > "Return true if expression ..." > > also documents the return value.  I think the comment should be adjusted > to match the intent of the function, namely > > "... can be converted to TYPE preserving its value." > > Passing the element type as TYPE seems to be enough as well. > > The rationale is that OpenCL does not permit truncations to happen, > but people will write things like  float_vector + 2.0 (instead of 2.0f), > so we allow value-preserving truncations for QOI reasons. > > +#define SWAP(x, y) do { __typeof (x) __tmp = x; x = y; y = __tmp; } while (0) > > we don't usually define such thing but expand it everywhere needed. > > +            { > +              tree sc = save_expr(op0); > > space after save_expr, likewise below. > > Otherwise looks ok (but I've been looking at the patches before).  I can't > approve it though. > > Thanks, > Richard. > Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 166126) +++ gcc/doc/extend.texi (working copy) @@ -6319,18 +6319,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/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,79 @@ +#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 = 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.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,39 @@ +/* { 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" } */ + f1 = sint + f0; /* { dg-error "can't convert between vector values of different size" } */ + + + return 0; +} Index: gcc/c-typeck.c =================================================================== --- gcc/c-typeck.c (revision 166126) +++ gcc/c-typeck.c (working copy) @@ -9387,6 +9387,104 @@ push_cleanup (tree decl, tree cleanup, b TREE_OPERAND (stmt, 0) = list; STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; } + +/* Return true if expression EXPR can be converted to the + vectortype TYPE preserving its value. */ +static bool +expr_fits_type_p (tree expr, tree type) +{ + enum machine_mode mode = TYPE_MODE (TREE_TYPE (type)); + if (TYPE_MODE (TREE_TYPE (expr)) == mode) + return true; + + if (TREE_CODE (expr) == INTEGER_CST) + return int_fits_type_p (expr, TREE_TYPE (type)); + else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE) + return !tree_int_cst_lt + (TYPE_SIZE (TREE_TYPE (type)), + TYPE_SIZE (TREE_TYPE (expr))); + 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); + } + else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) + return (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) + <= GET_MODE_SIZE (mode)); + return false; +} + +/* Convert scalar to vector for the range of operations. + Function can return: + -2 -- Error ocured + -1 -- Nothing happened + 0 -- First argument must be expanded + 1 -- Second argument must be expanded */ +static int +scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1) +{ + tree type0 = TREE_TYPE (op0); + tree type1 = TREE_TYPE (op1); + int ret = 0; + + switch (code) + { + case RSHIFT_EXPR: + case LSHIFT_EXPR: + if (TREE_CODE (type0) == INTEGER_TYPE) + if (!expr_fits_type_p (op0, type1)) + { + error_at (loc, "Conversion of scalar to vector " + "involves truncation"); + return -2; + } + return 0; + + 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) + { + ret = 1; + tree tmp; + /* 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 (!expr_fits_type_p (op0, type1)) + { + error_at (loc, "Conversion of scalar to vector " + "involves truncation"); + return -2; + } + return ret; + } + else if (TREE_CODE (type0) == REAL_TYPE + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1))) + { + if (!expr_fits_type_p (op0, type1)) + { + error_at (loc, "Truncating floating point constant to " + "vector precision does not preserve value"); + return -2; + } + return ret; + } + default: + break; + } + + return -1; +} /* Build a binary-operation expression without default conversions. CODE is the kind of expression to build. @@ -9570,6 +9668,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)) + { + int convert_flag = scalar_to_vector (location, code, op0, op1); + + switch (convert_flag) + { + case -2: + return error_mark_node; + case 0: + { + 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 1: + { + 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: