diff options
Diffstat (limited to 'gcc/tree-vect-slp.c')
-rw-r--r-- | gcc/tree-vect-slp.c | 255 |
1 files changed, 116 insertions, 139 deletions
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index 0800a3f6b23..15d589d3452 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -403,9 +403,9 @@ again: { case vect_constant_def: case vect_external_def: - case vect_reduction_def: break; + case vect_reduction_def: case vect_induction_def: case vect_internal_def: oprnd_info->def_stmts.quick_push (def_stmt); @@ -943,13 +943,31 @@ vect_build_slp_tree (vec_info *vinfo, else return NULL; - /* If the SLP node is a PHI (induction), terminate the recursion. */ + /* If the SLP node is a PHI (induction or reduction), terminate + the recursion. */ if (gimple_code (stmt) == GIMPLE_PHI) { - FOR_EACH_VEC_ELT (stmts, i, stmt) - if (stmt != stmts[0]) - /* Induction from different IVs is not supported. */ - return NULL; + vect_def_type def_type = STMT_VINFO_DEF_TYPE (vinfo_for_stmt (stmt)); + /* Induction from different IVs is not supported. */ + if (def_type == vect_induction_def) + { + FOR_EACH_VEC_ELT (stmts, i, stmt) + if (stmt != stmts[0]) + return NULL; + } + else + { + /* Else def types have to match. */ + FOR_EACH_VEC_ELT (stmts, i, stmt) + { + /* But for reduction chains only check on the first stmt. */ + if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) + && GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) != stmt) + continue; + if (STMT_VINFO_DEF_TYPE (vinfo_for_stmt (stmt)) != def_type) + return NULL; + } + } node = vect_create_new_slp_node (stmts); return node; } @@ -1005,6 +1023,7 @@ vect_build_slp_tree (vec_info *vinfo, unsigned int j; if (oprnd_info->first_dt != vect_internal_def + && oprnd_info->first_dt != vect_reduction_def && oprnd_info->first_dt != vect_induction_def) continue; @@ -2102,15 +2121,13 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) { unsigned int i; gimple *first_element; - bool ok = false; if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "=== vect_analyze_slp ===\n"); /* Find SLP sequences starting from groups of grouped stores. */ FOR_EACH_VEC_ELT (vinfo->grouped_stores, i, first_element) - if (vect_analyze_slp_instance (vinfo, first_element, max_tree_size)) - ok = true; + vect_analyze_slp_instance (vinfo, first_element, max_tree_size); if (loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo)) { @@ -2118,22 +2135,28 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) { /* Find SLP sequences starting from reduction chains. */ FOR_EACH_VEC_ELT (loop_vinfo->reduction_chains, i, first_element) - if (vect_analyze_slp_instance (vinfo, first_element, + if (! vect_analyze_slp_instance (vinfo, first_element, max_tree_size)) - ok = true; - else - return false; - - /* Don't try to vectorize SLP reductions if reduction chain was - detected. */ - return ok; + { + /* Dissolve reduction chain group. */ + gimple *next, *stmt = first_element; + while (stmt) + { + stmt_vec_info vinfo = vinfo_for_stmt (stmt); + next = GROUP_NEXT_ELEMENT (vinfo); + GROUP_FIRST_ELEMENT (vinfo) = NULL; + GROUP_NEXT_ELEMENT (vinfo) = NULL; + stmt = next; + } + STMT_VINFO_DEF_TYPE (vinfo_for_stmt (first_element)) + = vect_internal_def; + } } /* Find SLP sequences starting from groups of reductions. */ - if (loop_vinfo->reductions.length () > 1 - && vect_analyze_slp_instance (vinfo, loop_vinfo->reductions[0], - max_tree_size)) - ok = true; + if (loop_vinfo->reductions.length () > 1) + vect_analyze_slp_instance (vinfo, loop_vinfo->reductions[0], + max_tree_size); } return true; @@ -2432,7 +2455,7 @@ destroy_bb_vec_info (bb_vec_info bb_vinfo) the subtree. Return TRUE if the operations are supported. */ static bool -vect_slp_analyze_node_operations (slp_tree node) +vect_slp_analyze_node_operations (slp_tree node, slp_instance node_instance) { bool dummy; int i, j; @@ -2443,32 +2466,73 @@ vect_slp_analyze_node_operations (slp_tree node) return true; FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child) - if (!vect_slp_analyze_node_operations (child)) + if (!vect_slp_analyze_node_operations (child, node_instance)) return false; - bool res = true; - FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt) + stmt = SLP_TREE_SCALAR_STMTS (node)[0]; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + gcc_assert (stmt_info); + gcc_assert (STMT_SLP_TYPE (stmt_info) != loop_vect); + + /* For BB vectorization vector types are assigned here. + Memory accesses already got their vector type assigned + in vect_analyze_data_refs. */ + bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info); + if (bb_vinfo + && ! STMT_VINFO_DATA_REF (stmt_info)) { - stmt_vec_info stmt_info = vinfo_for_stmt (stmt); - gcc_assert (stmt_info); - gcc_assert (STMT_SLP_TYPE (stmt_info) != loop_vect); - - /* Push SLP node def-type to stmt operands. */ - FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), j, child) - if (SLP_TREE_DEF_TYPE (child) != vect_internal_def) - STMT_VINFO_DEF_TYPE (vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (child)[i])) - = SLP_TREE_DEF_TYPE (child); - res = vect_analyze_stmt (stmt, &dummy, node); - /* Restore def-types. */ - FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), j, child) - if (SLP_TREE_DEF_TYPE (child) != vect_internal_def) - STMT_VINFO_DEF_TYPE (vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (child)[i])) - = vect_internal_def; - if (! res) - break; + gcc_assert (PURE_SLP_STMT (stmt_info)); + + tree scalar_type = TREE_TYPE (gimple_get_lhs (stmt)); + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_NOTE, vect_location, + "get vectype for scalar type: "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, scalar_type); + dump_printf (MSG_NOTE, "\n"); + } + + tree vectype = get_vectype_for_scalar_type (scalar_type); + if (!vectype) + { + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "not SLPed: unsupported data-type "); + dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, + scalar_type); + dump_printf (MSG_MISSED_OPTIMIZATION, "\n"); + } + return false; + } + + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_NOTE, vect_location, "vectype: "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, vectype); + dump_printf (MSG_NOTE, "\n"); + } + + gimple *sstmt; + FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, sstmt) + STMT_VINFO_VECTYPE (vinfo_for_stmt (sstmt)) = vectype; } - return res; + /* Push SLP node def-type to stmt operands. */ + FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), j, child) + if (SLP_TREE_DEF_TYPE (child) != vect_internal_def) + STMT_VINFO_DEF_TYPE (vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (child)[0])) + = SLP_TREE_DEF_TYPE (child); + bool res = vect_analyze_stmt (stmt, &dummy, node, node_instance); + /* Restore def-types. */ + FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), j, child) + if (SLP_TREE_DEF_TYPE (child) != vect_internal_def) + STMT_VINFO_DEF_TYPE (vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (child)[0])) + = vect_internal_def; + if (! res) + return false; + + return true; } @@ -2487,7 +2551,8 @@ vect_slp_analyze_operations (vec<slp_instance> slp_instances, void *data) for (i = 0; slp_instances.iterate (i, &instance); ) { - if (!vect_slp_analyze_node_operations (SLP_INSTANCE_TREE (instance))) + if (!vect_slp_analyze_node_operations (SLP_INSTANCE_TREE (instance), + instance)) { dump_printf_loc (MSG_NOTE, vect_location, "removing SLP instance operations starting from: "); @@ -2976,8 +3041,7 @@ vect_mask_constant_operand_p (gimple *stmt, int opnum) static void vect_get_constant_vectors (tree op, slp_tree slp_node, vec<tree> *vec_oprnds, - unsigned int op_num, unsigned int number_of_vectors, - int reduc_index) + unsigned int op_num, unsigned int number_of_vectors) { vec<gimple *> stmts = SLP_TREE_SCALAR_STMTS (slp_node); gimple *stmt = stmts[0]; @@ -2996,8 +3060,6 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, bool constant_p, is_store; tree neutral_op = NULL; enum tree_code code = gimple_expr_code (stmt); - gimple *def_stmt; - struct loop *loop; gimple_seq ctor_seq = NULL; /* Check if vector type is a boolean vector. */ @@ -3009,64 +3071,6 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, vector_type = get_vectype_for_scalar_type (TREE_TYPE (op)); nunits = TYPE_VECTOR_SUBPARTS (vector_type); - if (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def - && reduc_index != -1) - { - op_num = reduc_index; - op = gimple_op (stmt, op_num + 1); - /* For additional copies (see the explanation of NUMBER_OF_COPIES below) - we need either neutral operands or the original operands. See - get_initial_def_for_reduction() for details. */ - switch (code) - { - case WIDEN_SUM_EXPR: - case DOT_PROD_EXPR: - case SAD_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (op))) - neutral_op = build_real (TREE_TYPE (op), dconst0); - else - neutral_op = build_int_cst (TREE_TYPE (op), 0); - - break; - - case MULT_EXPR: - if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (op))) - neutral_op = build_real (TREE_TYPE (op), dconst1); - else - neutral_op = build_int_cst (TREE_TYPE (op), 1); - - break; - - case BIT_AND_EXPR: - neutral_op = build_int_cst (TREE_TYPE (op), -1); - break; - - /* For MIN/MAX we don't have an easy neutral operand but - the initial values can be used fine here. Only for - a reduction chain we have to force a neutral element. */ - case MAX_EXPR: - case MIN_EXPR: - if (!GROUP_FIRST_ELEMENT (stmt_vinfo)) - neutral_op = NULL; - else - { - def_stmt = SSA_NAME_DEF_STMT (op); - loop = (gimple_bb (stmt))->loop_father; - neutral_op = PHI_ARG_DEF_FROM_EDGE (def_stmt, - loop_preheader_edge (loop)); - } - break; - - default: - gcc_assert (!GROUP_FIRST_ELEMENT (stmt_vinfo)); - neutral_op = NULL; - } - } - if (STMT_VINFO_DATA_REF (stmt_vinfo)) { is_store = true; @@ -3077,11 +3081,6 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, gcc_assert (op); - if (CONSTANT_CLASS_P (op)) - constant_p = true; - else - constant_p = false; - /* NUMBER_OF_COPIES is the number of times we need to use the same values in created vectors. It is greater than 1 if unrolling is performed. @@ -3101,6 +3100,7 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, number_of_copies = nunits * number_of_vectors / group_size; number_of_places_left_in_vector = nunits; + constant_p = true; elts = XALLOCAVEC (tree, nunits); bool place_after_defs = false; for (j = 0; j < number_of_copies; j++) @@ -3154,25 +3154,6 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, } } - if (reduc_index != -1) - { - loop = (gimple_bb (stmt))->loop_father; - def_stmt = SSA_NAME_DEF_STMT (op); - - gcc_assert (loop); - - /* Get the def before the loop. In reduction chain we have only - one initial value. */ - if ((j != (number_of_copies - 1) - || (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) - && i != 0)) - && neutral_op) - op = neutral_op; - else - op = PHI_ARG_DEF_FROM_EDGE (def_stmt, - loop_preheader_edge (loop)); - } - /* Create 'vect_ = {op0,op1,...,opn}'. */ number_of_places_left_in_vector--; tree orig_op = op; @@ -3236,8 +3217,6 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, if (number_of_places_left_in_vector == 0) { - number_of_places_left_in_vector = nunits; - if (constant_p) vec_cst = build_vector (vector_type, elts); else @@ -3268,6 +3247,8 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, } voprnds.quick_push (init); place_after_defs = false; + number_of_places_left_in_vector = nunits; + constant_p = true; } } } @@ -3340,7 +3321,7 @@ vect_get_slp_vect_defs (slp_tree slp_node, vec<tree> *vec_oprnds) void vect_get_slp_defs (vec<tree> ops, slp_tree slp_node, - vec<vec<tree> > *vec_oprnds, int reduc_index) + vec<vec<tree> > *vec_oprnds) { gimple *first_stmt; int number_of_vects = 0, i; @@ -3421,20 +3402,16 @@ vect_get_slp_defs (vec<tree> ops, slp_tree slp_node, /* For reduction defs we call vect_get_constant_vectors (), since we are looking for initial loop invariant values. */ - if (vectorized_defs && reduc_index == -1) + if (vectorized_defs) /* The defs are already vectorized. */ vect_get_slp_vect_defs (child, &vec_defs); else /* Build vectors from scalar defs. */ vect_get_constant_vectors (oprnd, slp_node, &vec_defs, i, - number_of_vects, reduc_index); + number_of_vects); vec_oprnds->quick_push (vec_defs); - /* For reductions, we only need initial values. */ - if (reduc_index != -1) - return; - first_iteration = false; } } |