A restrict-qualified pointer parameter of a function is an effective way to allow compilers to optimize that function:
int f(const int *restrict p) {
int n=*p;
printf("Debug\n");
return *p==n;
}
Here Clang 17 with -O3 will just return 1 without re-examining *p, and without performing the comparison.
Without restrict, *p has to be re-examined and the comparison has to be performed. This is because printf is an external function, and the compiler doesn't know if it might modify *p. Indeed, if p happens to be pointing into the file position indicator of stdout, printf is actually going to modify it.
So, as a general principle, if you want maximum optimization for the function, and your function ever calls an external function, it is not meaningless to declare all your parameters restrict. Of course, this places a severe restriction on callers, because it requires them to promise that they will not call your function with pointers aliased into unexpected places.
My question goes further than this observation. I ask if restrict permits optimization of the callers of your function too?
int f(const int *restrict p);
int caller(int *p) {
int n=*p;
f(p);
return *p==n;
}
It would seem to me that this guarantees to the compiler that f will not modify *p, thus it can omit re-examining *p and the comparison, and can safely return 1. Neither Clang nor GCC do this optimization.
I know it's OK that they don't optimize the caller. I am asking whether the are permitted to optimize. (This is primarily a question about the semantics of my program, not about performance.)
In this code:
the compiler cannot conclude that
*pdoes not change during execution offbecause the code below shows a definition offand a call tocallerin which the behavior is defined (does not violate therestrictrequirements) yet the value of*pchanges during execution off:When
fis called in this case,ppoints tom[0], so*pism[0]. Sincefchangesm[0], the value of*pchanges during execution off, but this does not violate therestrictrequirements because therestrictdefinition only imposes requirements ifpis used, directly or indirectly, to access the object. C 2018 6.7.3.1 4 says:In the above
f,m[0]is accessed only through the lvaluem[0]and not through any lvalue whose address is based onp. So the prerequisite condition forrestrictnever occurs form[0], so it imposes no constraints on whether or howm[0]is modified.