On Mon, 10 Nov 2025, Victor Do Nascimento wrote:
> Default types:
> --------------
>
> While the primary exit condition for loops is no longer tied to some
> upper limit in the number of executed iterations, similar limits are
> still required for vectorization. One example of this is with prolog
> peeling. The prolog will always have an IV exit associated with the
> misalignment of data accesses within the loop.
>
> Historically, the assumption held that the data-type that this counter
> should have could be derived from the type of the niters limit for the
> original loop, so we could get the type from `TREE_TYPE (niters)'.
>
> Moving forward, we provide a backup type to be used for iteration
> counters when the maximum number of iterations to be run is unknown.
>
> We take this to be `size_t', given its role in storing the maximum
> size of a theoretically possible object of any type (including array).
There are targets where size_t and pointer size do not agree. For
prologue peeling not related to early break vectorization the number
of iterations is bound by the number of bytes in a vector (at worst
case), for early break it's bound by page size in bytes or, as you
say, by the maximum size of objects. In the middle-end this is
'sizetype', so I think you should use that.
> Default return values:
> ----------------------
>
> To avoid having to gate all calls to functions that query a loop's
> niters value it is better to "teach" such functions how to handle
> uncounted loops and have them return a sensible value that can be
> handled upon a function's return.
>
> We therefore prevent functions operating on niters from segfaulting by
> adding a default `SCEV_NOT_KNOWN' return value when niters information
> absent.
>
> gcc/ChangeLog:
>
> * tree-vect-loop-manip.cc (vect_gen_prolog_loop_niters): Add
> type default of `size_t'.
> (vect_gen_vector_loop_niters): Likewise.
> (vect_do_peeling): Likewise.
> * tree-vect-loop.cc (vect_min_prec_for_max_niters): Likewise.
> * tree-vect-loop-manip.cc (vect_build_loop_niters): Gracefully
> handle uncounted loops.
> * tree-vect-loop.cc (loop_niters_no_overflow): Likewise.
> ---
> gcc/tree-vect-loop-manip.cc | 13 ++++++++++---
> gcc/tree-vect-loop.cc | 10 +++++++++-
> 2 files changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
> index 6af07efe68a..928045540da 100644
> --- a/gcc/tree-vect-loop-manip.cc
> +++ b/gcc/tree-vect-loop-manip.cc
> @@ -2511,7 +2511,10 @@ vect_gen_prolog_loop_niters (loop_vec_info loop_vinfo,
> {
> dr_vec_info *dr_info = LOOP_VINFO_UNALIGNED_DR (loop_vinfo);
> tree var;
> - tree niters_type = TREE_TYPE (LOOP_VINFO_NITERS (loop_vinfo));
> + tree niters_type
> + = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo) ? size_type_node
sizetype here and below
> + : TREE_TYPE (LOOP_VINFO_NITERS
> + (loop_vinfo));
> gimple_seq stmts = NULL, new_stmts = NULL;
> tree iters, iters_name;
> stmt_vec_info stmt_info = dr_info->stmt;
> @@ -2690,6 +2693,8 @@ vect_prepare_for_masked_peels (loop_vec_info loop_vinfo)
> tree
> vect_build_loop_niters (loop_vec_info loop_vinfo, bool *new_var_p)
> {
> + if (LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
> + return NULL_TREE;
> tree ni = unshare_expr (LOOP_VINFO_NITERS (loop_vinfo));
> if (TREE_CODE (ni) == INTEGER_CST)
> return ni;
> @@ -2784,7 +2789,8 @@ vect_gen_vector_loop_niters (loop_vec_info loop_vinfo,
> tree niters,
> bool niters_no_overflow)
> {
> tree ni_minus_gap, var;
> - tree niters_vector, step_vector, type = TREE_TYPE (niters);
> + tree niters_vector, step_vector;
> + tree type = niters ? TREE_TYPE (niters) : size_type_node;
> poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
> edge pe = loop_preheader_edge (LOOP_VINFO_LOOP (loop_vinfo));
>
> @@ -3139,7 +3145,8 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters,
> tree nitersm1,
> tree *advance)
> {
> edge e, guard_e;
> - tree type = TREE_TYPE (niters), guard_cond;
> + tree type = niters ? TREE_TYPE (niters) : size_type_node;
> + tree guard_cond;
> basic_block guard_bb, guard_to;
> profile_probability prob_prolog, prob_vector, prob_epilog;
> int estimated_vf;
> diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
> index dfb0960e7d1..b17745cdaa1 100644
> --- a/gcc/tree-vect-loop.cc
> +++ b/gcc/tree-vect-loop.cc
> @@ -937,7 +937,11 @@ vect_min_prec_for_max_niters (loop_vec_info loop_vinfo,
> unsigned int factor)
>
> /* Get the maximum number of iterations that is representable
> in the counter type. */
> - tree ni_type = TREE_TYPE (LOOP_VINFO_NITERSM1 (loop_vinfo));
> + tree ni_type;
> + if (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
> + ni_type = TREE_TYPE (LOOP_VINFO_NITERSM1 (loop_vinfo));
> + else
> + ni_type = size_type_node;
> widest_int max_ni = wi::to_widest (TYPE_MAX_VALUE (ni_type)) + 1;
>
> /* Get a more refined estimate for the number of iterations. */
> @@ -10490,6 +10494,10 @@ vectorizable_live_operation (vec_info *vinfo,
> stmt_vec_info stmt_info,
> static bool
> loop_niters_no_overflow (loop_vec_info loop_vinfo)
> {
> + /* Unknown case. */
> + if (LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
> + return true;
> +
false is a better "don't know", but IMO an assert that we do not
call loop_niters_no_overflow on uncounted loops would be better
which means guarding callers instead.
Richard.
> /* Constant case. */
> if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo))
> {
>
--
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)