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)

Reply via email to