On Mon, 10 Nov 2025, Victor Do Nascimento wrote:
> Given how present requirements for loops, early-break or otherwise, to
> have a known iteration count, there is currently no need for
> single-exit loops to reset induction variables and accumulators prior
> to entering the exit loop.
>
> For multiple-exit uncounted loops, there are provisions in the code
> for resetting IVs and accumulators on exiting the loop via early
> exits. This is extended to the main exit (though only in
> multiple-exit loops) if `peeled_iters' is set to `true', wherein the
> definition of `peeled_iters' is equivalent to that of
> LOOP_VINFO_EARLY_BREAKS_VECT_PEELED, but is evaluated independently as
> the function does not have access to loop_vinfo.
>
> Therefore, the first fix is to ensure that, just as for
> LOOP_VINFO_EARLY_BREAKS_VECT_PEELED, `peeled_iters' also evaluates to
> true for uncounted loops.
>
> The second fix implemented here is: given the relevant logic is
> currently hidden behind the `multiple_exits_p', we enable relevant
> logic via use of the new function argument `uncounted_p'.
>
> gcc/ChangeLog:
>
> * tree-vect-loop-manip.cc (slpeel_tree_duplicate_loop_to_edge_cfg):
> reset IVs and accumulators for all exits for uncounted loops.
> ---
> gcc/tree-vect-loop-manip.cc | 20 +++++++++++++-------
> gcc/tree-vectorizer.h | 3 ++-
> 2 files changed, 15 insertions(+), 8 deletions(-)
>
> diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
> index 640735388fe..6d623e980f2 100644
> --- a/gcc/tree-vect-loop-manip.cc
> +++ b/gcc/tree-vect-loop-manip.cc
> @@ -1479,7 +1479,8 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
> class loop *scalar_loop,
> edge scalar_exit, edge e, edge *new_e,
> bool flow_loops,
> - vec<basic_block> *updated_doms)
> + vec<basic_block> *updated_doms,
> + bool uncounted_p)
> {
> class loop *new_loop;
> basic_block *new_bbs, *bbs, *pbbs;
> @@ -1650,7 +1651,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
> the continuation values into the epilogue header.
> Do not bother with exit PHIs for the early exits but
> their live virtual operand. We'll fix up things below. */
> - if (multiple_exits_p)
> + if (multiple_exits_p || uncounted_p)
> {
> edge loop_e = single_succ_edge (new_preheader);
> new_preheader = split_edge (loop_e);
> @@ -1705,7 +1706,8 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
> if (flow_loops)
> {
> edge loop_entry = single_succ_edge (new_preheader);
> - bool peeled_iters = single_pred (loop->latch) != loop_exit->src;
> + bool peeled_iters = (uncounted_p
> + || single_pred (loop->latch) != loop_exit->src);
>
> /* Record the new SSA names in the cache so that we can skip
> materializing them again when we fill in the rest of the LC SSA
> @@ -1735,7 +1737,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
>
> /* Create the merge PHI nodes in new_preheader and populate the
> arguments for the exits. */
> - if (multiple_exits_p)
> + if (multiple_exits_p || uncounted_p)
> {
> for (auto gsi_from = gsi_start_phis (loop->header),
> gsi_to = gsi_start_phis (new_loop->header);
> @@ -1787,7 +1789,10 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
> /* And adjust the epilog entry value. */
> adjust_phi_and_debug_stmts (to_phi, loop_entry, new_res);
> }
> + }
>
> + if (multiple_exits_p)
> + {
> /* After creating the merge PHIs handle the early exits those
> should use the values at the start of the loop. */
> for (auto gsi_from = gsi_start_phis (loop->header),
> @@ -1824,7 +1829,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
> /* For the single exit case only create the missing LC PHI nodes
> for the continuation of the loop IVs that are not also already
> reductions and thus had LC PHI nodes on the exit already. */
> - else
> + if (!multiple_exits_p && !uncounted_p)
> {
> for (auto gsi_from = gsi_start_phis (loop->header),
> gsi_to = gsi_start_phis (new_loop->header);
> @@ -1867,7 +1872,7 @@ slpeel_tree_duplicate_loop_to_edge_cfg (class loop
> *loop, edge loop_exit,
> /* Finally after wiring the new epilogue we need to update its main
> exit
> to the original function exit we recorded. Other exits are already
> correct. */
> - if (multiple_exits_p)
> + if (multiple_exits_p || uncounted_p)
> {
> class loop *update_loop = new_loop;
> doms = get_all_dominated_blocks (CDI_DOMINATORS, loop->header);
> @@ -3464,7 +3469,8 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters,
> tree nitersm1,
> auto_vec<basic_block> doms;
> epilog
> = slpeel_tree_duplicate_loop_to_edge_cfg (loop, e, epilog, epilog_e, e,
> - &new_epilog_e, true, &doms);
> + &new_epilog_e, true, &doms,
> + uncounted_p);
>
> LOOP_VINFO_EPILOGUE_IV_EXIT (loop_vinfo) = new_epilog_e;
> gcc_assert (epilog);
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index 0ae880b15bb..bb761fdc9bb 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -2461,7 +2461,8 @@ extern bool slpeel_can_duplicate_loop_p (const class
> loop *, const_edge,
> class loop *slpeel_tree_duplicate_loop_to_edge_cfg (class loop *, edge,
> class loop *, edge,
> edge, edge *, bool = true,
> - vec<basic_block> * = NULL);
> + vec<basic_block> * = NULL,
> + bool=false);
Spaces around '=', otherwise OK.
Richard.
> class loop *vect_loop_versioning (loop_vec_info, gimple *);
> extern class loop *vect_do_peeling (loop_vec_info, tree, tree,
> tree *, tree *, tree *, int, bool, bool,
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)