On Tue, Feb 13, 2024 at 2:02 PM Ties Klappe via Gcc <gcc@gcc.gnu.org> wrote: > > Hi, > > I have two questions related to nested restrict pointers. > GCC 13.02 with optimization level 3 optimizes the function *foo1* to simply > return 10. > > int foo1(int *restrict *restrict p, int *restrict *restrict q) > { > **p = 10; > **q = 11; > return **p; > } > > I am curious why the function *foo2* is not optimized in the same way (see > https://godbolt.org/z/E4cx1c1GP): the first pointer dereference of p and q > result in the restrict qualified pointer lvalues, which are used to write > to a disjoint (as promised by the restrict qualifier) location storing an > integer object. So this should give enough information to perform the > optimization, i.e. a write via **q cannot change the object **p designates > if the program has defined behavior. > > int foo2(int *restrict *p, int *restrict *q) > { > **p = 10; > **q = 11;
this function could do int a; *p = &a; **q = 11; **p = 12; > return **q; even when being called as you outline below. > } > > Secondly, if we would have a client *main* invoking *foo1* (see below), the > optimization would be incorrect if the client does not contain undefined > behavior. So I am curious how the standard section 6.7.3.1 actually applies > here: if the program is defined, I would assume both lvalues *p and *q are > said to be based on xp (xp = *p = *q; = object `*P` *where the standard > refers to), but is it actually the case that both the *p and *q expressions > are based on the same object P? > > int main() { > int x = 0; > int* xp = &x; > > int res = foo1(&xp, &xp); > > return 0; > } > > So to wrap up, I have two questions: > > 1. Should *foo2* be optimized in the same way as *foo1* and is it simply a > missed optimization candidate, or is there another reason GCC does not > optimize it? > 2. Does the client *main* contain undefined behavior according to GCC, and > if so, why? > > Thank you in advance. We are optimizing the following which is related at least to the amount of memory references done. I'm also curious how the standard reads here. Implementation-wise it's a bit difficult to handle the int ** restrict case, as points-to analysis has to handle *p and *q to point to an object as if p and q themselves were restrict. I'm not sure that doesn't open up things for miscompiles. int * restrict p; int * restrict q; int foo2() { *p = 10; *q = 11; return *p; } int main () { int x = 0; int* xp = &x; p = xp; q = xp; int res = foo1(); return 0; } Richard. > Kind regards, > Ties