Rohith Kapelli <[email protected]> writes:
> For references with different bases, dependence analysis compares only
> the structure-rooted access functions and sets DDR_COULD_BE_INDEPENDENT_P.
> The distance vectors are then only valid for one fixed pair of objects,
> which is the case when DDR_OBJECT_A is set because both objects are
> invariant in the loop nest.  In PR115869 res[k].v and res[k + d].v move
> with k, so the vectors (0 0), (1 0) and (0 1) miss the (1, -d) dependence
> and loop interchange wrongly swaps the nest.  PR105771 is the same problem
> in unroll-and-jam.
>
> The vectorizer and prefetching handle such relations, but interchange and
> unroll-and-jam use the vectors as they are and cannot check the objects at
> runtime.  The following makes both passes give up when DDR_OBJECT_A is not
> set.
>
>       PR tree-optimization/115869
>       PR tree-optimization/105771
>
> gcc/ChangeLog:
>
>       * gimple-loop-interchange.cc (tree_loop_interchange_compute_ddrs):
>       Give up if DDR_COULD_BE_INDEPENDENT_P is set and DDR_OBJECT_A is not.
>       * gimple-loop-jam.cc (adjust_unroll_factor): Likewise.
>
> gcc/testsuite/ChangeLog:
>
>       * gcc.dg/torture/pr105771.c: New test.
>       * gcc.dg/torture/pr115869.c: New test.
>
> Signed-off-by: Rohith Kapelli <[email protected]>
> ---
> Bootstrapped and regression tested on aarch64-unknown-linux-gnu, and on
> the gcc-14, gcc-15 and gcc-16 branches.  An attempt to fix this in
> tree-data-ref.cc instead regressed gcc.dg/vect/vect-alias-check-3.c.
>
> OK for trunk and the branches?

I think the problem is instead in tree-data-ref.cc itself.  As the comments
say, the dependence distances are supposed to be conservatively correct even
when DDR_COULD_BE_INDEPEDENT_P is true.  (Thus the check in the prefetcher
should be unnecessary.)

The else in:

  if (same_base_p)
    {
      if (indices_a->unconstrained_base)
        full_seq.length += 1;
    }
  else
    full_seq = struct_seq;

was intended mostly to handle cases where an array access is a
subaccess of a structure access, such as in:

  x->foo[k] vs. y->foo[k + 1]

In this case we can compute a conservative dependence distance for a
single-nested k loop even if x and y are not invariant, since aliasing
rules don't allow x->foo and y->foo to partially overlap.

But "x[k].v" vs. "x[k + d].v" provides no more information than
"x[k]" vs. "x[k + d]" and so the dependencies should be the same.
Similarly for "x[k].v[j]" vs. "x[k + d].v[j]" where "j" is indepedent
of "k".

I'll need to think more about where in the compute_affine_dependence
this should be handled.  I just wanted to say something now rather than
leave the patch unreviewed.

Thanks,
Richard

