===================================================================
@@ -6511,18 +6511,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
===================================================================
@@ -1864,143 +1864,92 @@ tree shorten_binary_op (tree result_type
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,
@@ -2027,7 +1976,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
@@ -2036,58 +1985,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);
-
- if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
- || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
- give_warning = true;
- }
+ 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;
+ }
/* 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);
}
===================================================================
@@ -708,6 +708,7 @@ extern tree c_common_unsigned_type (tree
extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree);
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);
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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; }
===================================================================
@@ -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;
@@ -9313,6 +9321,88 @@ push_cleanup (tree decl, tree cleanup, b
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.
@@ -9424,7 +9514,10 @@ build_binary_op (location_t location, en
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);
@@ -9496,6 +9589,49 @@ 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))
+ {
+ 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 = c_save_expr (op0);
+ sc = convert (TREE_TYPE (type1), sc);
+ sc = c_fully_fold (sc, false, &maybe_const);
+ 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 = c_save_expr (op1);
+ sc = convert (TREE_TYPE (type0), sc);
+ sc = c_fully_fold (sc, false, &maybe_const);
+ op1 = build_vector_from_val (type0, sc);
+ if (!maybe_const)
+ op1 = 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: