Hi, This patch adds a special handling of boolean vector invariants. We need additional code to determine type of generated invariant. For VEC_COND_EXPR case we even provide this type directly because statement vectype doesn't allow us to compute it. Separate code is used to generate and expand such vectors.
Thanks, Ilya -- gcc/ 2015-10-08 Ilya Enkovich <enkovich....@gmail.com> * expr.c (const_vector_mask_from_tree): New. (const_vector_from_tree): Use const_vector_mask_from_tree for boolean vectors. * tree-vect-stmts.c (vect_init_vector): Support boolean vector invariants. (vect_get_vec_def_for_operand): Add VECTYPE arg. (vectorizable_condition): Directly provide vectype for invariants used in comparison. * tree-vectorizer.h (vect_get_vec_def_for_operand): Add VECTYPE arg. diff --git a/gcc/expr.c b/gcc/expr.c index 88da8cb..a624a34 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11320,6 +11320,40 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range, return 1; } +/* Return a CONST_VECTOR rtx representing vector mask for + a VECTOR_CST of booleans. */ +static rtx +const_vector_mask_from_tree (tree exp) +{ + rtvec v; + unsigned i; + int units; + tree elt; + machine_mode inner, mode; + + mode = TYPE_MODE (TREE_TYPE (exp)); + units = GET_MODE_NUNITS (mode); + inner = GET_MODE_INNER (mode); + + v = rtvec_alloc (units); + + for (i = 0; i < VECTOR_CST_NELTS (exp); ++i) + { + elt = VECTOR_CST_ELT (exp, i); + + gcc_assert (TREE_CODE (elt) == INTEGER_CST); + if (integer_zerop (elt)) + RTVEC_ELT (v, i) = CONST0_RTX (inner); + else if (integer_onep (elt) + || integer_minus_onep (elt)) + RTVEC_ELT (v, i) = CONSTM1_RTX (inner); + else + gcc_unreachable (); + } + + return gen_rtx_CONST_VECTOR (mode, v); +} + /* Return a CONST_VECTOR rtx for a VECTOR_CST tree. */ static rtx const_vector_from_tree (tree exp) @@ -11335,6 +11369,9 @@ const_vector_from_tree (tree exp) if (initializer_zerop (exp)) return CONST0_RTX (mode); + if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (exp))) + return const_vector_mask_from_tree (exp); + units = GET_MODE_NUNITS (mode); inner = GET_MODE_INNER (mode); diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 6949c71..337ea7b 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -1308,27 +1308,61 @@ vect_init_vector_1 (gimple *stmt, gimple *new_stmt, gimple_stmt_iterator *gsi) tree vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi) { + tree val_type = TREE_TYPE (val); + machine_mode mode = TYPE_MODE (type); + machine_mode val_mode = TYPE_MODE(val_type); tree new_var; gimple *init_stmt; tree vec_oprnd; tree new_temp; if (TREE_CODE (type) == VECTOR_TYPE - && TREE_CODE (TREE_TYPE (val)) != VECTOR_TYPE) - { - if (!types_compatible_p (TREE_TYPE (type), TREE_TYPE (val))) + && TREE_CODE (val_type) != VECTOR_TYPE) + { + /* Handle vector of bool represented as a vector of + integers here rather than on expand because it is + a default mask type for targets. Vector mask is + built in a following way: + + tmp = (int)val + vec_tmp = {tmp, ..., tmp} + vec_cst = VIEW_CONVERT_EXPR<vector(N) _Bool>(vec_tmp); */ + if (TREE_CODE (val_type) == BOOLEAN_TYPE + && VECTOR_MODE_P (mode) + && SCALAR_INT_MODE_P (GET_MODE_INNER (mode)) + && GET_MODE_INNER (mode) != val_mode) { - if (CONSTANT_CLASS_P (val)) - val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val); - else + unsigned size = GET_MODE_BITSIZE (GET_MODE_INNER (mode)); + tree stype = build_nonstandard_integer_type (size, 1); + tree vectype = get_vectype_for_scalar_type (stype); + + new_temp = make_ssa_name (stype); + init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val); + vect_init_vector_1 (stmt, init_stmt, gsi); + + val = make_ssa_name (vectype); + new_temp = build_vector_from_val (vectype, new_temp); + init_stmt = gimple_build_assign (val, new_temp); + vect_init_vector_1 (stmt, init_stmt, gsi); + + val = build1 (VIEW_CONVERT_EXPR, type, val); + } + else + { + if (!types_compatible_p (TREE_TYPE (type), val_type)) { - new_temp = make_ssa_name (TREE_TYPE (type)); - init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val); - vect_init_vector_1 (stmt, init_stmt, gsi); - val = new_temp; + if (CONSTANT_CLASS_P (val)) + val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (type), val); + else + { + new_temp = make_ssa_name (TREE_TYPE (type)); + init_stmt = gimple_build_assign (new_temp, NOP_EXPR, val); + vect_init_vector_1 (stmt, init_stmt, gsi); + val = new_temp; + } } + val = build_vector_from_val (type, val); } - val = build_vector_from_val (type, val); } new_var = vect_get_new_vect_var (type, vect_simple_var, "cst_"); @@ -1350,16 +1384,19 @@ vect_init_vector (gimple *stmt, tree val, tree type, gimple_stmt_iterator *gsi) STMT_VINFO_VEC_STMT of the defining stmt holds the relevant def. In case OP is an invariant or constant, a new stmt that creates a vector def - needs to be introduced. */ + needs to be introduced. VECTYPE may be used to specify a required type for + vector invariant. */ tree -vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def) +vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def, + tree vectype) { tree vec_oprnd; gimple *vec_stmt; gimple *def_stmt; stmt_vec_info def_stmt_info = NULL; stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt); + tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo); unsigned int nunits; loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo); tree def; @@ -1403,7 +1440,14 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def) /* Case 1: operand is a constant. */ case vect_constant_def: { - vector_type = get_vectype_for_scalar_type (TREE_TYPE (op)); + if (vectype) + vector_type = vectype; + else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE + && VECTOR_BOOLEAN_TYPE_P (stmt_vectype)) + vector_type = build_same_sized_truth_vector_type (stmt_vectype); + else + vector_type = get_vectype_for_scalar_type (TREE_TYPE (op)); + gcc_assert (vector_type); nunits = TYPE_VECTOR_SUBPARTS (vector_type); @@ -1421,7 +1465,13 @@ vect_get_vec_def_for_operand (tree op, gimple *stmt, tree *scalar_def) /* Case 2: operand is defined outside the loop - loop invariant. */ case vect_external_def: { - vector_type = get_vectype_for_scalar_type (TREE_TYPE (def)); + if (vectype) + vector_type = vectype; + else if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE + && VECTOR_BOOLEAN_TYPE_P (stmt_vectype)) + vector_type = build_same_sized_truth_vector_type (stmt_vectype); + else + vector_type = get_vectype_for_scalar_type (TREE_TYPE (def)); gcc_assert (vector_type); if (scalar_def) @@ -7437,13 +7487,13 @@ vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi, gimple *gtemp; vec_cond_lhs = vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 0), - stmt, NULL); + stmt, NULL, comp_vectype); vect_is_simple_use (TREE_OPERAND (cond_expr, 0), stmt, loop_vinfo, NULL, >emp, &def, &dts[0]); vec_cond_rhs = vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1), - stmt, NULL); + stmt, NULL, comp_vectype); vect_is_simple_use (TREE_OPERAND (cond_expr, 1), stmt, loop_vinfo, NULL, >emp, &def, &dts[1]); if (reduc_index == 1) diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 23a82ee..1a1e509 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1032,7 +1032,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int, extern void vect_finish_stmt_generation (gimple *, gimple *, gimple_stmt_iterator *); extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info); -extern tree vect_get_vec_def_for_operand (tree, gimple *, tree *); +extern tree vect_get_vec_def_for_operand (tree, gimple *, tree *, tree = NULL); extern tree vect_init_vector (gimple *, tree, tree, gimple_stmt_iterator *); extern tree vect_get_vec_def_for_stmt_copy (enum vect_def_type, tree);