===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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);
===================================================================
@@ -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;
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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 <shift> scalar' or 'scalar <shift> 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: