Commit 0e3a99ae by Artjoms Sinkarovs Committed by Richard Biener

c-typeck.c (scalar_to_vector): New function.

2011-08-10  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>

	* 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
parent 0eb77834
2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* 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 <rguenther@suse.de> 2011-08-10 Richard Guenther <rguenther@suse.de>
* tree.h (get_pointer_alignment): Remove max-align argument. * tree.h (get_pointer_alignment): Remove max-align argument.
......
2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* 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 <jakub@redhat.com> 2011-08-02 Jakub Jelinek <jakub@redhat.com>
* c-common.h (c_finish_omp_atomic): Adjust prototype. * c-common.h (c_finish_omp_atomic): Adjust prototype.
......
...@@ -1922,143 +1922,92 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) ...@@ -1922,143 +1922,92 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
return result_type; return result_type;
} }
/* Warns if the conversion of EXPR to TYPE may alter a value. /* Checks if expression EXPR of real/integer type cannot be converted
This is a helper function for warnings_for_convert_and_check. */ to the real/integer type TYPE. Function returns true when:
* EXPR is a constant which cannot be exactly converted to TYPE
static void * EXPR is not a constant and size of EXPR's type > than size of TYPE,
conversion_warning (tree type, tree expr) 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; bool give_warning = false;
int i;
const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
tree expr_type = TREE_TYPE (expr); tree expr_type = TREE_TYPE (expr);
location_t loc = EXPR_LOC_OR_HERE (expr); location_t loc = EXPR_LOC_OR_HERE (expr);
if (!warn_conversion && !warn_sign_conversion) if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
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:
/* Warn for real constant that is not an exact integer converted /* Warn for real constant that is not an exact integer converted
to integer type. */ to integer type. */
if (TREE_CODE (expr_type) == REAL_TYPE if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE) && TREE_CODE (type) == INTEGER_TYPE)
{ {
if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type))) if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
give_warning = true; give_warning = true;
} }
/* Warn for an integer constant that does not fit into integer type. */ /* Warn for an integer constant that does not fit into integer type. */
else if (TREE_CODE (expr_type) == INTEGER_TYPE else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (type) == INTEGER_TYPE
&& !int_fits_type_p (expr, type)) && !int_fits_type_p (expr, type))
{ {
if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type) if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
&& tree_int_cst_sgn (expr) < 0) && tree_int_cst_sgn (expr) < 0)
warning_at (loc, OPT_Wsign_conversion, "negative integer" {
" implicitly converted to unsigned type"); if (produce_warns)
else if (!TYPE_UNSIGNED (type) && TYPE_UNSIGNED (expr_type)) warning_at (loc, OPT_Wsign_conversion, "negative integer"
warning_at (loc, OPT_Wsign_conversion, "conversion of unsigned" " implicitly converted to unsigned type");
" constant value to negative integer"); }
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 else
give_warning = true; give_warning = true;
} }
else if (TREE_CODE (type) == REAL_TYPE) else if (TREE_CODE (type) == REAL_TYPE)
{ {
/* Warn for an integer constant that does not fit into real type. */ /* Warn for an integer constant that does not fit into real type. */
if (TREE_CODE (expr_type) == INTEGER_TYPE) if (TREE_CODE (expr_type) == INTEGER_TYPE)
{ {
REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr); REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
if (!exact_real_truncate (TYPE_MODE (type), &a)) if (!exact_real_truncate (TYPE_MODE (type), &a))
give_warning = true; give_warning = true;
} }
/* Warn for a real constant that does not fit into a smaller /* Warn for a real constant that does not fit into a smaller
real type. */ real type. */
else if (TREE_CODE (expr_type) == REAL_TYPE else if (TREE_CODE (expr_type) == REAL_TYPE
&& TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
{ {
REAL_VALUE_TYPE a = TREE_REAL_CST (expr); REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
if (!exact_real_truncate (TYPE_MODE (type), &a)) if (!exact_real_truncate (TYPE_MODE (type), &a))
give_warning = true; give_warning = true;
} }
} }
}
if (give_warning) else
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 real types converted to integer types. */ /* Warn for real types converted to integer types. */
if (TREE_CODE (expr_type) == REAL_TYPE if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE) && TREE_CODE (type) == INTEGER_TYPE)
give_warning = true; give_warning = true;
else if (TREE_CODE (expr_type) == INTEGER_TYPE 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; */ /* Don't warn about unsigned char y = 0xff, x = (int) y; */
expr = get_unwidened (expr, 0); expr = get_unwidened (expr, 0);
expr_type = TREE_TYPE (expr); expr_type = TREE_TYPE (expr);
/* Don't warn for short y; short x = ((int)y & 0xff); */ /* Don't warn for short y; short x = ((int)y & 0xff); */
if (TREE_CODE (expr) == BIT_AND_EXPR 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) || TREE_CODE (expr) == BIT_XOR_EXPR)
{ {
/* If both args were extended from a shortest type, /* If both args were extended from a shortest type,
...@@ -2085,7 +2034,7 @@ conversion_warning (tree type, tree expr) ...@@ -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_signed_type (type))
&& int_fits_type_p (op1, && int_fits_type_p (op1,
c_common_unsigned_type (type)))) c_common_unsigned_type (type))))
return; return false;
/* If constant is unsigned and fits in the target /* If constant is unsigned and fits in the target
type, then the result will also fit. */ type, then the result will also fit. */
else if ((TREE_CODE (op0) == INTEGER_CST else if ((TREE_CODE (op0) == INTEGER_CST
...@@ -2094,58 +2043,136 @@ conversion_warning (tree type, tree expr) ...@@ -2094,58 +2043,136 @@ conversion_warning (tree type, tree expr)
|| (TREE_CODE (op1) == INTEGER_CST || (TREE_CODE (op1) == INTEGER_CST
&& unsigned1 && unsigned1
&& int_fits_type_p (op1, type))) && 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)) if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
give_warning = true; give_warning = true;
/* When they are the same width but different signedness, /* When they are the same width but different signedness,
then the value may change. */ 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)) && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
/* Even when converted to a bigger type, if the type is /* Even when converted to a bigger type, if the type is
unsigned but expr is signed, then negative values unsigned but expr is signed, then negative values
will be changed. */ 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 " warning_at (loc, OPT_Wsign_conversion, "conversion to %qT from %qT "
"may change the sign of the result", "may change the sign of the result",
type, expr_type); type, expr_type);
} }
/* Warn for integer types converted to real types if and only if /* Warn for integer types converted to real types if and only if
all the range of values of the integer type cannot be all the range of values of the integer type cannot be
represented by the real type. */ represented by the real type. */
else if (TREE_CODE (expr_type) == INTEGER_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; 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; */ /* Don't warn about char y = 0xff; float x = (int) y; */
expr = get_unwidened (expr, 0); expr = get_unwidened (expr, 0);
expr_type = TREE_TYPE (expr); expr_type = TREE_TYPE (expr);
type_low_bound = TYPE_MIN_VALUE (expr_type); type_low_bound = TYPE_MIN_VALUE (expr_type);
type_high_bound = TYPE_MAX_VALUE (expr_type); type_high_bound = TYPE_MAX_VALUE (expr_type);
real_low_bound = real_value_from_int_cst (0, type_low_bound); real_low_bound = real_value_from_int_cst (0, type_low_bound);
real_high_bound = real_value_from_int_cst (0, type_high_bound); real_high_bound = real_value_from_int_cst (0, type_high_bound);
if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
|| !exact_real_truncate (TYPE_MODE (type), &real_high_bound)) || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
give_warning = true; give_warning = true;
} }
/* Warn for real types converted to smaller real types. */ /* Warn for real types converted to smaller real types. */
else if (TREE_CODE (expr_type) == REAL_TYPE else if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == REAL_TYPE && TREE_CODE (type) == REAL_TYPE
&& TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
give_warning = true; 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) static void
warning_at (loc, OPT_Wconversion, 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", "conversion to %qT from %qT may alter its value",
type, expr_type); type, expr_type);
} }
......
...@@ -742,6 +742,7 @@ extern tree c_common_signed_type (tree); ...@@ -742,6 +742,7 @@ extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree); extern tree c_common_signed_or_unsigned_type (int, tree);
extern void c_common_init_ts (void); extern void c_common_init_ts (void);
extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); 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 bool decl_with_nonnull_addr_p (const_tree);
extern tree c_fully_fold (tree, bool, bool *); extern tree c_fully_fold (tree, bool, bool *);
extern tree decl_constant_value_for_optimization (tree); extern tree decl_constant_value_for_optimization (tree);
......
...@@ -51,6 +51,14 @@ enum impl_conv { ...@@ -51,6 +51,14 @@ enum impl_conv {
ic_return 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__". */ /* The level of nesting inside "__alignof__". */
int in_alignof; int in_alignof;
...@@ -9323,6 +9331,88 @@ push_cleanup (tree decl, tree cleanup, bool eh_only) ...@@ -9323,6 +9331,88 @@ push_cleanup (tree decl, tree cleanup, bool eh_only)
TREE_OPERAND (stmt, 0) = list; TREE_OPERAND (stmt, 0) = list;
STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; 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. /* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build. CODE is the kind of expression to build.
...@@ -9434,7 +9524,10 @@ build_binary_op (location_t location, enum tree_code code, ...@@ -9434,7 +9524,10 @@ build_binary_op (location_t location, enum tree_code code,
else else
int_const = int_const_or_overflow = false; 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); op0 = default_conversion (op0);
op1 = default_conversion (op1); op1 = default_conversion (op1);
...@@ -9506,6 +9599,51 @@ build_binary_op (location_t location, enum tree_code code, ...@@ -9506,6 +9599,51 @@ build_binary_op (location_t location, enum tree_code code,
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE); 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) switch (code)
{ {
case PLUS_EXPR: case PLUS_EXPR:
......
...@@ -6526,18 +6526,25 @@ In C it is possible to use shifting operators @code{<<}, @code{>>} on ...@@ -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, integer-type vectors. The operation is defined as following: @code{@{a0,
a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1, a1, @dots{}, an@} >> @{b0, b1, @dots{}, bn@} == @{a0 >> b0, a1 >> b1,
@dots{}, an >> bn@}}@. Vector operands must have the same number of @dots{}, an >> bn@}}@. Vector operands must have the same number of
elements. Additionally second operands can be a scalar integer in which elements.
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 For the convenience in C it is allowed to use a binary vector operation
value. 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. Consider the following code.
@smallexample @smallexample
typedef int v4si __attribute__ ((vector_size (16))); 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 @end smallexample
In C vectors can be subscripted as if the vector were an array with In C vectors can be subscripted as if the vector were an array with
......
2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* 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 <rguenther@suse.de> 2011-08-09 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/vrp57.c: Disable CCP. * gcc.dg/tree-ssa/vrp57.c: Disable CCP.
......
#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;
}
#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;
}
#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;
}
/* { 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;
}
/* { 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; }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment