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
>