From patchwork Sat Aug 14 16:37:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Artem Shinkarov X-Patchwork-Id: 61732 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 34B63B70D0 for ; Sun, 15 Aug 2010 02:39:07 +1000 (EST) Received: (qmail 10030 invoked by alias); 14 Aug 2010 16:39:05 -0000 Received: (qmail 10019 invoked by uid 22791); 14 Aug 2010 16:39:02 -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, T_TO_NO_BRKTS_FREEMAIL 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; Sat, 14 Aug 2010 16:38:12 +0000 Received: by qyk5 with SMTP id 5so993852qyk.20 for ; Sat, 14 Aug 2010 09:38:10 -0700 (PDT) Received: by 10.224.78.148 with SMTP id l20mr1958171qak.388.1281803890226; Sat, 14 Aug 2010 09:38:10 -0700 (PDT) MIME-Version: 1.0 Received: by 10.229.66.165 with HTTP; Sat, 14 Aug 2010 09:37:50 -0700 (PDT) From: Artem Shinkarov Date: Sat, 14 Aug 2010 17:37:50 +0100 Message-ID: Subject: Scalar vector binary operation To: gcc-patches@gcc.gnu.org Cc: Richard Guenther 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 This patch allows to write a vector binary expression where one operand is a scalar. This is done according to the OpenCL standard. The scalar operand in the expression is converted to the vector where each element is the scalar form the expression. We check whether the scalar fits in the type of vector element. ChangeLog: 2010-06-18 Artem Shinkarov /gcc * tree.c (build_vector_from_val): Build vector from scalar * tree.h (build_vector_from_val): New declaration * 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. /gcc/testsuite * gcc.c-torture/execute/scal-to-vec1.c: New test. * gcc.dg/scal-to-vec1.c: New test. /gcc/doc * extend.texi: Adjust bootstrapped and tested on x86_64_unknown-linux Artem Shinkarov Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 163244) +++ gcc/doc/extend.texi (working copy) @@ -6135,6 +6135,25 @@ v4si a, b, c; c = a + b; @end smallexample +For the convenience 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, c; +long l; + +a = b + 1; /* a = b + {1,1,1,1}; */ +a = 2 * b; /* a = {2,2,2,2} * b; */ + +a = l + a; /* Error, cannot convert long to int. */ +@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 163244) +++ gcc/tree.c (working copy) @@ -1358,6 +1358,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 (const tree sc, const tree vectype) +{ + tree t = NULL_TREE; + int i, nunits = TYPE_VECTOR_SUBPARTS (vectype); + + if (sc == error_mark_node) + return sc; + + gcc_assert (TREE_TYPE (sc) == TREE_TYPE (vectype)); + + for (i = 0; i < nunits; ++i) + t = tree_cons (NULL_TREE, sc, t); + + if (CONSTANT_CLASS_P (sc)) + return build_vector (vectype, t); + else + return build_constructor_from_list (vectype, t); +} + + /* 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 163244) +++ gcc/tree.h (working copy) @@ -4027,6 +4027,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 (const tree, const 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/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,77 @@ +#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 = 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,25 @@ +/* { dg-do compile } */ +#define vector(elcount, type) \ +__attribute__((vector_size((elcount)*sizeof(type)))) type + +#define vidx(type, vec, idx) (*((type *) &(vec) + idx)) + + +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; + + int i = 12; + double d = 3.; + + v1 = i + v0; /* { dg-error "" } */ + v1 = 99999 + v0; /* { dg-error "" } */ + + f1 = d + f0; /* { dg-error "" } */ + f1 = 1.3 + f0; /* { dg-error "" } */ + + return 0; +} Index: gcc/c-typeck.c =================================================================== --- gcc/c-typeck.c (revision 163244) +++ gcc/c-typeck.c (working copy) @@ -9196,6 +9196,102 @@ push_cleanup (tree decl, tree cleanup, b TREE_OPERAND (stmt, 0) = list; STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; } + +/* Check whether expression EXPR can be converted to the TYPE, + considering the case when EXPR is a constant. */ +static inline bool +expr_fits_type_p (const tree expr, const 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 inline int +scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1) +{ +#define MSG "Conversion of scalar to vector involves truncation" +#define MSG_FLOAT "Truncating floating point constant to vector " \ + "precision does not preserve value" +#define ERROR(MSG, LOC, RET) { error_at (LOC, MSG); return RET; } + + tree type0 = TREE_TYPE (op0); + tree type1 = TREE_TYPE (op1); + enum tree_code code0 = TREE_CODE (type0); + enum tree_code code1 = TREE_CODE (type1); + + switch (code) + { + case RSHIFT_EXPR: + case LSHIFT_EXPR: + if (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE) + return 0; + + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case RDIV_EXPR: + if (code0 == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) + { + if (!expr_fits_type_p (op0, type1)) + ERROR (MSG, loc, -2); + return 0; + } + else if (code1 == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE) + { + if (!expr_fits_type_p (op1, type0)) + ERROR (MSG, loc, -2); + return 1; + } + + else if (code0 == REAL_TYPE + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1))) + { + if (!expr_fits_type_p (op0, type1)) + ERROR (MSG_FLOAT, loc, -2); + return 0; + } + else if (code1 == REAL_TYPE + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type0))) + { + if (!expr_fits_type_p (op1, type0)) + ERROR (MSG_FLOAT, loc, -2); + return 1; + } + default: + break; + } + + return -1; +} /* Build a binary-operation expression without default conversions. CODE is the kind of expression to build. @@ -9375,6 +9471,35 @@ 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)) + { + int convert_flag = scalar_to_vector (location, code, op0, op1); + + if (convert_flag == -2) + return error_mark_node; + else if (convert_flag == 0) + { + tree sc = save_expr(op0); + sc = convert (TREE_TYPE (type1), sc); + op0 = build_vector_from_val (sc, type1); + orig_type0 = type0 = TREE_TYPE (op0); + code0 = TREE_CODE (type0); + converted = 1; + } + else if (convert_flag == 1) + { + tree sc = save_expr(op1); + sc = convert (TREE_TYPE (type0), sc); + op1 = build_vector_from_val (sc, type0); + orig_type1 = type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + converted = 1; + } + } + switch (code) { case PLUS_EXPR: