From 0e3a99ae913c732f015b0dcfecb85d3236cc142f Mon Sep 17 00:00:00 2001 From: Artjoms Sinkarovs Date: Wed, 10 Aug 2011 14:44:02 +0000 Subject: [PATCH] c-typeck.c (scalar_to_vector): New function. 2011-08-10 Artjoms Sinkarovs * c-typeck.c (scalar_to_vector): New function. Try scalar to vector conversion. (stv_conv): New enum for scalar_to_vector return type. (build_binary_op): Adjust. * doc/extend.texi: Description of scalar to vector expansion. c-family/ * c-common.c (unsafe_conversion_p): New function. Check if it is unsafe to convert an expression to the type. (conversion_warning): Adjust, use unsafe_conversion_p. * c-common.h (unsafe_conversion_p): New function declaration. testsuite/ * gcc.c-torture/execute/scal-to-vec1.c: New test. * gcc.c-torture/execute/scal-to-vec2.c: New test. * gcc.c-torture/execute/scal-to-vec3.c: New test. * gcc.dg/scal-to-vec1.c: New test. * gcc.dg/scal-to-vec2.c: New test. From-SVN: r177622 --- gcc/ChangeLog | 8 + gcc/c-family/ChangeLog | 7 + gcc/c-family/c-common.c | 301 ++++++++++-------- gcc/c-family/c-common.h | 1 + gcc/c-typeck.c | 140 +++++++- gcc/doc/extend.texi | 19 +- gcc/testsuite/ChangeLog | 8 + .../gcc.c-torture/execute/scal-to-vec1.c | 85 +++++ .../gcc.c-torture/execute/scal-to-vec2.c | 62 ++++ .../gcc.c-torture/execute/scal-to-vec3.c | 48 +++ gcc/testsuite/gcc.dg/scal-to-vec1.c | 41 +++ gcc/testsuite/gcc.dg/scal-to-vec2.c | 16 + 12 files changed, 592 insertions(+), 144 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c create mode 100644 gcc/testsuite/gcc.dg/scal-to-vec1.c create mode 100644 gcc/testsuite/gcc.dg/scal-to-vec2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 33d7dbd93d1..7d5b49224b3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2011-08-10 Artjoms Sinkarovs + + * c-typeck.c (scalar_to_vector): New function. Try scalar to + vector conversion. + (stv_conv): New enum for scalar_to_vector return type. + (build_binary_op): Adjust. + * doc/extend.texi: Description of scalar to vector expansion. + 2011-08-10 Richard Guenther * tree.h (get_pointer_alignment): Remove max-align argument. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 91ed861b5b3..5f56369f3c3 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2011-08-10 Artjoms Sinkarovs + + * c-common.c (unsafe_conversion_p): New function. Check if it is + unsafe to convert an expression to the type. + (conversion_warning): Adjust, use unsafe_conversion_p. + * c-common.h (unsafe_conversion_p): New function declaration. + 2011-08-02 Jakub Jelinek * c-common.h (c_finish_omp_atomic): Adjust prototype. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 96275bac70a..1ef7e3c42e2 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -1922,143 +1922,92 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) return result_type; } -/* Warns if the conversion of EXPR to TYPE may alter a value. - This is a helper function for warnings_for_convert_and_check. */ - -static void -conversion_warning (tree type, tree expr) +/* Checks if expression EXPR of real/integer type cannot be converted + to the real/integer type TYPE. Function returns true when: + * EXPR is a constant which cannot be exactly converted to TYPE + * EXPR is not a constant and size of EXPR's type > than size of TYPE, + for EXPR type and TYPE being both integers or both real. + * EXPR is not a constant of real type and TYPE is an integer. + * EXPR is not a constant of integer type which cannot be + exactly converted to real type. + Function allows conversions between types of different signedness and + does not return true in that case. Function can produce signedness + warnings if PRODUCE_WARNS is true. */ +bool +unsafe_conversion_p (tree type, tree expr, bool produce_warns) { bool give_warning = false; - - int i; - const int expr_num_operands = TREE_OPERAND_LENGTH (expr); tree expr_type = TREE_TYPE (expr); location_t loc = EXPR_LOC_OR_HERE (expr); - if (!warn_conversion && !warn_sign_conversion) - return; - - /* If any operand is artificial, then this expression was generated - by the compiler and we do not warn. */ - for (i = 0; i < expr_num_operands; i++) - { - tree op = TREE_OPERAND (expr, i); - if (op && DECL_P (op) && DECL_ARTIFICIAL (op)) - return; - } - - switch (TREE_CODE (expr)) + if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST) { - case EQ_EXPR: - case NE_EXPR: - case LE_EXPR: - case GE_EXPR: - case LT_EXPR: - case GT_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_NOT_EXPR: - /* Conversion from boolean to a signed:1 bit-field (which only - can hold the values 0 and -1) doesn't lose information - but - it does change the value. */ - if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type)) - warning_at (loc, OPT_Wconversion, - "conversion to %qT from boolean expression", type); - return; - - case REAL_CST: - case INTEGER_CST: - /* Warn for real constant that is not an exact integer converted - to integer type. */ + to integer type. */ if (TREE_CODE (expr_type) == REAL_TYPE - && TREE_CODE (type) == INTEGER_TYPE) - { - if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type))) - give_warning = true; - } + && TREE_CODE (type) == INTEGER_TYPE) + { + if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type))) + give_warning = true; + } /* Warn for an integer constant that does not fit into integer type. */ else if (TREE_CODE (expr_type) == INTEGER_TYPE - && TREE_CODE (type) == INTEGER_TYPE - && !int_fits_type_p (expr, type)) - { - if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type) + && TREE_CODE (type) == INTEGER_TYPE + && !int_fits_type_p (expr, type)) + { + if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type) && tree_int_cst_sgn (expr) < 0) - warning_at (loc, OPT_Wsign_conversion, "negative integer" - " implicitly converted to unsigned type"); - else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type)) - warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned" - " constant value to negative integer"); + { + if (produce_warns) + warning_at (loc, OPT_Wsign_conversion, "negative integer" + " implicitly converted to unsigned type"); + } + else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type)) + { + if (produce_warns) + warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned" + " constant value to negative integer"); + } else give_warning = true; - } + } else if (TREE_CODE (type) == REAL_TYPE) - { - /* Warn for an integer constant that does not fit into real type. */ - if (TREE_CODE (expr_type) == INTEGER_TYPE) - { - REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr); - if (!exact_real_truncate (TYPE_MODE (type), &a)) - give_warning = true; - } - /* Warn for a real constant that does not fit into a smaller - real type. */ - else if (TREE_CODE (expr_type) == REAL_TYPE - && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) - { - REAL_VALUE_TYPE a = TREE_REAL_CST (expr); - if (!exact_real_truncate (TYPE_MODE (type), &a)) - give_warning = true; - } - } - - if (give_warning) - warning_at (loc, OPT_Wconversion, - "conversion to %qT alters %qT constant value", - type, expr_type); - - return; - - case COND_EXPR: - { - /* In case of COND_EXPR, if both operands are constants or - COND_EXPR, then we do not care about the type of COND_EXPR, - only about the conversion of each operand. */ - tree op1 = TREE_OPERAND (expr, 1); - tree op2 = TREE_OPERAND (expr, 2); - - if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST - || TREE_CODE (op1) == COND_EXPR) - && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST - || TREE_CODE (op2) == COND_EXPR)) - { - conversion_warning (type, op1); - conversion_warning (type, op2); - return; - } - /* Fall through. */ - } - - default: /* 'expr' is not a constant. */ - + { + /* Warn for an integer constant that does not fit into real type. */ + if (TREE_CODE (expr_type) == INTEGER_TYPE) + { + REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr); + if (!exact_real_truncate (TYPE_MODE (type), &a)) + give_warning = true; + } + /* Warn for a real constant that does not fit into a smaller + real type. */ + else if (TREE_CODE (expr_type) == REAL_TYPE + && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) + { + REAL_VALUE_TYPE a = TREE_REAL_CST (expr); + if (!exact_real_truncate (TYPE_MODE (type), &a)) + give_warning = true; + } + } + } + else + { /* Warn for real types converted to integer types. */ if (TREE_CODE (expr_type) == REAL_TYPE - && TREE_CODE (type) == INTEGER_TYPE) - give_warning = true; + && TREE_CODE (type) == INTEGER_TYPE) + give_warning = true; else if (TREE_CODE (expr_type) == INTEGER_TYPE - && TREE_CODE (type) == INTEGER_TYPE) - { + && TREE_CODE (type) == INTEGER_TYPE) + { /* Don't warn about unsigned char y = 0xff, x = (int) y; */ expr = get_unwidened (expr, 0); expr_type = TREE_TYPE (expr); /* Don't warn for short y; short x = ((int)y & 0xff); */ if (TREE_CODE (expr) == BIT_AND_EXPR - || TREE_CODE (expr) == BIT_IOR_EXPR + || TREE_CODE (expr) == BIT_IOR_EXPR || TREE_CODE (expr) == BIT_XOR_EXPR) { /* If both args were extended from a shortest type, @@ -2085,7 +2034,7 @@ conversion_warning (tree type, tree expr) && int_fits_type_p (op1, c_common_signed_type (type)) && int_fits_type_p (op1, c_common_unsigned_type (type)))) - return; + return false; /* If constant is unsigned and fits in the target type, then the result will also fit. */ else if ((TREE_CODE (op0) == INTEGER_CST @@ -2094,58 +2043,136 @@ conversion_warning (tree type, tree expr) || (TREE_CODE (op1) == INTEGER_CST && unsigned1 && int_fits_type_p (op1, type))) - return; + return false; } } - /* Warn for integer types converted to smaller integer types. */ + /* Warn for integer types converted to smaller integer types. */ if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) give_warning = true; /* When they are the same width but different signedness, then the value may change. */ - else if ((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type) + else if (((TYPE_PRECISION (type) == TYPE_PRECISION (expr_type) && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type)) /* Even when converted to a bigger type, if the type is unsigned but expr is signed, then negative values will be changed. */ - || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type))) + || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type))) + && produce_warns) warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT " "may change the sign of the result", type, expr_type); - } + } /* Warn for integer types converted to real types if and only if - all the range of values of the integer type cannot be - represented by the real type. */ + all the range of values of the integer type cannot be + represented by the real type. */ else if (TREE_CODE (expr_type) == INTEGER_TYPE - && TREE_CODE (type) == REAL_TYPE) - { + && TREE_CODE (type) == REAL_TYPE) + { tree type_low_bound, type_high_bound; - REAL_VALUE_TYPE real_low_bound, real_high_bound; + REAL_VALUE_TYPE real_low_bound, real_high_bound; /* Don't warn about char y = 0xff; float x = (int) y; */ expr = get_unwidened (expr, 0); expr_type = TREE_TYPE (expr); - type_low_bound = TYPE_MIN_VALUE (expr_type); - type_high_bound = TYPE_MAX_VALUE (expr_type); - real_low_bound = real_value_from_int_cst (0, type_low_bound); - real_high_bound = real_value_from_int_cst (0, type_high_bound); + type_low_bound = TYPE_MIN_VALUE (expr_type); + type_high_bound = TYPE_MAX_VALUE (expr_type); + real_low_bound = real_value_from_int_cst (0, type_low_bound); + real_high_bound = real_value_from_int_cst (0, type_high_bound); - if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) - || !exact_real_truncate (TYPE_MODE (type), &real_high_bound)) - give_warning = true; - } + if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) + || !exact_real_truncate (TYPE_MODE (type), &real_high_bound)) + give_warning = true; + } /* Warn for real types converted to smaller real types. */ else if (TREE_CODE (expr_type) == REAL_TYPE - && TREE_CODE (type) == REAL_TYPE - && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) - give_warning = true; + && TREE_CODE (type) == REAL_TYPE + && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) + give_warning = true; + } + return give_warning; +} + +/* Warns if the conversion of EXPR to TYPE may alter a value. + This is a helper function for warnings_for_convert_and_check. */ - if (give_warning) - warning_at (loc, OPT_Wconversion, +static void +conversion_warning (tree type, tree expr) +{ + int i; + const int expr_num_operands = TREE_OPERAND_LENGTH (expr); + tree expr_type = TREE_TYPE (expr); + location_t loc = EXPR_LOC_OR_HERE (expr); + + if (!warn_conversion && !warn_sign_conversion) + return; + + /* If any operand is artificial, then this expression was generated + by the compiler and we do not warn. */ + for (i = 0; i < expr_num_operands; i++) + { + tree op = TREE_OPERAND (expr, i); + if (op && DECL_P (op) && DECL_ARTIFICIAL (op)) + return; + } + + switch (TREE_CODE (expr)) + { + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case TRUTH_NOT_EXPR: + /* Conversion from boolean to a signed:1 bit-field (which only + can hold the values 0 and -1) doesn't lose information - but + it does change the value. */ + if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type)) + warning_at (loc, OPT_Wconversion, + "conversion to %qT from boolean expression", type); + return; + + case REAL_CST: + case INTEGER_CST: + if (unsafe_conversion_p (type, expr, true)) + warning_at (loc, OPT_Wconversion, + "conversion to %qT alters %qT constant value", + type, expr_type); + return; + + case COND_EXPR: + { + /* In case of COND_EXPR, if both operands are constants or + COND_EXPR, then we do not care about the type of COND_EXPR, + only about the conversion of each operand. */ + tree op1 = TREE_OPERAND (expr, 1); + tree op2 = TREE_OPERAND (expr, 2); + + if ((TREE_CODE (op1) == REAL_CST || TREE_CODE (op1) == INTEGER_CST + || TREE_CODE (op1) == COND_EXPR) + && (TREE_CODE (op2) == REAL_CST || TREE_CODE (op2) == INTEGER_CST + || TREE_CODE (op2) == COND_EXPR)) + { + conversion_warning (type, op1); + conversion_warning (type, op2); + return; + } + /* Fall through. */ + } + + default: /* 'expr' is not a constant. */ + if (unsafe_conversion_p (type, expr, true)) + warning_at (loc, OPT_Wconversion, "conversion to %qT from %qT may alter its value", type, expr_type); } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 3a4977929d9..6905737c28e 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -742,6 +742,7 @@ extern tree c_common_signed_type (tree); extern tree c_common_signed_or_unsigned_type (int, tree); extern void c_common_init_ts (void); extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); +extern bool unsafe_conversion_p (tree, tree, bool); extern bool decl_with_nonnull_addr_p (const_tree); extern tree c_fully_fold (tree, bool, bool *); extern tree decl_constant_value_for_optimization (tree); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index f7f78244094..7577f4f830f 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -51,6 +51,14 @@ enum impl_conv { ic_return }; +/* Possibe cases of scalar_to_vector conversion. */ +enum stv_conv { + stv_error, /* Error occured. */ + stv_nothing, /* Nothing happened. */ + stv_firstarg, /* First argument must be expanded. */ + stv_secondarg /* Second argument must be expanded. */ +}; + /* The level of nesting inside "__alignof__". */ int in_alignof; @@ -9323,6 +9331,88 @@ push_cleanup (tree decl, tree cleanup, bool eh_only) TREE_OPERAND (stmt, 0) = list; STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; } + +/* Convert scalar to vector for the range of operations. */ +static enum stv_conv +scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1) +{ + tree type0 = TREE_TYPE (op0); + tree type1 = TREE_TYPE (op1); + bool integer_only_op = false; + enum stv_conv ret = stv_firstarg; + + gcc_assert (TREE_CODE (type0) == VECTOR_TYPE + || TREE_CODE (type1) == VECTOR_TYPE); + switch (code) + { + case RSHIFT_EXPR: + case LSHIFT_EXPR: + if (TREE_CODE (type0) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE) + { + if (unsafe_conversion_p (TREE_TYPE (type1), op0, false)) + { + error_at (loc, "conversion of scalar to vector " + "involves truncation"); + return stv_error; + } + else + return stv_firstarg; + } + break; + + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + integer_only_op = true; + /* ... fall through ... */ + + 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) + { + tree tmp; + ret = stv_secondarg; + /* 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 (unsafe_conversion_p (TREE_TYPE (type1), op0, false)) + { + error_at (loc, "conversion of scalar to vector " + "involves truncation"); + return stv_error; + } + return ret; + } + else if (!integer_only_op + /* Allow integer --> real conversion if safe. */ + && (TREE_CODE (type0) == REAL_TYPE + || TREE_CODE (type0) == INTEGER_TYPE) + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type1))) + { + if (unsafe_conversion_p (TREE_TYPE (type1), op0, false)) + { + error_at (loc, "conversion of scalar to vector " + "involves truncation"); + return stv_error; + } + return ret; + } + default: + break; + } + + return stv_nothing; +} /* Build a binary-operation expression without default conversions. CODE is the kind of expression to build. @@ -9434,7 +9524,10 @@ build_binary_op (location_t location, enum tree_code code, else int_const = int_const_or_overflow = false; - if (convert_p) + /* Do not apply default conversion in mixed vector/scalar expression. */ + if (convert_p + && !((TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE) + != (TREE_CODE (TREE_TYPE (op1)) == VECTOR_TYPE))) { op0 = default_conversion (op0); op1 = default_conversion (op1); @@ -9506,6 +9599,51 @@ build_binary_op (location_t location, enum tree_code code, 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)) + { + enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1); + + switch (convert_flag) + { + case stv_error: + return error_mark_node; + case stv_firstarg: + { + bool maybe_const = true; + tree sc; + sc = c_fully_fold (op0, false, &maybe_const); + sc = save_expr (sc); + sc = convert (TREE_TYPE (type1), sc); + op0 = build_vector_from_val (type1, sc); + if (!maybe_const) + op0 = c_wrap_maybe_const (op0, true); + orig_type0 = type0 = TREE_TYPE (op0); + code0 = TREE_CODE (type0); + converted = 1; + break; + } + case stv_secondarg: + { + bool maybe_const = true; + tree sc; + sc = c_fully_fold (op1, false, &maybe_const); + sc = save_expr (sc); + sc = convert (TREE_TYPE (type0), sc); + op1 = build_vector_from_val (type0, sc); + if (!maybe_const) + op0 = c_wrap_maybe_const (op1, true); + orig_type1 = type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + converted = 1; + break; + } + default: + break; + } + } + switch (code) { case PLUS_EXPR: diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 480a8b0288e..49a81253593 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -6526,18 +6526,25 @@ 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. +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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ba435362e6f..b4b76d5a8a6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2011-08-10 Artjoms Sinkarovs + + * gcc.c-torture/execute/scal-to-vec1.c: New test. + * gcc.c-torture/execute/scal-to-vec2.c: New test. + * gcc.c-torture/execute/scal-to-vec3.c: New test. + * gcc.dg/scal-to-vec1.c: New test. + * gcc.dg/scal-to-vec2.c: New test. + 2011-08-09 Richard Guenther * gcc.dg/tree-ssa/vrp57.c: Disable CCP. diff --git a/gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c b/gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c new file mode 100644 index 00000000000..e2b43f42635 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/scal-to-vec1.c @@ -0,0 +1,85 @@ +#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 = 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); + 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; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c b/gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c new file mode 100644 index 00000000000..0a5037e333e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/scal-to-vec2.c @@ -0,0 +1,62 @@ +#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) + + +long __attribute__ ((noinline)) vlng () { return (long)42; } +int __attribute__ ((noinline)) vint () { return (int) 43; } +short __attribute__ ((noinline)) vsrt () { return (short)42; } +char __attribute__ ((noinline)) vchr () { return (char)42; } + + +int main (int argc, char *argv[]) { + vector(16, char) c0 = {argc, 1,2,3,4,5,6,7, argc, 1,2,3,4,5,6,7}; + vector(16, char) c1; + + vector(8, short) s0 = {argc, 1,2,3,4,5,6,7}; + vector(8, short) s1; + + vector(4, int) i0 = {argc, 1, 2, 3}; + vector(4, int) i1; + + vector(2, long) l0 = {argc, 1}; + vector(2, long) l1; + + c1 = vchr() + c0; check (char, 16, c0, c1, vchr(), +, l); + + s1 = vsrt() + s0; check (short, 8, s0, s1, vsrt(), +, l); + s1 = vchr() + s0; check (short, 8, s0, s1, vchr(), +, l); + + i1 = vint() * i0; check (int, 4, i0, i1, vint(), *, l); + i1 = vsrt() * i0; check (int, 4, i0, i1, vsrt(), *, l); + i1 = vchr() * i0; check (int, 4, i0, i1, vchr(), *, l); + + l1 = vlng() * l0; check (long, 2, l0, l1, vlng(), *, l); + l1 = vint() * l0; check (long, 2, l0, l1, vint(), *, l); + l1 = vsrt() * l0; check (long, 2, l0, l1, vsrt(), *, l); + l1 = vchr() * l0; check (long, 2, l0, l1, vchr(), *, l); + + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c b/gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c new file mode 100644 index 00000000000..76fc245c6ea --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/scal-to-vec3.c @@ -0,0 +1,48 @@ +#define vector(elcount, type) \ +__attribute__((vector_size((elcount)*sizeof(type)))) type + +#define vidx(type, vec, idx) (*((type *) &(vec) + idx)) + +#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(4, float) f0 = {1., 2., 3., 4.}; + vector(4, float) f1, f2; + + vector(2, double) d0 = {1., 2.}; + vector(2, double) d1, d2; + + + 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; +} diff --git a/gcc/testsuite/gcc.dg/scal-to-vec1.c b/gcc/testsuite/gcc.dg/scal-to-vec1.c new file mode 100644 index 00000000000..503426dbb29 --- /dev/null +++ b/gcc/testsuite/gcc.dg/scal-to-vec1.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-long-long" } */ +#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; +extern long long sll; + +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 "conversion of scalar to vector" } */ + f1 = 1.3 + f0; /* { dg-error "conversion of scalar to vector" } */ + f1 = sll + f0; /* { dg-error "conversion of scalar to vector" } */ + f1 = ((int)998769576) + f0; /* { dg-error "conversion of scalar to vector" } */ + + /* 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" } */ + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/scal-to-vec2.c b/gcc/testsuite/gcc.dg/scal-to-vec2.c new file mode 100644 index 00000000000..1354aa55b3d --- /dev/null +++ b/gcc/testsuite/gcc.dg/scal-to-vec2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +/* Test for C_MAYBE_CONST are folded correctly when + expanding an expression to vector. */ + +int f(void); +unsigned int g(void); +unsigned int h; + +typedef unsigned int vec __attribute__((vector_size(16))); + +vec i; + + +vec fv1(void) { return i + (h ? f() : g()); } +vec fv2(void) { return (h ? f() : g()) + i; } -- 2.30.2