>
>  gcc/gimple-loop-interchange.cc          |  7 +++++
>  gcc/gimple-loop-jam.cc                  |  5 +++-
>  gcc/testsuite/gcc.dg/torture/pr105771.c | 36 +++++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/torture/pr115869.c | 25 +++++++++++++++++
>  4 files changed, 72 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr105771.c
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr115869.c
>
> diff --git a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc
> index 7f8ca2f9d57b..4091d1916ed1 100644
> --- a/gcc/gimple-loop-interchange.cc
> +++ b/gcc/gimple-loop-interchange.cc
> @@ -1883,6 +1883,13 @@ tree_loop_interchange_compute_ddrs (vec<loop_p> 
> loop_nest,
>                   && DDR_NUM_DIR_VECTS (ddr) == 0))
>             return false;
>  
> +         /* The vectors describe one fixed pair of objects only when
> +            DDR_OBJECT_A is set; this pass cannot check them at runtime.  */
> +         if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE
> +             && DDR_COULD_BE_INDEPENDENT_P (ddr)
> +             && !DDR_OBJECT_A (ddr))
> +           return false;
> +
>           /* If either data references is in outer loop of nest, we require
>              no dependence here because the data reference need to be moved
>              into inner loop during interchange.  */
> diff --git a/gcc/gimple-loop-jam.cc b/gcc/gimple-loop-jam.cc
> index 2c4162d17a2a..7b39f40f229a 100644
> --- a/gcc/gimple-loop-jam.cc
> +++ b/gcc/gimple-loop-jam.cc
> @@ -407,7 +407,10 @@ adjust_unroll_factor (class loop *inner, struct 
> data_dependence_relation *ddr,
>    bool ret = false;
>    if (DDR_ARE_DEPENDENT (ddr) != chrec_known)
>      {
> -      if (DDR_NUM_DIST_VECTS (ddr) == 0)
> +      /* The vectors describe one fixed pair of objects only when
> +      DDR_OBJECT_A is set; this pass cannot check them at runtime.  */
> +      if (DDR_NUM_DIST_VECTS (ddr) == 0
> +       || (DDR_COULD_BE_INDEPENDENT_P (ddr) && !DDR_OBJECT_A (ddr)))
>       return false;
>        unsigned i;
>        lambda_vector dist_v;
> diff --git a/gcc/testsuite/gcc.dg/torture/pr105771.c 
> b/gcc/testsuite/gcc.dg/torture/pr105771.c
> new file mode 100644
> index 000000000000..dc862f7e7cae
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr105771.c
> @@ -0,0 +1,36 @@
> +/* PR tree-optimization/105771 */
> +/* { dg-do run } */
> +/* { dg-additional-options "-floop-unroll-and-jam" } */
> +
> +struct st { unsigned v; };
> +
> +__attribute__((noipa)) void
> +f (struct st *p, int m, int n, int d)
> +{
> +  for (int i = 0; i < m; i++)
> +    for (int k = 0; k + d < n; k++)
> +      p[k + d].v = p[k + d].v * 3 + p[k].v + (unsigned) i;
> +}
> +
> +__attribute__((noipa)) void
> +g (volatile unsigned *q, int m, int n, int d)
> +{
> +  for (int i = 0; i < m; i++)
> +    for (int k = 0; k + d < n; k++)
> +      q[k + d] = q[k + d] * 3 + q[k] + (unsigned) i;
> +}
> +
> +int
> +main ()
> +{
> +  struct st p[16];
> +  unsigned q[16];
> +  for (int j = 0; j < 16; j++)
> +    p[j].v = q[j] = (unsigned) j + 1;
> +  f (p, 8, 16, 1);
> +  g (q, 8, 16, 1);
> +  for (int j = 0; j < 16; j++)
> +    if (p[j].v != q[j])
> +      __builtin_abort ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/torture/pr115869.c 
> b/gcc/testsuite/gcc.dg/torture/pr115869.c
> new file mode 100644
> index 000000000000..083a6180cc30
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr115869.c
> @@ -0,0 +1,25 @@
> +/* PR tree-optimization/115869 */
> +/* { dg-do run } */
> +/* { dg-additional-options "-floop-interchange" } */
> +
> +struct st { int v; };
> +
> +__attribute__((noipa)) int
> +f (struct st *res)
> +{
> +  res[0].v = 1;
> +  for (int d = 1; d < 3; d++)
> +    for (int i = 0; i < 2; i++)
> +      for (int k = 0; k + d < 3; k++)
> +     res[k + d].v += res[k].v;
> +  return res[2].v;
> +}
> +
> +int
> +main ()
> +{
> +  struct st res[3] = { { 0 }, { 0 }, { 0 } };
> +  if (f (res) != 5)
> +    __builtin_abort ();
> +  return 0;
> +}

Reply via email to