Hello,

On Tue, 13 Oct 2026, Richard Biener wrote:

> > > 1. It also happens with plain arrays and the same base.  PR120254 is
> > >    wrong at -O3 on trunk (92a7b1230e6): for A[k+1][i][i] against
> > >    A[k][i][i] in an (i, j, k) nest the only distance vector is (0 0 1),
> > >    but (0 1 -1) is a real distance, and interchange swaps j and k.
> > >
> > > 2. The cause is in build_classic_dist_vector.  Call a loop of the nest
> > >    free when none of the compared access functions evolves in it.
> > >    A free loop gets component 0 in every distance vector.  Only when
> > >    it lies outside every constrained loop are vectors added with 1 in
> > >    its component (add_outer_distances, add_other_self_distances,
> > >    add_distance_for_zero_overlaps).  So the vectors cover all
> > >    distances only when there is no free loop, or exactly one that
> > >    lies outside all the constrained loops.
> > >
> > > 3. In the structure case, full_seq = struct_seq drops the base
> > >    subscript, so the loop in which the objects move becomes a free
> > >    loop.  That is PR115869 and PR105771.
> > >
> > > 4. Unroll-and-jam already guards against this using DR_ACCESS_FNS, but
> > >    the structure path defeats that check because it looks at the
> > >    reference's access functions rather than the compared ones.  Loop
> > >    distribution has its own guard.  Interchange has none.  I found no
> > >    vectorizer miscompile.
> > >
> > > 5. On x[k].v vs x[k + d].v: giving it the same dependences as x[k] vs
> > >    x[k + d] would be right, but not enough on its own, since as in 1
> > >    plain arrays miss distances too in deeper nests.  For x[k].v[j],
> > >    j invariant or in an outer loop behaves like x[k].v; with j in an
> > >    inner loop the vectors are conservative in a two-deep nest, but a
> > >    three-deep nest with the objects moving in the middle loop
> > >    miscompiles at -O3 -fno-loop-unroll-and-jam.
> > >
> > > I have tried a fix in both places:
> > >
> > >  a) In the consumers: unroll-and-jam's existing guard uses the
> > >     compared access functions, and interchange refuses only a loop
> > >     pair whose swap a missing distance could reverse.  57 changed
> > >     lines.
> > >
> > >  b) In tree-data-ref.cc: give up on a relation whose vectors miss a
> > >     free loop.  This also has to release the distance vectors
> > >     (unroll-and-jam reads them even on chrec_dont_know) and count a
> > >     loop as free only if it contains both references.  61 changed
> > >     lines.
...
> > So I was hoping there might be a simpler way.  However, the same-base
> > examples above suggest that (b) really is the right thing after all.
> > 
> > Isn't it a bug that unroll-and-jam's adjust_unroll_factor doesn't check
> > whether DDR_ARE_DEPENDENT (ddr) is chrec_dont_know?  The dump functions
> > in tree-data-ref.cc suggest that the distance vectors shouldn't be read
> > in that case.  And there is an existing early-out in
> > add_other_self_distances:
> > 
> >           if (DDR_NUM_SUBSCRIPTS (ddr) != 1)
> >             {
> >               DDR_ARE_DEPENDENT (ddr) = chrec_dont_know;
> >               return;
> >             }
> > 
> > where (AIUI) the code is explicitly dropping a case that would matter
> > to consumers of the distance vectors.
> 
> IIRC Michael Matz analyzed a latent data dependence issue that boils
> down to the bad representation of distance/direction vectors which
> do not encode the do-not-know (either direction) case leading to
> downstream wrong answers exactly in the case where there are
> loops without an evolution.  Maybe he remembers and also the
> associated PR.

I don't and I can't seem to find my notes about that.  I think my last two 
comments at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49782#c3 are 
remnants of what was the cause that ultimately lead me to investigate the 
current representation of distance and direction vectors in tree-data-ref, 
whatever that cause really was :)

I think the observations (1) to (5) are correct, though I seem to remember 
that also the fact that if there are multiple directions (+1 and -1) in 
one dimension that the resulting dimension isn't correctly collapsing to 
'*' (i.e. not necessarily only in cases where the dimension is such 
because of invariantness in its respective iteration dimension).  In fact 
we have no notion of '*' at all, and hence variously either give up 
totally or create wrong or incomplete distance vectors.

There certainly were confusing interactions between the manipulation of 
nr-of-dimensions and sometimes ignoring or not ignoring the such-changed
dimensions and building the classic distance vectors out of that: for 
client code the number of components in these vectors must match the 
nest-depth of the analyzed loop nest and the manipulation above shuffles 
components around in non-obvious ways ultimately leading to comparing 
dimensions that really stem from different loops, and hence needing 
strange-looking workaround in several of the client code that currently 
exists in GCC.  That all usually only starts to matter when a real nest, 
i.e. at least two loops, are involved.

The fact that unroll-and-jam doesn't test DDR_ARE_DEPENDEND for 
chrec_dont_know may be an artifact of such client-code work-arounds, I 
don't remember.  I also may have just missed to add it and the other 
necessary work-arounds were hiding the fact.

Another wart was that the direction vector is calculation from the 
distance vector(s), which is always optimal: the direction vector may 
exist when the distance vectors aren't representable, which we don't 
handle.

Either way, I think just adding various additional guards to the existing 
passes is the wrong way.  The output of tree-data-ref (and in particular 
the dependence relation pairs) simply needs to be correct.  For that I 
think we need a representation of '*' in a component, and we need to stop 
adding fake dimensions that aren't directly related to a loop (certainly 
such fake dimensions must at least not be used when considering a pair of 
datarefs), and then the component of a relation between two datarefs where 
one is invariant and the other affine will naturally come out as '*', as 
it should be.

I'm sorry if this sounds like unstructured rambling, I really don't 
remember the details or find my notes :-(

Ciao,
Michael.

> 
> Richard.
> 
> > Thanks,
> > Richard
> > 
> > > Testing so far, on aarch64-linux: both were built and run through the
> > > same targeted tests (the new tests, vect.exp, the interchange,
> > > unroll-and-jam and prefetch tests) and the testsuite comparison above.
> > > (a) has also passed a three-stage bootstrap and full regression
> > > testing against an unpatched baseline; (b) has not had a bootstrap or
> > > a full regression run.
> > >
> > > The v1 patch does not fix PR120254 and should be considered
> > > superseded.
> > >
> > > Which direction would you prefer?  I will post (a) once the release
> > > branch testing finishes, unless you would rather have (b), in which
> > > case I will give it the same full testing first.
> > >
> > > Thanks,
> > > Rohith
> > 
> 
> 

Reply via email to