diff options
author | Thomas Schwinge <tschwinge@baylibre.com> | 2024-03-11 22:51:28 +0100 |
---|---|---|
committer | Thomas Schwinge <tschwinge@baylibre.com> | 2024-03-11 22:51:28 +0100 |
commit | a95e21151a6366e7344d0f1983f99e318c5a7097 (patch) | |
tree | 11d987406d9ce8399ec1736477d971ef09344df2 /gcc/tree-vect-loop.cc | |
parent | 02d394b2736afa9a24ab3e1b8ad56fd6ac37e0f4 (diff) | |
parent | af4bb221153359f5948da917d5ef2df738bb1e61 (diff) | |
download | gcc-a95e21151a6366e7344d0f1983f99e318c5a7097.zip gcc-a95e21151a6366e7344d0f1983f99e318c5a7097.tar.gz gcc-a95e21151a6366e7344d0f1983f99e318c5a7097.tar.bz2 |
Merge commit 'af4bb221153359f5948da917d5ef2df738bb1e61' into HEAD
Diffstat (limited to 'gcc/tree-vect-loop.cc')
-rw-r--r-- | gcc/tree-vect-loop.cc | 262 |
1 files changed, 172 insertions, 90 deletions
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 23c6e82..ebab195 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -851,80 +851,137 @@ vect_fixup_scalar_cycles_with_patterns (loop_vec_info loop_vinfo) in NUMBER_OF_ITERATIONSM1. Place the condition under which the niter information holds in ASSUMPTIONS. - Return the loop exit condition. */ + Return the loop exit conditions. */ -static gcond * -vect_get_loop_niters (class loop *loop, tree *assumptions, +static vec<gcond *> +vect_get_loop_niters (class loop *loop, const_edge main_exit, tree *assumptions, tree *number_of_iterations, tree *number_of_iterationsm1) { - edge exit = single_exit (loop); + auto_vec<edge> exits = get_loop_exit_edges (loop); + vec<gcond *> conds; + conds.create (exits.length ()); class tree_niter_desc niter_desc; tree niter_assumptions, niter, may_be_zero; - gcond *cond = get_loop_exit_condition (loop); *assumptions = boolean_true_node; *number_of_iterationsm1 = chrec_dont_know; *number_of_iterations = chrec_dont_know; + DUMP_VECT_SCOPE ("get_loop_niters"); - if (!exit) - return cond; + if (exits.is_empty ()) + return conds; + + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "Loop has %d exits.\n", + exits.length ()); - may_be_zero = NULL_TREE; - if (!number_of_iterations_exit_assumptions (loop, exit, &niter_desc, NULL) - || chrec_contains_undetermined (niter_desc.niter)) - return cond; + edge exit; + unsigned int i; + FOR_EACH_VEC_ELT (exits, i, exit) + { + gcond *cond = get_loop_exit_condition (exit); + if (cond) + conds.safe_push (cond); - niter_assumptions = niter_desc.assumptions; - may_be_zero = niter_desc.may_be_zero; - niter = niter_desc.niter; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "Analyzing exit %d...\n", i); - if (may_be_zero && integer_zerop (may_be_zero)) - may_be_zero = NULL_TREE; + if (exit != main_exit) + continue; - if (may_be_zero) - { - if (COMPARISON_CLASS_P (may_be_zero)) + may_be_zero = NULL_TREE; + if (!number_of_iterations_exit_assumptions (loop, exit, &niter_desc, NULL) + || chrec_contains_undetermined (niter_desc.niter)) + continue; + + niter_assumptions = niter_desc.assumptions; + may_be_zero = niter_desc.may_be_zero; + niter = niter_desc.niter; + + if (may_be_zero && integer_zerop (may_be_zero)) + may_be_zero = NULL_TREE; + + if (may_be_zero) { - /* Try to combine may_be_zero with assumptions, this can simplify - computation of niter expression. */ - if (niter_assumptions && !integer_nonzerop (niter_assumptions)) - niter_assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, - niter_assumptions, - fold_build1 (TRUTH_NOT_EXPR, - boolean_type_node, - may_be_zero)); + if (COMPARISON_CLASS_P (may_be_zero)) + { + /* Try to combine may_be_zero with assumptions, this can simplify + computation of niter expression. */ + if (niter_assumptions && !integer_nonzerop (niter_assumptions)) + niter_assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, + niter_assumptions, + fold_build1 (TRUTH_NOT_EXPR, + boolean_type_node, + may_be_zero)); + else + niter = fold_build3 (COND_EXPR, TREE_TYPE (niter), may_be_zero, + build_int_cst (TREE_TYPE (niter), 0), + rewrite_to_non_trapping_overflow (niter)); + + may_be_zero = NULL_TREE; + } + else if (integer_nonzerop (may_be_zero)) + { + *number_of_iterationsm1 = build_int_cst (TREE_TYPE (niter), 0); + *number_of_iterations = build_int_cst (TREE_TYPE (niter), 1); + continue; + } else - niter = fold_build3 (COND_EXPR, TREE_TYPE (niter), may_be_zero, - build_int_cst (TREE_TYPE (niter), 0), - rewrite_to_non_trapping_overflow (niter)); + continue; + } - may_be_zero = NULL_TREE; - } - else if (integer_nonzerop (may_be_zero)) - { - *number_of_iterationsm1 = build_int_cst (TREE_TYPE (niter), 0); - *number_of_iterations = build_int_cst (TREE_TYPE (niter), 1); - return cond; - } - else - return cond; + /* Loop assumptions are based off the normal exit. */ + *assumptions = niter_assumptions; + *number_of_iterationsm1 = niter; + + /* We want the number of loop header executions which is the number + of latch executions plus one. + ??? For UINT_MAX latch executions this number overflows to zero + for loops like do { n++; } while (n != 0); */ + if (niter && !chrec_contains_undetermined (niter)) + niter = fold_build2 (PLUS_EXPR, TREE_TYPE (niter), + unshare_expr (niter), + build_int_cst (TREE_TYPE (niter), 1)); + *number_of_iterations = niter; } - *assumptions = niter_assumptions; - *number_of_iterationsm1 = niter; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "All loop exits successfully analyzed.\n"); - /* We want the number of loop header executions which is the number - of latch executions plus one. - ??? For UINT_MAX latch executions this number overflows to zero - for loops like do { n++; } while (n != 0); */ - if (niter && !chrec_contains_undetermined (niter)) - niter = fold_build2 (PLUS_EXPR, TREE_TYPE (niter), unshare_expr (niter), - build_int_cst (TREE_TYPE (niter), 1)); - *number_of_iterations = niter; + return conds; +} - return cond; +/* Determine the main loop exit for the vectorizer. */ + +edge +vec_init_loop_exit_info (class loop *loop) +{ + /* Before we begin we must first determine which exit is the main one and + which are auxilary exits. */ + auto_vec<edge> exits = get_loop_exit_edges (loop); + if (exits.length () == 1) + return exits[0]; + + /* If we have multiple exits we only support counting IV at the moment. Analyze + all exits and return one */ + class tree_niter_desc niter_desc; + edge candidate = NULL; + for (edge exit : exits) + { + if (!get_loop_exit_condition (exit)) + continue; + + if (number_of_iterations_exit_assumptions (loop, exit, &niter_desc, NULL) + && !chrec_contains_undetermined (niter_desc.niter)) + { + if (!niter_desc.may_be_zero || !candidate) + candidate = exit; + } + } + + return candidate; } /* Function bb_in_loop_p @@ -987,7 +1044,10 @@ _loop_vec_info::_loop_vec_info (class loop *loop_in, vec_info_shared *shared) has_mask_store (false), scalar_loop_scaling (profile_probability::uninitialized ()), scalar_loop (NULL), - orig_loop_info (NULL) + orig_loop_info (NULL), + vec_loop_iv_exit (NULL), + vec_epilogue_loop_iv_exit (NULL), + scalar_loop_iv_exit (NULL) { /* CHECKME: We want to visit all BBs before their successors (except for latch blocks, for which this assertion wouldn't hold). In the simple @@ -1646,6 +1706,18 @@ vect_analyze_loop_form (class loop *loop, vect_loop_form_info *info) { DUMP_VECT_SCOPE ("vect_analyze_loop_form"); + edge exit_e = vec_init_loop_exit_info (loop); + if (!exit_e) + return opt_result::failure_at (vect_location, + "not vectorized:" + " could not determine main exit from" + " loop with multiple exits.\n"); + info->loop_exit = exit_e; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "using as main loop exit: %d -> %d [AUX: %p]\n", + exit_e->src->index, exit_e->dest->index, exit_e->aux); + /* Different restrictions apply when we are considering an inner-most loop, vs. an outer (nested) loop. (FORNOW. May want to relax some of these restrictions in the future). */ @@ -1739,7 +1811,7 @@ vect_analyze_loop_form (class loop *loop, vect_loop_form_info *info) if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "Considering outer-loop vectorization.\n"); - info->inner_loop_cond = inner.loop_cond; + info->inner_loop_cond = inner.conds[0]; } if (!single_exit (loop)) @@ -1760,31 +1832,39 @@ vect_analyze_loop_form (class loop *loop, vect_loop_form_info *info) "not vectorized: latch block not empty.\n"); /* Make sure the exit is not abnormal. */ - edge e = single_exit (loop); - if (e->flags & EDGE_ABNORMAL) + if (exit_e->flags & EDGE_ABNORMAL) return opt_result::failure_at (vect_location, "not vectorized:" " abnormal loop exit edge.\n"); - info->loop_cond - = vect_get_loop_niters (loop, &info->assumptions, + info->conds + = vect_get_loop_niters (loop, exit_e, &info->assumptions, &info->number_of_iterations, &info->number_of_iterationsm1); - if (!info->loop_cond) + + if (info->conds.is_empty ()) return opt_result::failure_at (vect_location, "not vectorized: complicated exit condition.\n"); + /* Determine what the primary and alternate exit conds are. */ + for (unsigned i = 0; i < info->conds.length (); i++) + { + gcond *cond = info->conds[i]; + if (exit_e->src == gimple_bb (cond)) + std::swap (info->conds[0], info->conds[i]); + } + if (integer_zerop (info->assumptions) || !info->number_of_iterations || chrec_contains_undetermined (info->number_of_iterations)) return opt_result::failure_at - (info->loop_cond, + (info->conds[0], "not vectorized: number of iterations cannot be computed.\n"); if (integer_zerop (info->number_of_iterations)) return opt_result::failure_at - (info->loop_cond, + (info->conds[0], "not vectorized: number of iterations = 0.\n"); if (!(tree_fits_shwi_p (info->number_of_iterations) @@ -1819,8 +1899,18 @@ vect_create_loop_vinfo (class loop *loop, vec_info_shared *shared, if (!integer_onep (info->assumptions) && !main_loop_info) LOOP_VINFO_NITERS_ASSUMPTIONS (loop_vinfo) = info->assumptions; - stmt_vec_info loop_cond_info = loop_vinfo->lookup_stmt (info->loop_cond); - STMT_VINFO_TYPE (loop_cond_info) = loop_exit_ctrl_vec_info_type; + for (gcond *cond : info->conds) + { + stmt_vec_info loop_cond_info = loop_vinfo->lookup_stmt (cond); + STMT_VINFO_TYPE (loop_cond_info) = loop_exit_ctrl_vec_info_type; + } + + for (unsigned i = 1; i < info->conds.length (); i ++) + LOOP_VINFO_LOOP_CONDS (loop_vinfo).safe_push (info->conds[i]); + LOOP_VINFO_LOOP_IV_COND (loop_vinfo) = info->conds[0]; + + LOOP_VINFO_IV_EXIT (loop_vinfo) = info->loop_exit; + if (info->inner_loop_cond) { stmt_vec_info inner_loop_cond_info @@ -3063,9 +3153,9 @@ start_over: if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "epilog loop required\n"); if (!vect_can_advance_ivs_p (loop_vinfo) - || !slpeel_can_duplicate_loop_p (LOOP_VINFO_LOOP (loop_vinfo), - single_exit (LOOP_VINFO_LOOP - (loop_vinfo)))) + || !slpeel_can_duplicate_loop_p (loop, + LOOP_VINFO_IV_EXIT (loop_vinfo), + LOOP_VINFO_IV_EXIT (loop_vinfo))) { ok = opt_result::failure_at (vect_location, "not vectorized: can't create required " @@ -3986,24 +4076,15 @@ pop: ??? We could relax this and handle arbitrary live stmts by forcing a scalar epilogue for example. */ imm_use_iterator imm_iter; + use_operand_p use_p; gimple *op_use_stmt; unsigned cnt = 0; FOR_EACH_IMM_USE_STMT (op_use_stmt, imm_iter, op.ops[opi]) if (!is_gimple_debug (op_use_stmt) && (*code != ERROR_MARK || flow_bb_inside_loop_p (loop, gimple_bb (op_use_stmt)))) - { - /* We want to allow x + x but not x < 1 ? x : 2. */ - if (is_gimple_assign (op_use_stmt) - && gimple_assign_rhs_code (op_use_stmt) == COND_EXPR) - { - use_operand_p use_p; - FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) - cnt++; - } - else - cnt++; - } + FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) + cnt++; if (cnt != 1) { fail = true; @@ -5780,7 +5861,7 @@ vect_create_epilog_for_reduction (loop_vec_info loop_vinfo, basic_block exit_bb; tree scalar_dest; tree scalar_type; - gimple *new_phi = NULL, *phi; + gimple *new_phi = NULL, *phi = NULL; gimple_stmt_iterator exit_gsi; tree new_temp = NULL_TREE, new_name, new_scalar_dest; gimple *epilog_stmt = NULL; @@ -6002,7 +6083,7 @@ vect_create_epilog_for_reduction (loop_vec_info loop_vinfo, Store them in NEW_PHIS. */ if (double_reduc) loop = outer_loop; - exit_bb = single_exit (loop)->dest; + exit_bb = LOOP_VINFO_IV_EXIT (loop_vinfo)->dest; exit_gsi = gsi_after_labels (exit_bb); reduc_inputs.create (slp_node ? vec_num : ncopies); for (unsigned i = 0; i < vec_num; i++) @@ -6018,7 +6099,7 @@ vect_create_epilog_for_reduction (loop_vec_info loop_vinfo, phi = create_phi_node (new_def, exit_bb); if (j) def = gimple_get_lhs (STMT_VINFO_VEC_STMTS (rdef_info)[j]); - SET_PHI_ARG_DEF (phi, single_exit (loop)->dest_idx, def); + SET_PHI_ARG_DEF (phi, LOOP_VINFO_IV_EXIT (loop_vinfo)->dest_idx, def); new_def = gimple_convert (&stmts, vectype, new_def); reduc_inputs.quick_push (new_def); } @@ -10416,12 +10497,12 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info, lhs' = new_tree; */ class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); - basic_block exit_bb = single_exit (loop)->dest; + basic_block exit_bb = LOOP_VINFO_IV_EXIT (loop_vinfo)->dest; gcc_assert (single_pred_p (exit_bb)); tree vec_lhs_phi = copy_ssa_name (vec_lhs); gimple *phi = create_phi_node (vec_lhs_phi, exit_bb); - SET_PHI_ARG_DEF (phi, single_exit (loop)->dest_idx, vec_lhs); + SET_PHI_ARG_DEF (phi, LOOP_VINFO_IV_EXIT (loop_vinfo)->dest_idx, vec_lhs); gimple_seq stmts = NULL; tree new_tree; @@ -10965,7 +11046,7 @@ vect_get_loop_len (loop_vec_info loop_vinfo, gimple_stmt_iterator *gsi, profile. */ static void -scale_profile_for_vect_loop (class loop *loop, unsigned vf, bool flat) +scale_profile_for_vect_loop (class loop *loop, edge exit_e, unsigned vf, bool flat) { /* For flat profiles do not scale down proportionally by VF and only cap by known iteration count bounds. */ @@ -10980,7 +11061,6 @@ scale_profile_for_vect_loop (class loop *loop, unsigned vf, bool flat) return; } /* Loop body executes VF fewer times and exit increases VF times. */ - edge exit_e = single_exit (loop); profile_count entry_count = loop_preheader_edge (loop)->count (); /* If we have unreliable loop profile avoid dropping entry @@ -11350,7 +11430,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) /* Make sure there exists a single-predecessor exit bb. Do this before versioning. */ - edge e = single_exit (loop); + edge e = LOOP_VINFO_IV_EXIT (loop_vinfo); if (! single_pred_p (e->dest)) { split_loop_exit_edge (e, true); @@ -11376,7 +11456,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) loop closed PHI nodes on the exit. */ if (LOOP_VINFO_SCALAR_LOOP (loop_vinfo)) { - e = single_exit (LOOP_VINFO_SCALAR_LOOP (loop_vinfo)); + e = LOOP_VINFO_SCALAR_IV_EXIT (loop_vinfo); if (! single_pred_p (e->dest)) { split_loop_exit_edge (e, true); @@ -11625,8 +11705,9 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) a zero NITERS becomes a nonzero NITERS_VECTOR. */ if (integer_onep (step_vector)) niters_no_overflow = true; - vect_set_loop_condition (loop, loop_vinfo, niters_vector, step_vector, - niters_vector_mult_vf, !niters_no_overflow); + vect_set_loop_condition (loop, LOOP_VINFO_IV_EXIT (loop_vinfo), loop_vinfo, + niters_vector, step_vector, niters_vector_mult_vf, + !niters_no_overflow); unsigned int assumed_vf = vect_vf_for_cost (loop_vinfo); @@ -11681,7 +11762,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) LOOP_VINFO_VECT_FACTOR (loop_vinfo), &bound)) loop->nb_iterations_upper_bound - = wi::umin ((widest_int) (bound - 1), + = wi::umin ((bound_wide_int) (bound - 1), loop->nb_iterations_upper_bound); } } @@ -11699,7 +11780,8 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) assumed_vf) - 1 : wi::udiv_floor (loop->nb_iterations_estimate + bias_for_assumed, assumed_vf) - 1); - scale_profile_for_vect_loop (loop, assumed_vf, flat); + scale_profile_for_vect_loop (loop, LOOP_VINFO_IV_EXIT (loop_vinfo), + assumed_vf, flat); if (dump_enabled_p ()) { |