From 1f137e6da1f8e0f05a788aa2683ea46053e7a7c0 Mon Sep 17 00:00:00 2001 From: ienkovich Date: Wed, 21 Oct 2015 16:01:43 +0000 Subject: [PATCH] gcc/ * doc/tm.texi: Regenerated. * doc/tm.texi.in (TARGET_VECTORIZE_GET_MASK_MODE): New. * stor-layout.c (layout_type): Use mode to get vector mask size. * target.def (get_mask_mode): New. * targhooks.c (default_get_mask_mode): New. * targhooks.h (default_get_mask_mode): New. * gcc/tree-vect-stmts.c (get_same_sized_vectype): Add special case for boolean vector. * tree.c (MAX_BOOL_CACHED_PREC): New. (nonstandard_boolean_type_cache): New. (build_nonstandard_boolean_type): New. (make_vector_type): Vector mask has no canonical type. (build_truth_vector_type): New. (build_same_sized_truth_vector_type): New. (truth_type_for): Support vector masks. * tree.h (VECTOR_BOOLEAN_TYPE_P): New. (build_truth_vector_type): New. (build_same_sized_truth_vector_type): New. (build_nonstandard_boolean_type): New. * tree-cfg.c (verify_gimple_comparison) Require boolean vector type for vector comparison. (verify_gimple_assign_ternary): Likewise. * optabs.c (expand_vec_cond_expr): Accept boolean vector as condition operand. * tree-vect-stmts.c (vectorizable_condition): Use boolean vector type for vector comparison. * tree-vect-generic.c (elem_op_func): Add new operand to hold vector type. (do_unop): Adjust to modified function type. (do_binop): Likewise. (do_plus_minus): Likewise. (do_negate); Likewise. (expand_vector_piecewise): Likewise. (do_cond): Likewise. (do_compare): Use comparison instead of condition. (expand_vector_divmod): Use boolean vector type for comparison. (expand_vector_operations_1): Skip scalar mask operations. gcc/c * c-typeck.c (build_conditional_expr): Use boolean vector type for vector comparison. (build_vec_cmp): New. (build_binary_op): Use build_vec_cmp for comparison. gcc/cp * call.c (build_conditional_expr_1): Use boolean vector type for vector comparison. * typeck.c (build_vec_cmp): New. (cp_build_binary_op): Use build_vec_cmp for comparison. gcc/testsuite/ * g++.dg/ext/vector22.C: Allow VEC_COND_EXPR. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@229128 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 40 ++++++++++++++++++++ gcc/c/ChangeLog | 7 ++++ gcc/c/c-typeck.c | 32 +++++++++++++++- gcc/cp/ChangeLog | 7 ++++ gcc/cp/call.c | 15 +++++++- gcc/cp/typeck.c | 16 +++++++- gcc/doc/tm.texi | 6 +++ gcc/doc/tm.texi.in | 2 + gcc/optabs.c | 5 ++- gcc/stor-layout.c | 14 +++++-- gcc/target.def | 10 +++++ gcc/targhooks.c | 14 +++++++ gcc/targhooks.h | 1 + gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/ext/vector22.C | 1 - gcc/tree-cfg.c | 21 ++++------- gcc/tree-vect-generic.c | 57 +++++++++++++++++----------- gcc/tree-vect-stmts.c | 8 ++-- gcc/tree.c | 74 ++++++++++++++++++++++++++++++++++--- gcc/tree.h | 9 +++++ 20 files changed, 287 insertions(+), 56 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2971405..d5296ae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,45 @@ 2015-10-21 Ilya Enkovich + * doc/tm.texi: Regenerated. + * doc/tm.texi.in (TARGET_VECTORIZE_GET_MASK_MODE): New. + * stor-layout.c (layout_type): Use mode to get vector mask size. + * target.def (get_mask_mode): New. + * targhooks.c (default_get_mask_mode): New. + * targhooks.h (default_get_mask_mode): New. + * gcc/tree-vect-stmts.c (get_same_sized_vectype): Add special case + for boolean vector. + * tree.c (MAX_BOOL_CACHED_PREC): New. + (nonstandard_boolean_type_cache): New. + (build_nonstandard_boolean_type): New. + (make_vector_type): Vector mask has no canonical type. + (build_truth_vector_type): New. + (build_same_sized_truth_vector_type): New. + (truth_type_for): Support vector masks. + * tree.h (VECTOR_BOOLEAN_TYPE_P): New. + (build_truth_vector_type): New. + (build_same_sized_truth_vector_type): New. + (build_nonstandard_boolean_type): New. + * tree-cfg.c (verify_gimple_comparison) Require boolean + vector type for vector comparison. + (verify_gimple_assign_ternary): Likewise. + * optabs.c (expand_vec_cond_expr): Accept boolean vector as + condition operand. + * tree-vect-stmts.c (vectorizable_condition): Use boolean + vector type for vector comparison. + * tree-vect-generic.c (elem_op_func): Add new operand to hold + vector type. + (do_unop): Adjust to modified function type. + (do_binop): Likewise. + (do_plus_minus): Likewise. + (do_negate); Likewise. + (expand_vector_piecewise): Likewise. + (do_cond): Likewise. + (do_compare): Use comparison instead of condition. + (expand_vector_divmod): Use boolean vector type for comparison. + (expand_vector_operations_1): Skip scalar mask operations. + +2015-10-21 Ilya Enkovich + * omp-low.c (simd_clone_create): Set in_other_partition for created clones. diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index c1dbde6..34aafc2 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,10 @@ +2015-10-21 Ilya Enkovich + + * c-typeck.c (build_conditional_expr): Use boolean vector + type for vector comparison. + (build_vec_cmp): New. + (build_binary_op): Use build_vec_cmp for comparison. + 2015-10-20 Marek Polacek * c-parser.c (is_cilkplus_vector_p): Don't define here. diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index bc43602..6b32781 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4771,6 +4771,18 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, && TREE_CODE (orig_op2) == INTEGER_CST && !TREE_OVERFLOW (orig_op2))); } + + /* Need to convert condition operand into a vector mask. */ + if (VECTOR_TYPE_P (TREE_TYPE (ifexp))) + { + tree vectype = TREE_TYPE (ifexp); + tree elem_type = TREE_TYPE (vectype); + tree zero = build_int_cst (elem_type, 0); + tree zero_vec = build_vector_from_val (vectype, zero); + tree cmp_type = build_same_sized_truth_vector_type (vectype); + ifexp = build2 (NE_EXPR, cmp_type, ifexp, zero_vec); + } + if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST)) ret = fold_build3_loc (colon_loc, COND_EXPR, result_type, ifexp, op1, op2); else @@ -10237,6 +10249,20 @@ push_cleanup (tree decl, tree cleanup, bool eh_only) STATEMENT_LIST_STMT_EXPR (list) = stmt_expr; } +/* Build a vector comparison of ARG0 and ARG1 using CODE opcode + into a value of TYPE type. Comparison is done via VEC_COND_EXPR. */ + +static tree +build_vec_cmp (tree_code code, tree type, + tree arg0, tree arg1) +{ + tree zero_vec = build_zero_cst (type); + tree minus_one_vec = build_minus_one_cst (type); + tree cmp_type = build_same_sized_truth_vector_type (type); + tree cmp = build2 (code, cmp_type, arg0, arg1); + return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec); +} + /* Build a binary-operation expression without default conversions. CODE is the kind of expression to build. LOCATION is the operator's location. @@ -10803,7 +10829,8 @@ build_binary_op (location_t location, enum tree_code code, result_type = build_opaque_vector_type (intt, TYPE_VECTOR_SUBPARTS (type0)); converted = 1; - break; + ret = build_vec_cmp (resultcode, result_type, op0, op1); + goto return_build_binary_op; } if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)) warning_at (location, @@ -10955,7 +10982,8 @@ build_binary_op (location_t location, enum tree_code code, result_type = build_opaque_vector_type (intt, TYPE_VECTOR_SUBPARTS (type0)); converted = 1; - break; + ret = build_vec_cmp (resultcode, result_type, op0, op1); + goto return_build_binary_op; } build_type = integer_type_node; if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9f282d8..2a9e873 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2015-10-21 Ilya Enkovich + + * call.c (build_conditional_expr_1): Use boolean vector + type for vector comparison. + * typeck.c (build_vec_cmp): New. + (cp_build_binary_op): Use build_vec_cmp for comparison. + 2015-10-20 Jason Merrill PR c++/66583 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f8db2df..55b3c8c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4627,6 +4627,15 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3, if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1))) { + /* If arg1 is another cond_expr choosing between -1 and 0, + then we can use its comparison. It may help to avoid + additional comparison, produce more accurate diagnostics + and enables folding. */ + if (TREE_CODE (arg1) == VEC_COND_EXPR + && integer_minus_onep (TREE_OPERAND (arg1, 1)) + && integer_zerop (TREE_OPERAND (arg1, 2))) + arg1 = TREE_OPERAND (arg1, 0); + arg1 = force_rvalue (arg1, complain); arg2 = force_rvalue (arg2, complain); arg3 = force_rvalue (arg3, complain); @@ -4739,8 +4748,10 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3, } if (!COMPARISON_CLASS_P (arg1)) - arg1 = cp_build_binary_op (loc, NE_EXPR, arg1, - build_zero_cst (arg1_type), complain); + { + tree cmp_type = build_same_sized_truth_vector_type (arg1_type); + arg1 = build2 (NE_EXPR, cmp_type, arg1, build_zero_cst (arg1_type)); + } return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9e6f949..3147609 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3916,6 +3916,20 @@ build_binary_op (location_t location, enum tree_code code, tree op0, tree op1, return cp_build_binary_op (location, code, op0, op1, tf_warning_or_error); } +/* Build a vector comparison of ARG0 and ARG1 using CODE opcode + into a value of TYPE type. Comparison is done via VEC_COND_EXPR. */ + +static tree +build_vec_cmp (tree_code code, tree type, + tree arg0, tree arg1) +{ + tree zero_vec = build_zero_cst (type); + tree minus_one_vec = build_minus_one_cst (type); + tree cmp_type = build_same_sized_truth_vector_type(type); + tree cmp = build2 (code, cmp_type, arg0, arg1); + cmp = fold_if_not_in_template (cmp); + return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec); +} /* Build a binary-operation expression without default conversions. CODE is the kind of expression to build. @@ -4785,7 +4799,7 @@ cp_build_binary_op (location_t location, result_type = build_opaque_vector_type (intt, TYPE_VECTOR_SUBPARTS (type0)); converted = 1; - break; + return build_vec_cmp (resultcode, result_type, op0, op1); } build_type = boolean_type_node; if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 731e630..4a12ad6 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -5688,6 +5688,12 @@ mode returned by @code{TARGET_VECTORIZE_PREFERRED_SIMD_MODE}. The default is zero which means to not iterate over other vector sizes. @end deftypefn +@deftypefn {Target Hook} machine_mode TARGET_VECTORIZE_GET_MASK_MODE (unsigned @var{nunits}, unsigned @var{length}) +This hook returns mode to be used for a mask to be used for a vector +of specified @var{length} with @var{nunits} elements. By default an integer +vector mode of a proper size is returned. +@end deftypefn + @deftypefn {Target Hook} {void *} TARGET_VECTORIZE_INIT_COST (struct loop *@var{loop_info}) This hook should initialize target-specific data structures in preparation for modeling the costs of vectorizing a loop or basic block. The default allocates three unsigned integers for accumulating costs for the prologue, body, and epilogue of the loop or basic block. If @var{loop_info} is non-NULL, it identifies the loop being vectorized; otherwise a single block is being vectorized. @end deftypefn diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 0b52250d..6f0c252 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -4225,6 +4225,8 @@ address; but often a machine-dependent strategy can generate better code. @hook TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES +@hook TARGET_VECTORIZE_GET_MASK_MODE + @hook TARGET_VECTORIZE_INIT_COST @hook TARGET_VECTORIZE_ADD_STMT_COST diff --git a/gcc/optabs.c b/gcc/optabs.c index 223daf7..82a1ee6 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -5365,16 +5365,17 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2, op0a = TREE_OPERAND (op0, 0); op0b = TREE_OPERAND (op0, 1); tcode = TREE_CODE (op0); + unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a)); } else { /* Fake op0 < 0. */ - gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (op0))); + gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0))); op0a = op0; op0b = build_zero_cst (TREE_TYPE (op0)); tcode = LT_EXPR; + unsignedp = false; } - unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a)); cmp_op_mode = TYPE_MODE (TREE_TYPE (op0a)); diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 938e54b..58ecd7b 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -2184,10 +2184,16 @@ layout_type (tree type) TYPE_SATURATING (type) = TYPE_SATURATING (TREE_TYPE (type)); TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type)); - TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR, - TYPE_SIZE_UNIT (innertype), - size_int (nunits)); - TYPE_SIZE (type) = int_const_binop (MULT_EXPR, TYPE_SIZE (innertype), + /* Several boolean vector elements may fit in a single unit. */ + if (VECTOR_BOOLEAN_TYPE_P (type)) + TYPE_SIZE_UNIT (type) + = size_int (GET_MODE_SIZE (type->type_common.mode)); + else + TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR, + TYPE_SIZE_UNIT (innertype), + size_int (nunits)); + TYPE_SIZE (type) = int_const_binop (MULT_EXPR, + TYPE_SIZE (innertype), bitsize_int (nunits)); /* For vector types, we do not default to the mode's alignment. diff --git a/gcc/target.def b/gcc/target.def index 694e455..93478e8 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -1810,6 +1810,16 @@ The default is zero which means to not iterate over other vector sizes.", (void), default_autovectorize_vector_sizes) +/* Function to get a target mode for a vector mask. */ +DEFHOOK +(get_mask_mode, + "This hook returns mode to be used for a mask to be used for a vector\n\ +of specified @var{length} with @var{nunits} elements. By default an integer\n\ +vector mode of a proper size is returned.", + machine_mode, + (unsigned nunits, unsigned length), + default_get_mask_mode) + /* Target builtin that implements vector gather operation. */ DEFHOOK (builtin_gather, diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 5077ec9..01aaed07 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1087,6 +1087,20 @@ default_autovectorize_vector_sizes (void) return 0; } +/* By defaults a vector of integers is used as a mask. */ + +machine_mode +default_get_mask_mode (unsigned nunits, unsigned vector_size) +{ + unsigned elem_size = vector_size / nunits; + machine_mode elem_mode + = smallest_mode_for_size (elem_size * BITS_PER_UNIT, MODE_INT); + + gcc_assert (elem_size * nunits == vector_size); + + return mode_for_vector (elem_mode, nunits); +} + /* By default, the cost model accumulates three separate costs (prologue, loop body, and epilogue) for a vectorized loop or block. So allocate an array of three unsigned ints, set it to zero, and return its address. */ diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 77c284a..e13e087 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -100,6 +100,7 @@ default_builtin_support_vector_misalignment (machine_mode mode, int, bool); extern machine_mode default_preferred_simd_mode (machine_mode mode); extern unsigned int default_autovectorize_vector_sizes (void); +extern machine_mode default_get_mask_mode (unsigned, unsigned); extern void *default_init_cost (struct loop *); extern unsigned default_add_stmt_cost (void *, int, enum vect_cost_for_stmt, struct _stmt_vec_info *, int, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ed725ee..3f325b9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2015-10-21 Ilya Enkovich + * g++.dg/ext/vector22.C: Allow VEC_COND_EXPR. + +2015-10-21 Ilya Enkovich + * gcc.dg/lto/simd-function_0.c: New test. 2015-10-21 Uros Bizjak diff --git a/gcc/testsuite/g++.dg/ext/vector22.C b/gcc/testsuite/g++.dg/ext/vector22.C index daf4e19..5d28637 100644 --- a/gcc/testsuite/g++.dg/ext/vector22.C +++ b/gcc/testsuite/g++.dg/ext/vector22.C @@ -18,4 +18,3 @@ void h(vec*a){ } /* { dg-final { scan-tree-dump-not "~" "gimple" } } */ -/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR" "gimple" } } */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 5bf546e..8e3e810 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -3465,10 +3465,10 @@ verify_gimple_comparison (tree type, tree op0, tree op1) return true; } } - /* Or an integer vector type with the same size and element count + /* Or a boolean vector type with the same element count as the comparison operand types. */ else if (TREE_CODE (type) == VECTOR_TYPE - && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE) + && TREE_CODE (TREE_TYPE (type)) == BOOLEAN_TYPE) { if (TREE_CODE (op0_type) != VECTOR_TYPE || TREE_CODE (op1_type) != VECTOR_TYPE) @@ -3479,12 +3479,7 @@ verify_gimple_comparison (tree type, tree op0, tree op1) return true; } - if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type) - || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type))) - != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0_type)))) - /* The result of a vector comparison is of signed - integral type. */ - || TYPE_UNSIGNED (TREE_TYPE (type))) + if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type)) { error ("invalid vector comparison resulting type"); debug_generic_expr (type); @@ -3971,15 +3966,13 @@ verify_gimple_assign_ternary (gassign *stmt) break; case VEC_COND_EXPR: - if (!VECTOR_INTEGER_TYPE_P (rhs1_type) - || TYPE_SIGN (rhs1_type) != SIGNED - || TYPE_SIZE (rhs1_type) != TYPE_SIZE (lhs_type) + if (!VECTOR_BOOLEAN_TYPE_P (rhs1_type) || TYPE_VECTOR_SUBPARTS (rhs1_type) != TYPE_VECTOR_SUBPARTS (lhs_type)) { - error ("the first argument of a VEC_COND_EXPR must be of a signed " - "integral vector type of the same size and number of " - "elements as the result"); + error ("the first argument of a VEC_COND_EXPR must be of a " + "boolean vector type of the same number of elements " + "as the result"); debug_generic_expr (lhs_type); debug_generic_expr (rhs1_type); return true; diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index dad38a2..a20b9af 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -105,14 +105,27 @@ build_word_mode_vector_type (int nunits) } typedef tree (*elem_op_func) (gimple_stmt_iterator *, - tree, tree, tree, tree, tree, enum tree_code); + tree, tree, tree, tree, tree, enum tree_code, + tree); static inline tree tree_vec_extract (gimple_stmt_iterator *gsi, tree type, tree t, tree bitsize, tree bitpos) { if (bitpos) - return gimplify_build3 (gsi, BIT_FIELD_REF, type, t, bitsize, bitpos); + { + if (TREE_CODE (type) == BOOLEAN_TYPE) + { + tree itype + = build_nonstandard_integer_type (tree_to_uhwi (bitsize), 0); + tree field = gimplify_build3 (gsi, BIT_FIELD_REF, itype, t, + bitsize, bitpos); + return gimplify_build2 (gsi, NE_EXPR, type, field, + build_zero_cst (itype)); + } + else + return gimplify_build3 (gsi, BIT_FIELD_REF, type, t, bitsize, bitpos); + } else return gimplify_build1 (gsi, VIEW_CONVERT_EXPR, type, t); } @@ -120,7 +133,7 @@ tree_vec_extract (gimple_stmt_iterator *gsi, tree type, static tree do_unop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b ATTRIBUTE_UNUSED, tree bitpos, tree bitsize, - enum tree_code code) + enum tree_code code, tree type ATTRIBUTE_UNUSED) { a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); return gimplify_build1 (gsi, code, inner_type, a); @@ -128,7 +141,8 @@ do_unop (gimple_stmt_iterator *gsi, tree inner_type, tree a, static tree do_binop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, - tree bitpos, tree bitsize, enum tree_code code) + tree bitpos, tree bitsize, enum tree_code code, + tree type ATTRIBUTE_UNUSED) { if (TREE_CODE (TREE_TYPE (a)) == VECTOR_TYPE) a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); @@ -145,20 +159,12 @@ do_binop (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, size equal to the size of INNER_TYPE. */ static tree do_compare (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, - tree bitpos, tree bitsize, enum tree_code code) + tree bitpos, tree bitsize, enum tree_code code, tree type) { - tree comp_type; - a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); b = tree_vec_extract (gsi, inner_type, b, bitsize, bitpos); - comp_type = build_nonstandard_integer_type - (GET_MODE_BITSIZE (TYPE_MODE (inner_type)), 0); - - return gimplify_build3 (gsi, COND_EXPR, comp_type, - fold_build2 (code, boolean_type_node, a, b), - build_int_cst (comp_type, -1), - build_int_cst (comp_type, 0)); + return gimplify_build2 (gsi, code, TREE_TYPE (type), a, b); } /* Expand vector addition to scalars. This does bit twiddling @@ -177,7 +183,7 @@ do_compare (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, static tree do_plus_minus (gimple_stmt_iterator *gsi, tree word_type, tree a, tree b, tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED, - enum tree_code code) + enum tree_code code, tree type ATTRIBUTE_UNUSED) { tree inner_type = TREE_TYPE (TREE_TYPE (a)); unsigned HOST_WIDE_INT max; @@ -209,7 +215,8 @@ static tree do_negate (gimple_stmt_iterator *gsi, tree word_type, tree b, tree unused ATTRIBUTE_UNUSED, tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED, - enum tree_code code ATTRIBUTE_UNUSED) + enum tree_code code ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED) { tree inner_type = TREE_TYPE (TREE_TYPE (b)); HOST_WIDE_INT max; @@ -255,7 +262,7 @@ expand_vector_piecewise (gimple_stmt_iterator *gsi, elem_op_func f, for (i = 0; i < nunits; i += delta, index = int_const_binop (PLUS_EXPR, index, part_width)) { - tree result = f (gsi, inner_type, a, b, index, part_width, code); + tree result = f (gsi, inner_type, a, b, index, part_width, code, type); constructor_elt ce = {NULL_TREE, result}; v->quick_push (ce); } @@ -298,7 +305,7 @@ expand_vector_parallel (gimple_stmt_iterator *gsi, elem_op_func f, tree type, /* Use a single scalar operation with a mode no wider than word_mode. */ mode = mode_for_size (tree_to_uhwi (TYPE_SIZE (type)), MODE_INT, 0); compute_type = lang_hooks.types.type_for_mode (mode, 1); - result = f (gsi, compute_type, a, b, NULL_TREE, NULL_TREE, code); + result = f (gsi, compute_type, a, b, NULL_TREE, NULL_TREE, code, type); warning_at (loc, OPT_Wvector_operation_performance, "vector operation will be expanded with a " "single scalar operation"); @@ -615,11 +622,12 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0, if (addend == NULL_TREE && expand_vec_cond_expr_p (type, type)) { - tree zero, cst, cond; + tree zero, cst, cond, mask_type; gimple *stmt; + mask_type = build_same_sized_truth_vector_type (type); zero = build_zero_cst (type); - cond = build2 (LT_EXPR, type, op0, zero); + cond = build2 (LT_EXPR, mask_type, op0, zero); for (i = 0; i < nunits; i++) vec[i] = build_int_cst (TREE_TYPE (type), ((unsigned HOST_WIDE_INT) 1 @@ -1386,7 +1394,8 @@ count_type_subparts (tree type) static tree do_cond (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b, - tree bitpos, tree bitsize, enum tree_code code) + tree bitpos, tree bitsize, enum tree_code code, + tree type ATTRIBUTE_UNUSED) { if (TREE_CODE (TREE_TYPE (a)) == VECTOR_TYPE) a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); @@ -1496,6 +1505,12 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi) if (TREE_CODE (type) != VECTOR_TYPE) return; + /* A scalar operation pretending to be a vector one. */ + if (VECTOR_BOOLEAN_TYPE_P (type) + && !VECTOR_MODE_P (TYPE_MODE (type)) + && TYPE_MODE (type) != BLKmode) + return; + if (CONVERT_EXPR_CODE_P (code) || code == FLOAT_EXPR || code == FIX_TRUNC_EXPR diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 3896e5c..19f62d0 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -7254,10 +7254,7 @@ vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi, if (!vect_is_simple_use (else_clause, stmt_info->vinfo, &def_stmt, &dt)) return false; - unsigned int prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vectype))); - /* The result of a vector comparison should be signed type. */ - tree cmp_type = build_nonstandard_integer_type (prec, 0); - vec_cmp_type = get_same_sized_vectype (cmp_type, vectype); + vec_cmp_type = build_same_sized_truth_vector_type (comp_vectype); if (vec_cmp_type == NULL_TREE) return false; @@ -8067,6 +8064,9 @@ get_vectype_for_scalar_type (tree scalar_type) tree get_same_sized_vectype (tree scalar_type, tree vector_type) { + if (TREE_CODE (scalar_type) == BOOLEAN_TYPE) + return build_same_sized_truth_vector_type (vector_type); + return get_vectype_for_scalar_type_and_size (scalar_type, GET_MODE_SIZE (TYPE_MODE (vector_type))); } diff --git a/gcc/tree.c b/gcc/tree.c index 9d0e9de..6c75699 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -8041,6 +8041,34 @@ build_nonstandard_integer_type (unsigned HOST_WIDE_INT precision, return ret; } +#define MAX_BOOL_CACHED_PREC \ + (HOST_BITS_PER_WIDE_INT > 64 ? HOST_BITS_PER_WIDE_INT : 64) +static GTY(()) tree nonstandard_boolean_type_cache[MAX_BOOL_CACHED_PREC + 1]; + +/* Builds a boolean type of precision PRECISION. + Used for boolean vectors to choose proper vector element size. */ +tree +build_nonstandard_boolean_type (unsigned HOST_WIDE_INT precision) +{ + tree type; + + if (precision <= MAX_BOOL_CACHED_PREC) + { + type = nonstandard_boolean_type_cache[precision]; + if (type) + return type; + } + + type = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (type) = precision; + fixup_unsigned_type (type); + + if (precision <= MAX_INT_CACHED_PREC) + nonstandard_boolean_type_cache[precision] = type; + + return type; +} + /* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE or BOOLEAN_TYPE) with low bound LOWVAL and high bound HIGHVAL. If SHARED is true, reuse such a type that has already been constructed. */ @@ -9791,8 +9819,9 @@ make_vector_type (tree innertype, int nunits, machine_mode mode) if (TYPE_STRUCTURAL_EQUALITY_P (innertype)) SET_TYPE_STRUCTURAL_EQUALITY (t); - else if (TYPE_CANONICAL (innertype) != innertype - || mode != VOIDmode) + else if ((TYPE_CANONICAL (innertype) != innertype + || mode != VOIDmode) + && !VECTOR_BOOLEAN_TYPE_P (t)) TYPE_CANONICAL (t) = make_vector_type (TYPE_CANONICAL (innertype), nunits, VOIDmode); @@ -10617,6 +10646,40 @@ build_vector_type (tree innertype, int nunits) return make_vector_type (innertype, nunits, VOIDmode); } +/* Build truth vector with specified length and number of units. */ + +tree +build_truth_vector_type (unsigned nunits, unsigned vector_size) +{ + machine_mode mask_mode = targetm.vectorize.get_mask_mode (nunits, + vector_size); + + gcc_assert (mask_mode != VOIDmode); + + unsigned HOST_WIDE_INT esize = GET_MODE_BITSIZE (mask_mode) / nunits; + gcc_assert (esize * nunits == GET_MODE_BITSIZE (mask_mode)); + + tree bool_type = build_nonstandard_boolean_type (esize); + + return make_vector_type (bool_type, nunits, mask_mode); +} + +/* Returns a vector type corresponding to a comparison of VECTYPE. */ + +tree +build_same_sized_truth_vector_type (tree vectype) +{ + if (VECTOR_BOOLEAN_TYPE_P (vectype)) + return vectype; + + unsigned HOST_WIDE_INT size = GET_MODE_SIZE (TYPE_MODE (vectype)); + + if (!size) + size = tree_to_uhwi (TYPE_SIZE_UNIT (vectype)); + + return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (vectype), size); +} + /* Similarly, but builds a variant type with TYPE_VECTOR_OPAQUE set. */ tree @@ -11103,9 +11166,10 @@ truth_type_for (tree type) { if (TREE_CODE (type) == VECTOR_TYPE) { - tree elem = lang_hooks.types.type_for_size - (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (type))), 0); - return build_opaque_vector_type (elem, TYPE_VECTOR_SUBPARTS (type)); + if (VECTOR_BOOLEAN_TYPE_P (type)) + return type; + return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (type), + GET_MODE_SIZE (TYPE_MODE (type))); } else return boolean_type_node; diff --git a/gcc/tree.h b/gcc/tree.h index f62cd27..300077c 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -470,6 +470,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE) +/* Nonzero if TYPE represents a vector of booleans. */ + +#define VECTOR_BOOLEAN_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == VECTOR_TYPE \ + && TREE_CODE (TREE_TYPE (TYPE)) == BOOLEAN_TYPE) + /* Nonzero if TYPE represents an integral type. Note that we do not include COMPLEX types here. Keep these checks in ascending code order. */ @@ -3895,6 +3901,8 @@ extern tree build_reference_type_for_mode (tree, machine_mode, bool); extern tree build_reference_type (tree); extern tree build_vector_type_for_mode (tree, machine_mode); extern tree build_vector_type (tree innertype, int nunits); +extern tree build_truth_vector_type (unsigned, unsigned); +extern tree build_same_sized_truth_vector_type (tree vectype); extern tree build_opaque_vector_type (tree innertype, int nunits); extern tree build_index_type (tree); extern tree build_array_type (tree, tree); @@ -4615,6 +4623,7 @@ extern void init_ttree (void); extern void build_common_tree_nodes (bool, bool); extern void build_common_builtin_nodes (void); extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int); +extern tree build_nonstandard_boolean_type (unsigned HOST_WIDE_INT); extern tree build_range_type (tree, tree, tree); extern tree build_nonshared_range_type (tree, tree, tree); extern bool subrange_type_for_debug_p (const_tree, tree *, tree *); -- 2.7.4