On Fri, Jul 10, 2026 at 6:13 PM Robin Dapp <[email protected]> wrote:
>
> From: Robin Dapp <[email protected]>
>
> This adds the get_niter_type_bound helper and uses it in
> loop_exits_before_overflow as well as derive_simple_iv_with_niters.
> We can re-use it in subsequent patches for computing nowrap bounds.

OK.

Thanks,
Richard.

> gcc/ChangeLog:
>
>         * tree-scalar-evolution.cc (derive_simple_iv_with_niters): Use
>         new function.
>         * tree-ssa-loop-niter.cc (loop_exits_before_overflow): Use new
>         function.
>         (get_niter_type_bound): New function.
>         * tree-ssa-loop-niter.h (get_niter_type_bound): Declare.
> ---
>  gcc/tree-scalar-evolution.cc | 20 ++++------------
>  gcc/tree-ssa-loop-niter.cc   | 44 ++++++++++++++++++++++--------------
>  gcc/tree-ssa-loop-niter.h    |  1 +
>  3 files changed, 32 insertions(+), 33 deletions(-)
>
> diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc
> index 279ff46474e..b9acdbe9135 100644
> --- a/gcc/tree-scalar-evolution.cc
> +++ b/gcc/tree-scalar-evolution.cc
> @@ -3239,22 +3239,10 @@ derive_simple_iv_with_niters (tree ev, tree *niters)
>       folded only if inner iv won't overflow.  We compute the maximum
>       number the inner iv can iterate before overflowing and return the
>       simplified affine iv.  */
> -  tree delta;
> -  init = fold_convert (type, init);
> -  step = fold_convert (type, step);
> -  ev = build_polynomial_chrec (CHREC_VARIABLE (inner_ev), init, step);
> -  if (tree_int_cst_sign_bit (step))
> -    {
> -      tree bound = lower_bound_in_type (inner_type, inner_type);
> -      delta = fold_build2 (MINUS_EXPR, type, init, fold_convert (type, 
> bound));
> -      step = fold_build1 (NEGATE_EXPR, type, step);
> -    }
> -  else
> -    {
> -      tree bound = upper_bound_in_type (inner_type, inner_type);
> -      delta = fold_build2 (MINUS_EXPR, type, fold_convert (type, bound), 
> init);
> -    }
> -  *niters = fold_build2 (FLOOR_DIV_EXPR, type, delta, step);
> +  ev = build_polynomial_chrec (CHREC_VARIABLE (inner_ev),
> +                              fold_convert (type, init),
> +                              fold_convert (type, step));
> +  *niters = get_niter_type_bound (inner_type, init, step);
>    return ev;
>  }
>
> diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
> index 0c1ebd1c7d5..fe179b69b05 100644
> --- a/gcc/tree-ssa-loop-niter.cc
> +++ b/gcc/tree-ssa-loop-niter.cc
> @@ -5357,24 +5357,15 @@ nowrap_type_p (tree type)
>    return false;
>  }
>
> -/* Return true if we can prove LOOP is exited before evolution of induction
> -   variable {BASE, STEP} overflows with respect to its type bound.  */
> +/* Return an upper bound on the number of times the affine IV {BASE, +, STEP}
> +   of type TYPE can step while staying within TYPE's range.  */
>
> -static bool
> -loop_exits_before_overflow (tree base, tree step,
> -                           gimple *at_stmt, class loop *loop)
> +tree
> +get_niter_type_bound (tree type, tree base, tree step)
>  {
> -  widest_int niter;
> -  struct control_iv *civ;
> -  class nb_iter_bound *bound;
> -  tree e, delta, step_abs, unsigned_base;
> -  tree type = TREE_TYPE (step);
> -  tree unsigned_type, valid_niter;
> -
> -  /* Compute the number of iterations before we reach the bound of the
> -     type, and verify that the loop is exited before this occurs.  */
> -  unsigned_type = unsigned_type_for (type);
> -  unsigned_base = fold_convert (unsigned_type, base);
> +  tree unsigned_type = unsigned_type_for (type);
> +  tree unsigned_base = fold_convert (unsigned_type, base);
> +  tree delta, step_abs;
>
>    if (tree_int_cst_sign_bit (step))
>      {
> @@ -5392,7 +5383,26 @@ loop_exits_before_overflow (tree base, tree step,
>        step_abs = fold_convert (unsigned_type, step);
>      }
>
> -  valid_niter = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs);
> +  return fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs);
> +}
> +
> +/* Return true if we can prove LOOP is exited before evolution of induction
> +   variable {BASE, STEP} overflows with respect to its type bound.  */
> +
> +static bool
> +loop_exits_before_overflow (tree base, tree step,
> +                           gimple *at_stmt, class loop *loop)
> +{
> +  widest_int niter;
> +  struct control_iv *civ;
> +  class nb_iter_bound *bound;
> +  tree e;
> +  tree type = TREE_TYPE (step);
> +  tree valid_niter;
> +
> +  /* Compute the number of iterations before we reach the bound of the
> +     type, and verify that the loop is exited before this occurs.  */
> +  valid_niter = get_niter_type_bound (type, base, step);
>
>    estimate_numbers_of_iterations (loop);
>
> diff --git a/gcc/tree-ssa-loop-niter.h b/gcc/tree-ssa-loop-niter.h
> index 643ac1d7f7f..24e458f08db 100644
> --- a/gcc/tree-ssa-loop-niter.h
> +++ b/gcc/tree-ssa-loop-niter.h
> @@ -52,6 +52,7 @@ extern void estimate_numbers_of_iterations (function *);
>  extern void estimate_numbers_of_iterations (class loop *);
>  extern bool stmt_dominates_stmt_p (gimple *, gimple *);
>  extern bool nowrap_type_p (tree);
> +extern tree get_niter_type_bound (tree, tree, tree);
>  extern bool scev_probably_wraps_p (tree, tree, tree, gimple *,
>                                    class loop *, bool);
>  extern void free_numbers_of_iterations_estimates (class loop *);
> --
> 2.54.0
>

Reply via email to