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