On Fri, Jul 10, 2026 at 6:13 PM Robin Dapp <[email protected]> wrote:
>
> From: Robin Dapp <[email protected]>
>
> This patch adds a nowrap_bound field to data_reference which denotes the
> upper bound under which the DR is non wrapping.
>
> dr_analyze_innermost, create_data_ref, and find_data_references_in_stmt
> get an additional parameter to control whether or not a no-wrap bound
> should be recorded.
This looks OK, the only thing might be to mimic
number_of_iterations_exit_assumptions
vs. number_of_iterations_exit instead of adding a (defaulted)
parameter indicating
whether to allow assumptions. I think I prefer the extra parameter as
done here.
Thanks,
Richard.
> gcc/ChangeLog:
>
> * tree-data-ref.cc (dr_analyze_innermost): Add nowrap-bound param.
> (dr_analyze_indices): Likewise.
> (create_data_ref): Likewise.
> (find_data_references_in_stmt): Add allow_assumptions param.
> * tree-data-ref.h (struct data_reference): Add nowrap_bound.
> (DR_NOWRAP_BOUND): New.
> (dr_analyze_innermost): Pass on nowrap_bound.
> (find_data_references_in_stmt): Likewise.
> ---
> gcc/tree-data-ref.cc | 77 +++++++++++++++++++++++++++++++++-----------
> gcc/tree-data-ref.h | 13 ++++++--
> 2 files changed, 68 insertions(+), 22 deletions(-)
>
> diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
> index 1114903784e..2d6ddb14a23 100644
> --- a/gcc/tree-data-ref.cc
> +++ b/gcc/tree-data-ref.cc
> @@ -1129,11 +1129,15 @@ canonicalize_base_object_address (tree addr)
> dummy outermost loop. In other cases perform loop analysis.
>
> Return true if the analysis succeeded and store the results in DRB if so.
> - BB analysis can only fail for bitfield or reversed-storage accesses. */
> + BB analysis can only fail for bitfield or reversed-storage accesses.
> +
> + If NOWRAP_BOUND is nonzero, allow simple_iv to record no-wrap bounds.
> + Then, store non-trivial bounds in NOWRAP_BOUND. */
>
> opt_result
> dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
> - class loop *loop, const gimple *stmt)
> + class loop *loop, const gimple *stmt,
> + tree *nowrap_bound)
> {
> poly_int64 pbitsize, pbitpos;
> tree base, poffset;
> @@ -1195,9 +1199,11 @@ dr_analyze_innermost (innermost_loop_behavior *drb,
> tree ref,
> base = build_fold_addr_expr (base);
> }
>
> + bool allow_wrapping = (nowrap_bound != nullptr);
> +
> if (in_loop)
> {
> - if (!simple_iv (loop, loop, base, &base_iv, true))
> + if (!simple_iv (loop, loop, base, &base_iv, true, allow_wrapping))
> return opt_result::failure_at
> (stmt, "failed: evolution of base is not affine.\n");
> }
> @@ -1206,25 +1212,35 @@ dr_analyze_innermost (innermost_loop_behavior *drb,
> tree ref,
> base_iv.base = base;
> base_iv.step = ssize_int (0);
> base_iv.no_overflow = true;
> + base_iv.nowrap_bound = NULL_TREE;
> }
>
> if (!poffset)
> {
> offset_iv.base = ssize_int (0);
> offset_iv.step = ssize_int (0);
> + offset_iv.nowrap_bound = NULL_TREE;
> }
> else
> {
> if (!in_loop)
> - {
> - offset_iv.base = poffset;
> - offset_iv.step = ssize_int (0);
> - }
> - else if (!simple_iv (loop, loop, poffset, &offset_iv, true))
> + {
> + offset_iv.base = poffset;
> + offset_iv.step = ssize_int (0);
> + offset_iv.nowrap_bound = NULL_TREE;
> + }
> + else if (!simple_iv (loop, loop, poffset, &offset_iv, true,
> + allow_wrapping))
> return opt_result::failure_at
> (stmt, "failed: evolution of offset is not affine.\n");
> }
>
> + if (nowrap_bound)
> + {
> + *nowrap_bound = base_iv.nowrap_bound;
> + scev_add_nowrap_bound (nowrap_bound, offset_iv.nowrap_bound);
> + }
> +
> init = ssize_int (pbytepos);
>
> /* Subtract any constant component from the base and add it to INIT
> instead.
> @@ -1320,10 +1336,14 @@ base_supports_access_fn_components_p (tree base)
> }
>
> /* Determines the base object and the list of indices of memory reference
> - DR, analyzed in LOOP and instantiated before NEST. */
> + DR, analyzed in LOOP and instantiated before NEST.
> +
> + If NOWRAP_BOUND is nonzero, pass it to scev which will then store
> + the bound under which we do not wrap. */
>
> static void
> -dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop)
> +dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop,
> + tree *nowrap_bound = nullptr)
> {
> /* If analyzing a basic-block there are no indices to analyze
> and thus no access functions. */
> @@ -1358,7 +1378,7 @@ dr_analyze_indices (struct indices *dri, tree ref, edge
> nest, loop_p loop)
> if (TREE_CODE (ref) == ARRAY_REF)
> {
> tree op = TREE_OPERAND (ref, 1);
> - tree access_fn = analyze_scalar_evolution (loop, op);
> + tree access_fn = analyze_scalar_evolution (loop, op, nowrap_bound);
> access_fn = instantiate_scev (nest, loop, access_fn);
> access_fns.safe_push (access_fn);
> }
> @@ -1390,7 +1410,7 @@ dr_analyze_indices (struct indices *dri, tree ref, edge
> nest, loop_p loop)
> if (TREE_CODE (ref) == MEM_REF)
> {
> tree op = TREE_OPERAND (ref, 0);
> - tree access_fn = analyze_scalar_evolution (loop, op);
> + tree access_fn = analyze_scalar_evolution (loop, op, nowrap_bound);
> access_fn = instantiate_scev (nest, loop, access_fn);
> STRIP_NOPS (access_fn);
> if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC)
> @@ -1496,11 +1516,16 @@ free_data_ref (data_reference_p dr)
>
> Return the data_reference description of MEMREF. NEST is the outermost
> loop in which the reference should be instantiated, LOOP is the loop
> - in which the data reference should be analyzed. */
> + in which the data reference should be analyzed.
> +
> + If ALLOW_ASSUMPTIONS is true, pass an empty no-wrap bound to scev and
> + have it store its assumptions there. If we got a nontrivial
> + assumption, save it in DR's DR_NOWRAP_BOUND. */
>
> struct data_reference *
> create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
> - bool is_read, bool is_conditional_in_stmt)
> + bool is_read, bool is_conditional_in_stmt,
> + bool allow_assumptions)
> {
> struct data_reference *dr;
>
> @@ -1517,11 +1542,16 @@ create_data_ref (edge nest, loop_p loop, tree memref,
> gimple *stmt,
> DR_IS_READ (dr) = is_read;
> DR_IS_CONDITIONAL_IN_STMT (dr) = is_conditional_in_stmt;
>
> + tree nowrap_bound = NULL_TREE;
> dr_analyze_innermost (&DR_INNERMOST (dr), memref,
> - nest != NULL ? loop : NULL, stmt);
> - dr_analyze_indices (&dr->indices, DR_REF (dr), nest, loop);
> + nest != NULL ? loop : NULL, stmt,
> + allow_assumptions ? &nowrap_bound : nullptr);
> + dr_analyze_indices (&dr->indices, DR_REF (dr), nest, loop,
> + allow_assumptions ? &nowrap_bound : nullptr);
> dr_analyze_alias (dr);
>
> + DR_NOWRAP_BOUND (dr) = nowrap_bound;
> +
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> unsigned i;
> @@ -1541,6 +1571,11 @@ create_data_ref (edge nest, loop_p loop, tree memref,
> gimple *stmt,
> fprintf (dump_file, "\n\tstep alignment: %d", DR_STEP_ALIGNMENT (dr));
> fprintf (dump_file, "\n\tbase_object: ");
> print_generic_expr (dump_file, DR_BASE_OBJECT (dr), TDF_SLIM);
> + if (DR_NOWRAP_BOUND (dr))
> + {
> + fprintf (dump_file, "\n\tnowrap bound: ");
> + print_generic_expr (dump_file, DR_NOWRAP_BOUND (dr), TDF_SLIM);
> + }
> fprintf (dump_file, "\n");
> for (i = 0; i < DR_NUM_DIMENSIONS (dr); i++)
> {
> @@ -6025,11 +6060,14 @@ loop_nest_has_data_refs (loop_p loop)
>
> /* Stores the data references in STMT to DATAREFS. If there is an
> unanalyzable
> reference, returns false, otherwise returns true. NEST is the outermost
> - loop of the loop nest in which the references should be analyzed. */
> + loop of the loop nest in which the references should be analyzed.
> + ALLOW_ASSUMPTIONS determines whether or not no-wrap assumptions
> + are allowed. */
>
> opt_result
> find_data_references_in_stmt (class loop *nest, gimple *stmt,
> - vec<data_reference_p> *datarefs)
> + vec<data_reference_p> *datarefs,
> + bool allow_assumptions)
> {
> auto_vec<data_ref_loc, 2> references;
> data_reference_p dr;
> @@ -6042,7 +6080,8 @@ find_data_references_in_stmt (class loop *nest, gimple
> *stmt,
> {
> dr = create_data_ref (nest ? loop_preheader_edge (nest) : NULL,
> loop_containing_stmt (stmt), ref.ref,
> - stmt, ref.is_read, ref.is_conditional_in_stmt);
> + stmt, ref.is_read, ref.is_conditional_in_stmt,
> + allow_assumptions);
> gcc_assert (dr != NULL);
> datarefs->safe_push (dr);
> }
> diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
> index e25f98d2966..deb264ded2e 100644
> --- a/gcc/tree-data-ref.h
> +++ b/gcc/tree-data-ref.h
> @@ -172,6 +172,10 @@ struct data_reference
> /* Behavior of the memory reference in the innermost loop. */
> struct innermost_loop_behavior innermost;
>
> + /* Upper bound for the number of loop iterations for which this DR's
> + IV does not wrap. */
> + tree nowrap_bound;
> +
> /* Subscripts of this data reference. */
> struct indices indices;
>
> @@ -201,6 +205,7 @@ struct data_reference
> #define DR_OFFSET_ALIGNMENT(DR) (DR)->innermost.offset_alignment
> #define DR_STEP_ALIGNMENT(DR) (DR)->innermost.step_alignment
> #define DR_INNERMOST(DR) (DR)->innermost
> +#define DR_NOWRAP_BOUND(DR) (DR)->nowrap_bound
>
> typedef struct data_reference *data_reference_p;
>
> @@ -520,7 +525,8 @@ typedef struct data_dependence_relation *ddr_p;
>
>
> opt_result dr_analyze_innermost (innermost_loop_behavior *, tree,
> - class loop *, const gimple *);
> + class loop *, const gimple *,
> + tree * = nullptr);
> extern bool compute_data_dependences_for_loop (class loop *, bool,
> vec<loop_p> *,
> vec<data_reference_p> *,
> @@ -543,13 +549,14 @@ extern void free_dependence_relations (vec<ddr_p>& );
> extern void free_data_ref (data_reference_p);
> extern void free_data_refs (vec<data_reference_p>& );
> extern opt_result find_data_references_in_stmt (class loop *, gimple *,
> - vec<data_reference_p> *);
> + vec<data_reference_p> *,
> + bool = false);
> extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
> vec<data_reference_p> *);
> tree find_data_references_in_loop (class loop *, vec<data_reference_p> *);
> bool loop_nest_has_data_refs (loop_p loop);
> struct data_reference *create_data_ref (edge, loop_p, tree, gimple *, bool,
> - bool);
> + bool, bool = false);
> extern bool find_loop_nest (class loop *, vec<loop_p> *);
> extern struct data_dependence_relation *initialize_data_dependence_relation
> (struct data_reference *, struct data_reference *, vec<loop_p>);
> --
> 2.54.0
>