On Fri, Aug 12, 2011 at 4:03 AM, Artem Shinkarov
<[email protected]> wrote:
> Hi
>
> Here is a completed version of the vector comparison patch we
> discussed a long time ago here:
> http://gcc.gnu.org/ml/gcc-patches/2010-08/msg01184.html
>
> The patch implements vector comparison according to the OpenCL
> standard, when the result of the comparison of two vectors is vector
> of signed integers, where -1 represents true and 0 false.
>
> The patch implements vector conditional res = VCOND<V1 ? V2 : V3>
> which is expanded into:
> foreach (i in length (V1)) res[i] = V1 == 0 ? V3[i] : V2[i].
Some comments on the patch below. First, in general I don't see
why you need a new target hook to specify whether to "vectorize"
a comparison. Why are the existing hooks used by the vectorizer
not enough?
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c (revision 177665)
+++ gcc/fold-const.c (working copy)
@@ -9073,34 +9073,61 @@ fold_comparison (location_t loc, enum tr
floating-point, we can only do some of these simplifications.) */
if (operand_equal_p (arg0, arg1, 0))
{
- switch (code)
+ if (TREE_CODE (TREE_TYPE (arg0)) == VECTOR_TYPE)
{
- case EQ_EXPR:
- if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
- || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
- return constant_boolean_node (1, type);
I think this change should go in a separate patch for improved
constant folding. It shouldn't be necessary for enabling vector compares, no?
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (ifexp))))
+ {
+ error_at (colon_loc, "vector comparison must be of signed "
+ "integer vector type");
+ return error_mark_node;
+ }
why that?
+ if (TYPE_VECTOR_SUBPARTS (type1) != TYPE_VECTOR_SUBPARTS (type2)
+ || TYPE_VECTOR_SUBPARTS (TREE_TYPE (ifexp))
+ != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (colon_loc, "vectors of different length found in "
+ "vector comparison");
+ return error_mark_node;
+ }
I miss verification that type1 and type2 are vector types, or is that done
elsewhere? I think type1 and type2 are already verified to be
compatible (but you might double-check). At least the above would be
redundant with
+ if (type1 != type2)
+ {
+ error_at (colon_loc, "vectors of different types involved in "
+ "vector comparison");
+ return error_mark_node;
+ }
Joseph may have comments about the fully-fold stuff that follows.
+ /* Currently the expansion of VEC_COND_EXPR does not allow
+ expessions where the type of vectors you compare differs
+ form the type of vectors you select from. For the time
+ being we insert implicit conversions. */
+ if ((COMPARISON_CLASS_P (ifexp)
Why only for comparison-class?
+ && TREE_TYPE (TREE_OPERAND (ifexp, 0)) != type1)
+ || TREE_TYPE (ifexp) != type1)
+ {
+ tree comp_type = COMPARISON_CLASS_P (ifexp)
+ ? TREE_TYPE (TREE_OPERAND (ifexp, 0))
+ : TREE_TYPE (ifexp);
+ tree vcond;
+
+ op1 = convert (comp_type, op1);
+ op2 = convert (comp_type, op2);
+ vcond = build3 (VEC_COND_EXPR, comp_type, ifexp, op1, op2);
+ vcond = convert (type1, vcond);
+ return vcond;
+ }
+ else
+ return build3 (VEC_COND_EXPR, type1, ifexp, op1, op2);
In the end we of course will try to fix the middle-end/backends to
allow mixed types here as the current restriction doesn't really make sense.
case EQ_EXPR:
case NE_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
as above - compatibility should already be ensured, thus type0 == type1
here?
+/* Try a hardware hook for vector comparison or
+ extract comparison piecewise. */
+static tree
+expand_vector_comparison (gimple_stmt_iterator *gsi, tree type, tree op0,
+ tree op1, enum tree_code code)
comments should mention and describe all function arguments.
+/* Expand vector condition EXP which should have the form
+ VEC_COND_EXPR<cond, vec0, vec1> into the following
+ vector:
+ {cond[i] != 0 ? vec0[i] : vec1[i], ... }
+ i changes from 0 to TYPE_VECTOR_SUBPARTS (TREE_TYPE (vec0)). */
+static tree
+earlyexpand_vec_cond_expr (gimple_stmt_iterator *gsi, tree exp)
that would be expand_vec_cond_expr_piecewise, no?
+ /* Ensure that we will be able to expand vector comparison
+ in case it is not supported by the architecture. */
+ gcc_assert (COMPARISON_CLASS_P (cond));
that looks dangerous to me - did you try
vec = v1 <= v2;
vec2 = vec ? v1 : v2;
without optimization?
+ /* Check if we need to expand vector condition inside of
+ VEC_COND_EXPR. */
+ var = create_tmp_reg (TREE_TYPE (cond), "cond");
+ new_rhs = expand_vector_comparison (gsi, TREE_TYPE (cond),
+ TREE_OPERAND (cond, 0),
+ TREE_OPERAND (cond, 1),
+ TREE_CODE (cond));
That unconditionally expands, so no need for "Check".
+ /* Expand VEC_COND_EXPR into a vector of scalar COND_EXPRs. */
+ v = VEC_alloc(constructor_elt, gc, nunits);
+ for (i = 0; i < nunits;
+ i += 1, index = int_const_binop (PLUS_EXPR, index, part_width))
+ {
+ tree tcond = tree_vec_extract (gsi, inner_type, var, part_width, index);
+ tree a = tree_vec_extract (gsi, inner_type, vec0, part_width, index);
+ tree b = tree_vec_extract (gsi, inner_type, vec1, part_width, index);
+ tree rcond = gimplify_build2 (gsi, NE_EXPR, boolean_type_node, tcond,
+ build_int_cst (inner_type ,0));
I seriously doubt that when expanding this part piecewise expanding
the mask first in either way is going to be beneficial. Instead I would
suggest to "inline" the comparison here. Thus instead of
mask =
= { mask[0] != 0 ? ... }
do
= { c0[0] < c1[0] ? ..., }
or even expand the ? : using mask operations if we efficiently can
create that mask.
+ /* Check if VEC_COND_EXPR is supported in hardware within the
+ given types. */
+ if (code == VEC_COND_EXPR)
+ {
+ tree exp = gimple_assign_rhs1 (stmt);
+ tree cond = TREE_OPERAND (exp, 0);
+
+ /* If VEC_COND_EXPR is presented as A ? V0 : V1, we
+ change it to A != {0,0,...} ? V0 : V1 */
+ if (!COMPARISON_CLASS_P (cond))
+ TREE_OPERAND (exp, 0) =
+ build2 (NE_EXPR, TREE_TYPE (cond), cond,
+ build_vector_from_val (TREE_TYPE (cond),
+ build_int_cst (TREE_TYPE (TREE_TYPE (cond)), 0)));
That looks inefficient as well. Iff we know that the mask is always
either {-1, -1 ..} or {0, 0 ...} then we can expand the ? : using
bitwise operations (see what the i?86 expander does, for example).
@@ -471,6 +603,7 @@ expand_vector_operations_1 (gimple_stmt_
gcc_assert (code != CONVERT_EXPR);
+
/* The signedness is determined from input argument. */
if (code == VEC_UNPACK_FLOAT_HI_EXPR
|| code == VEC_UNPACK_FLOAT_LO_EXPR)
spurious whitespace change.
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c (revision 177665)
+++ gcc/tree-cfg.c (working copy)
@@ -3191,6 +3191,38 @@ verify_gimple_comparison (tree type, tre
return true;
}
+ if (TREE_CODE (op0_type) == VECTOR_TYPE
+ && TREE_CODE (op1_type) == VECTOR_TYPE
+ && TREE_CODE (type) == VECTOR_TYPE)
+ {
this should check TREE_CODE (type) == VECTOR_TYPE only
and then verify the comparison operands are actually vectors.
+ if (TREE_TYPE (op0_type) != TREE_TYPE (op1_type))
+ {
+ error ("invalid vector comparison, vector element type mismatch");
+ debug_generic_expr (op0_type);
+ debug_generic_expr (op1_type);
+ return true;
+ }
this needs to use code similar to the scalar variant,
!useless_type_conversion_p (op0_type, op1_type)
&& !useless_type_conversion_p (op1_type, op0_type)
which also makes the first TYPE_VECTOR_SUBPARTS redundant.
+ if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type)
+ && TYPE_PRECISION (TREE_TYPE (op0_type))
+ != TYPE_PRECISION (TREE_TYPE (type)))
+ {
+ error ("invalid vector comparison resulting type");
+ debug_generic_expr (type);
+ return true;
+ }
I think you can drop the TYPE_PRECISION check. We might want to
assert that a vector element types precision always matches its
mode precision (in make_vector_type).
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c (revision 177665)
+++ gcc/c-parser.c (working copy)
@@ -5337,8 +5337,17 @@ c_parser_conditional_expression (c_parse
if (c_parser_next_token_is (parser, CPP_COLON))
{
tree eptype = NULL_TREE;
-
+
middle_loc = c_parser_peek_token (parser)->location;
+
+ if (TREE_CODE (TREE_TYPE (cond.value)) == VECTOR_TYPE)
watch out for whitespace changes - you add a trailing tab here.
+/* Find target specific sequence for vector comparison of
+ real-type vectors V0 and V1. Returns variable containing
+ result of the comparison or NULL_TREE in other case. */
+static tree
+vector_fp_compare (gimple_stmt_iterator *gsi, tree rettype,
+ enum machine_mode mode, tree v0, tree v1,
+ enum tree_code code)
+{
+ enum ix86_builtins fcode;
is there a reason we need this and cannot simply provide expanders
for the named patterns? We'd need to give them semantics of
producing all-ones / all-zero masks of course. Richard, do you think
that's sensible? That way we'd avoid the new target hook and could
simply do optab queries.
Thanks,
Richard.
> ChangeLog
>
> 2011-08-12 Artjoms Sinkarovs <[email protected]>
>
> gcc/
> * targhooks.c (default_builtin_vec_compare): New hook.
> * targhooks.h (default_builtin_vec_compare): New definition.
> * target.def (builtin_vec_compare): New hook.
> * target.h: New include (gimple.h).
> * fold-const.c
> (fold_comparison): Adjust x <cmp> x vector operations.
> * c-typeck.c (build_binary_op): Allow vector comparison.
> (c_obj_common_truthvalue_conversion): Deny vector comparison
> inside of if statement.
> (build_conditional_expr): Adjust to build VEC_COND_EXPR.
> * tree-vect-generic.c (do_compare): Helper function.
> (expand_vector_comparison): Check if hardware comparison
> is available, if not expand comparison piecewise.
> (expand_vector_operation): Handle vector comparison
> expressions separately.
> (earlyexpand_vec_cond_expr): Expand vector comparison
> piecewise.
> * Makefile.in: New dependencies.
> * tree-cfg.c (verify_gimple_comparison): Allow vector
> comparison operations in gimple.
> * c-parser.c (c_parser_conditional_expression): Adjust
> to handle VEC_COND_EXPR.
> * gimplify.c (gimplify_expr): Adjust to handle VEC_COND_EXPR.
> * config/i386/i386.c (vector_fp_compare): Build hardware
> specific code for floating point vector comparison.
> (vector_int_compare): Build hardware specific code for
> integer vector comparison.
> (ix86_vectorize_builtin_vec_compare): Implementation of
> builtin_vec_compare hook.
>
> gcc/testsuite/
> * gcc.c-torture/execute/vector-vcond-1.c: New test.
> * gcc.c-torture/execute/vector-vcond-2.c: New test.
> * gcc.c-torture/execute/vector-compare-1.c: New test.
> * gcc.c-torture/execute/vector-compare-2.c: New test.
> * gcc.dg/vector-compare-1.c: New test.
> * gcc.dg/vector-compare-2.c: New test.
>
> gcc/doc
> * extend.texi: Adjust.
> * tm.texi: Adjust.
> * tm.texi.in: Adjust.
>
>
> bootstrapped and tested on x86_64_unknown-linux.
>
>
> Thanks,
> Artem Shinkarov.
>