+
+/* Widen a scalar value SCALAR_VALUE to vector type VECTOR_TYPE by
+ replicating SCALAR_VALUE for each element of the vector. Only scalar
+ types that can be cast to the type of one element of the vector are
+ acceptable. The newly created vector value is returned upon success,
+ otherwise an error is thrown. */
+
+struct value *
+value_vector_widen (struct value *scalar_value, struct type *vector_type)
+{
+ /* Widen the scalar to a vector. */
+ struct type *eltype, *scalar_type;
+ struct value *val, *elval;
+ LONGEST low_bound, high_bound;
+ int i;
+
+ vector_type = check_typedef (vector_type);
+
+ gdb_assert (TYPE_CODE (vector_type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (vector_type));
+
+ if (!get_array_bounds (vector_type, &low_bound, &high_bound))
+ error (_("Could not determine the vector bounds"));
+
+ eltype = check_typedef (TYPE_TARGET_TYPE (vector_type));
+ elval = value_cast (eltype, scalar_value);
+
+ scalar_type = check_typedef (value_type (scalar_value));
+
+ /* If we reduced the length of the scalar then check we didn't loose any
+ important bits. */
+ if (TYPE_LENGTH (eltype) < TYPE_LENGTH (scalar_type)
+ && !value_equal (elval, scalar_value))
+ error (_("conversion of scalar to vector involves truncation"));
+
+ val = allocate_value (vector_type);
+ for (i = 0; i < high_bound - low_bound + 1; i++)
+ /* Duplicate the contents of elval into the destination vector. */
+ memcpy (value_contents_writeable (val) + (i * TYPE_LENGTH (eltype)),
+ value_contents_all (elval), TYPE_LENGTH (eltype));
+
+ return val;
+}
+
+/* Performs a binary operation on two vector operands by calling scalar_binop
+ for each pair of vector components. */
+
+static struct value *
+vector_binop (struct value *val1, struct value *val2, enum exp_opcode op)
+{
+ struct value *val, *tmp, *mark;
+ struct type *type1, *type2, *eltype1, *eltype2;
+ int t1_is_vec, t2_is_vec, elsize, i;
+ LONGEST low_bound1, high_bound1, low_bound2, high_bound2;
+
+ type1 = check_typedef (value_type (val1));
+ type2 = check_typedef (value_type (val2));
+
+ t1_is_vec = (TYPE_CODE (type1) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type1)) ? 1 : 0;
+ t2_is_vec = (TYPE_CODE (type2) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type2)) ? 1 : 0;
+
+ if (!t1_is_vec || !t2_is_vec)
+ error (_("Vector operations are only supported among vectors"));
+
+ if (!get_array_bounds (type1, &low_bound1, &high_bound1)
+ || !get_array_bounds (type2, &low_bound2, &high_bound2))
+ error (_("Could not determine the vector bounds"));
+
+ eltype1 = check_typedef (TYPE_TARGET_TYPE (type1));
+ eltype2 = check_typedef (TYPE_TARGET_TYPE (type2));
+ elsize = TYPE_LENGTH (eltype1);
+
+ if (TYPE_CODE (eltype1) != TYPE_CODE (eltype2)
+ || elsize != TYPE_LENGTH (eltype2)
+ || TYPE_UNSIGNED (eltype1) != TYPE_UNSIGNED (eltype2)
+ || low_bound1 != low_bound2 || high_bound1 != high_bound2)
+ error (_("Cannot perform operation on vectors with different types"));
+
+ val = allocate_value (type1);
+ mark = value_mark ();
+ for (i = 0; i < high_bound1 - low_bound1 + 1; i++)
+ {
+ tmp = value_binop (value_subscript (val1, i),
+ value_subscript (val2, i), op);
+ memcpy (value_contents_writeable (val) + i * elsize,
+ value_contents_all (tmp),
+ elsize);
+ }
+ value_free_to_mark (mark);
+
+ return val;
+}
+
+/* Perform a binary operation on two operands. */
+
+struct value *
+value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
+{
+ struct value *val;
+ struct type *type1 = check_typedef (value_type (arg1));
+ struct type *type2 = check_typedef (value_type (arg2));
+ int t1_is_vec = (TYPE_CODE (type1) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type1));
+ int t2_is_vec = (TYPE_CODE (type2) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type2));
+
+ if (!t1_is_vec && !t2_is_vec)
+ val = scalar_binop (arg1, arg2, op);
+ else if (t1_is_vec && t2_is_vec)
+ val = vector_binop (arg1, arg2, op);
+ else
+ {
+ /* Widen the scalar operand to a vector. */
+ struct value **v = t1_is_vec ? &arg2 : &arg1;
+ struct type *t = t1_is_vec ? type2 : type1;
+
+ if (TYPE_CODE (t) != TYPE_CODE_FLT
+ && TYPE_CODE (t) != TYPE_CODE_DECFLOAT
+ && !is_integral_type (t))
+ error (_("Argument to operation not a number or boolean."));
+
+ /* Replicate the scalar value to make a vector value. */
+ *v = value_vector_widen (*v, t1_is_vec ? type1 : type2);
+
+ val = vector_binop (arg1, arg2, op);
+ }
+
+ return val;
+}