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

            Bug ID: 92963
           Summary: Optimization with `restrict`: is `p == q ? p : q`
                    "based" on `p`?
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ch3root at openwall dot com
  Target Milestone: ---

The question: is `p == q ? p : q` "based" on `p` (as in C11, 6.7.3.1p3)?

First, suppose that the answer is "yes". Then the following program should be
strictly conforming and should always print "2":

----------------------------------------------------------------------
#include <stdio.h>

__attribute__((__noinline__)) // imagine it in a separate TU
static int f(int *restrict p, int *restrict q)
{
    *p = 1;

    int *r;
    if (p == q)
        r = p;
    else
        r = q;

    // is r "based" on p?

    *r = 2;

    return *p;
}

int main()
{
    int x;
    printf("%d\n", f(&x, &x));
}
----------------------------------------------------------------------
$ gcc -std=c11 test.c && ./a.out
2
$ gcc -std=c11 -O3 test.c && ./a.out
1
----------------------------------------------------------------------
gcc x86-64 version: gcc (GCC) 10.0.0 20191216 (experimental)
----------------------------------------------------------------------

Ok, fair enough, `p == q ? p : q` is always equal to `q`, doesn't change when
`p` changes and, thus, is not "based" on `p`.
Then the following program (3 differences are marked) should be fine according
to the standard and should always print "2":

----------------------------------------------------------------------
#include <stdio.h>

__attribute__((__noinline__)) // imagine it in a separate TU
static int f(int *restrict p, int *restrict q)
{
    *q = 1; // 1) changed p -> q

    int *r;
    if (p == q)
        r = p;
    else
        r = q;

    // is r "based" on p?

    if (p == q) // 2) added if
        *r = 2;

    return *q; // 3) changed p -> q
}

int main()
{
    int x;
    printf("%d\n", f(&x, &x));
}
----------------------------------------------------------------------
$ gcc -std=c11 test.c && ./a.out
2
$ gcc -std=c11 -O3 test.c && ./a.out
1
----------------------------------------------------------------------

Either way, there is a problem...

Reply via email to