On Wed, 17 Jun 2026, [email protected] wrote:

> From: Kyrylo Tkachov <[email protected]>
> 
> This is preparatory analysis with no effect on its own; the following
> patch consumes it.
> 
> ivopts splits the memory references of a loop into address use-groups.
> Two references that share the same base object and step but differ by a
> constant offset (e.g. src[i] and src[i] + 16 after vectorisation and
> unrolling) end up in separate groups.

But the intention of grouping in IVOPTs is to group exactly that,
bases that differ by only a constant.

So what you do seems backwards to me.  If the existing mechanism
doesn't work, fix it.

Richard.

>  Whether such references can later
> be combined into a load/store pair depends on how ivopts chooses to
> address them: an immediate offset from a shared base register keeps them
> pairable, a register offset (a single shared "index" IV) does not.
> 
> Record, for each address use, whether another address use in the loop
> refers to the same base object with the same step but a different base,
> i.e. a different constant offset ("a pairing sibling").  The flag is
> computed by a new helper called from find_interesting_uses; it is not
> read anywhere yet.  The next patch uses it in the address cost model.
> 
> The scan is O(n^2) in the number of address uses, so it is skipped for
> loops with more groups than MAX_CONSIDERED_GROUPS, mirroring the
> bail-out that ivopts already applies to such loops before candidate
> selection.  The new field is zero-initialised (record_use allocates
> iv_use with XCNEW), so it defaults to false and no other code path needs
> changing.  The patch is therefore codegen-neutral by construction: it
> only sets a flag that nothing consumes yet.
> 
> gcc/ChangeLog:
> 
>       PR target/121315
>       * tree-ssa-loop-ivopts.cc (struct iv_use): Add has_pairing_sibling.
>       (determine_addr_use_pairing_siblings): New function.
>       (find_interesting_uses): Call it, subject to MAX_CONSIDERED_GROUPS.
> 
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
>  gcc/tree-ssa-loop-ivopts.cc | 56 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
> 
> diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
> index bbd3cfaab24..557b35ed2a1 100644
> --- a/gcc/tree-ssa-loop-ivopts.cc
> +++ b/gcc/tree-ssa-loop-ivopts.cc
> @@ -415,6 +415,13 @@ struct iv_use
>    tree addr_base;    /* Base address with const offset stripped.  */
>    poly_uint64 addr_offset;
>                       /* Const offset stripped from base address.  */
> +  bool has_pairing_sibling;
> +                     /* For address uses, true if another address use in the
> +                        loop refers to the same base object with the same
> +                        step but a different base (i.e. a different constant
> +                        offset).  A register-offset address for such a use
> +                        prevents the accesses from being combined into a
> +                        load/store pair.  */
>  };
>  
>  /* Group of uses.  */
> @@ -2676,6 +2683,50 @@ split_address_groups (struct ivopts_data *data)
>      }
>  }
>  
> +/* Mark each address-type use for which another address use in the loop
> +   refers to the same base object, with the same step, but a different base
> +   (i.e. a different constant offset).  Such accesses can be combined into a
> +   load/store pair when addressed with an immediate offset from a shared 
> base,
> +   but not when addressed with a register offset.  The flag lets candidate
> +   selection (via the cost in get_address_cost) steer away from 
> register-offset
> +   addressing in that case.  */
> +
> +static void
> +determine_addr_use_pairing_siblings (struct ivopts_data *data)
> +{
> +  auto_vec<struct iv_use *, 16> addr_uses;
> +  unsigned i, j;
> +  struct iv_group *group;
> +
> +  FOR_EACH_VEC_ELT (data->vgroups, i, group)
> +    {
> +      if (!address_p (group->type))
> +     continue;
> +      struct iv_use *use;
> +      FOR_EACH_VEC_ELT (group->vuses, j, use)
> +     /* integer_zero_node is determine_base_object's "multiple base objects"
> +        sentinel; it must not be treated as a shared base.  */
> +     if (use->iv->base_object != NULL_TREE
> +         && use->iv->base_object != integer_zero_node)
> +       addr_uses.safe_push (use);
> +    }
> +
> +  struct iv_use *u, *v;
> +  FOR_EACH_VEC_ELT (addr_uses, i, u)
> +    FOR_EACH_VEC_ELT (addr_uses, j, v)
> +      {
> +     if (u == v)
> +       continue;
> +     if (operand_equal_p (u->iv->base_object, v->iv->base_object, 0)
> +         && operand_equal_p (u->iv->step, v->iv->step, OEP_ASSUME_WRAPV)
> +         && !operand_equal_p (u->iv->base, v->iv->base, OEP_ASSUME_WRAPV))
> +       {
> +         u->has_pairing_sibling = true;
> +         break;
> +       }
> +      }
> +}
> +
>  /* Finds uses of the induction variables that are interesting.  */
>  
>  static void
> @@ -2705,6 +2756,11 @@ find_interesting_uses (struct ivopts_data *data, 
> basic_block *body)
>  
>    split_address_groups (data);
>  
> +  /* Skip the sibling analysis for loops the optimizer will not consider
> +     anyway (cf. the MAX_CONSIDERED_GROUPS bail-out in its caller).  */
> +  if (data->vgroups.length () <= MAX_CONSIDERED_GROUPS)
> +    determine_addr_use_pairing_siblings (data);
> +
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      {
>        fprintf (dump_file, "\n<IV Groups>:\n");
> 

-- 
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