On Mon, 10 Nov 2025, Victor Do Nascimento wrote:
> In its current implementation, the loop vectorizer requires the main
> exit be the counting IV exit. With uncounted loops we no longer need
> to have any counting IV exits. Furthermore, it is possible to have
> reached this stage with malformed loops with no exits at all.
>
> Consequently, we need an approach to handle malformed loops and some
> logic to follow when choosing the main exit, when counting IV is no
> longer a valid criterion.
>
> For malformed loops, it is sufficient to return NULL, so that we can
> reject such loops upon the function return.
>
> In the case of multiple exits and no counting IV exit, we choose the
> last one in the loop. This is done so that we continue to have an
> empty effective latch.
There's still
if (!get_loop_exit_condition (exit))
continue;
and I think even uncounted loops require an exit condition. Likewise
all early exits do. I'm not sure at which point we catch this at
the moment - there's a EDGE_ABNORMAL check later, but I see no
explicit check of EDGE_EH exits. It would be good to catch this
early, so this looks like a good opportunity to simply return NULL
(with a dump indicating an unhandled exit).
> gcc/ChangeLog:
>
> * tree-vect-loop.cc (vec_init_loop_exit_info): Handle
> multiple-exit uncounted loops.
> * tree-vect-loop.cc (vec_init_loop_exit_info): Handle
> ill-formed loops with no exits.
> (vect_analyze_loop_form): Fix `failure_at' message.
> ---
> gcc/tree-vect-loop.cc | 16 ++++++++++++++--
> 1 file changed, 14 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
> index 8d5fb64ca9c..dfb0960e7d1 100644
> --- a/gcc/tree-vect-loop.cc
> +++ b/gcc/tree-vect-loop.cc
> @@ -657,6 +657,8 @@ 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 () == 0)
> + return NULL;
> if (exits.length () == 1)
> return exits[0];
>
> @@ -688,6 +690,17 @@ vec_init_loop_exit_info (class loop *loop)
> }
> }
>
> + /* If no exit is analyzable by scalar evolution, we return the last exit
> + under the assummption we are dealing with an uncounted loop. */
> + if (!candidate)
> + for (edge exit : exits)
> + if (single_pred_p (loop->latch)
> + && exit->src == single_pred (loop->latch))
> + {
> + candidate = exit;
> + break;
> + }
> +
I think this could be simplified to
if (!candidate && single_pred_p (loop->latch))
candidate = loop_exits_from_bb_p (loop, single_pred (loop->latch)));
with adjusting loop_exits_from_bb_p to return the edge found
(or alternatively adding a loop_exit_from_bb () non-predicate doing
exactly that).
> return candidate;
> }
>
> @@ -1438,8 +1451,7 @@ vect_analyze_loop_form (class loop *loop, gimple
> *loop_vectorized_call,
> if (!exit_e)
> return opt_result::failure_at (vect_location,
> "not vectorized:"
> - " could not determine main exit from"
> - " loop with multiple exits.\n");
> + " Infinite loop detected.\n");
> if (loop_vectorized_call)
> {
> tree arg = gimple_call_arg (loop_vectorized_call, 1);
>
--
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)