As a follow up to my previous question, consider the following code:
int f(int *p);
static inline int g0(int *p) {
*p=0;
f(NULL); // might modify *p
return *p==0;
}
int caller0(int *q) { return g0(q); }
Above, after calling f, the compiler has to fetch *p and perform the comparison to 0, because p might alias memory that is also available to f. However:
static inline int g1(int *restrict p) {
*p=0;
f(NULL); // cannot modify *p
return *p==0;
}
int caller1(int *q) { return g1(q); }
Because of restrict, the compiler can deduce that it is illegal for f to modify *p, thus it can just return 1, optimizing out the fetch and the comparison. Clang 17 does this optimization. However:
int caller2(int *q) {
{ int *restrict p=q;
*p=0;
f(NULL);
return *p==0;
}
}
This caller2 seems to me to be equivalent to caller1, just inlined by hand. The same Clang compiler did not optimize this (it emits the fetch and the comparison).
First question: Is the compiler allowed to optimize caller2?
Further:
int caller3(int *q) {
... // many lines of code
{ int *restrict p=q;
*p=0;
... // do something useful
f(q);
if (*p==0) { ... } // do something useful
}
... // many lines of code
}
Now this is the part I actually care about. If the compiler is allowed to optimize caller2, is it allowed to optimize caller3?
According to my reading of the standard, q is not "based on" p here, and *p is modified through the restrict-qualified pointer, therefore the compiler can assume that f does not modify *p (further; f isn't even allowed to read *q, so the compiler is even allowed to reorder the assignment *p=0 after the call to f (though f may legally read/write *(q+1))).
Is this correct? If it is, it suggests that restrict can be creatively used even inside the bodies of your functions to make various hints about aliasing to the compiler.
int dummy = *p;or(void)*pwould make it UB for anything in any callee to modify*pvia a differently-derived pointer. And I agree that access via the originalqor an arg copy of it probably doesn't count as "based on"int *restrict p = q. But that's the part I'm least sure about, only maybe 90 to 95% sure.restrictis introduced inside a function as withint * restrict p = q;is a deficiency discussed in a recent question, marked as a duplicate of this one.