https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67705

            Bug ID: 67705
           Summary: incorrect restrict interpretation
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vries at gcc dot gnu.org
  Target Milestone: ---

I think I found an example for which the compiler misinterprets restrict.

Consider test-case test.c:
...
void
f (int *__restrict__ &__restrict__ fp,
   int *__restrict__ &__restrict__ fp2)
{
  *fp = 1;
  *fp2 = 2;
}

void
g (int *__restrict__ gp)
{
  f (gp, gp);
}

void
h (void)
{
  int ha;
  g (&ha);
}
...

At the ealias dump we see that the two stores are disambiguated, due to the
fact that they're in the same clique (1) but have different bases (base 2 and
base 4):
...
void f(int* __restrict__&, int* __restrict__&) (intD.9 * restrict & restrict
fpD.2252, intD.9 * restrict & restrict fp2D.2253)
{
  intD.9 * _3;
  intD.9 * _6;

  # VUSE <.MEM_1(D)>
  # PT = { D.2269 } (nonlocal)
  _3 = MEM[(intD.9 * restrict &)fp_2(D) clique 1 base 1];

  # .MEM_4 = VDEF <.MEM_1(D)>
  MEM[(intD.9 *)_3 clique 1 base 2] = 1;

  # VUSE <.MEM_4>
  # PT = { D.2271 } (nonlocal)
  _6 = MEM[(intD.9 * restrict &)fp2_5(D) clique 1 base 3];

  # .MEM_7 = VDEF <.MEM_4>
  MEM[(intD.9 *)_6 clique 1 base 4] = 2;
...

>From the example, it's obvious that the stores in fact alias, because we call f
with the two arguments being identical.

The question is if this is a valid example, in other words, doesn't passing
identical arguments violate the second restrict in both "int *__restrict__
&__restrict__ fp" and "int *__restrict__ &__restrict__ fp2"?

I think the example is valid, due to the "modified" wording in the restrict
definition.

In the case of the second restrict, the object being referenced is gp. And gp
is not modified during execution of f, so the restrict has no impact.

This link has an explanation of the "modified" wording:
http://www.lysator.liu.se/%28nobg%29/c/restrict.html at "Aliasing of unmodified
objects".

It's to allow a call "f10(x, y, y)" to this function:
...
void
f10 (int n, float *restrict a, float *restrict b, float *restrict c)
{
  int i;
  for ( i=0; i<n; i++ )
    a[i] = b[i] + c[i];
}
...
The object pointed to by y is not modified in f10, so we're allowed to mark
both b and c restrict. And marking b and c restrict helps compilers which only
disambiguate is both pointers are restrict (PR48885), in other words, it allows
those compilers to disambiguate between first a[i] and b[i], and second a[i]
and c[i].

The downside of the "modified" wording is: "... allow aliasing through two
restrict-qualified pointers provided the referenced objects are not modified.
Unfortunately, if those objects are themselves pointers (i.e., there are two
levels of indirection), this aliasing can inhibit optimization, even if the
secondary pointers are also restrict-qualified and used to modify the objects
to which they, in turn, refer.  See X3J11.1/93-040 for examples."

I think test.c above is such an example (I have no access to X3J11.1/93-040
though).

Reply via email to