If I got the C99 restrict
keyword right, qualifying a pointer with it is a promise made that the data it references won\'t be modified behind the compiler\'s back t
Your understanding is largely correct. The restrict
qualifier simply states that the data accessed by a so-qualified pointer is only accessed by that exact pointer. It applies to reads as wells as writes.
The compiler doesn't care about concurrent threads, it wasn't going to generate code any differently, and you may clobber your own data as you like. But it does need to know what pointer operations may change what global memory.
Restrict
also carries with it an API warning to humans that a given function is implemented with the assumption of unaliased parameters.
No locking by the user is necessary as far as the compiler is concerned. It only wants to make sure it correctly reads data that was supposed to be clobbered, by code the compiler was supposed to generate, in case there is no restrict
qualifier. Adding restrict
frees it from that concern.
Finally, note that the compiler is likely to already be analyzing possible aliasing based on data types, at the higher optimization levels, so restrict
is important mostly for functions with multiple pointers to the same type of data. You can take a lesson from this subject and make sure that any deliberate aliasing you do is done via a union
.
We can see restrict
in action:
void move(int *a, int *b) { void move(int *__restrict a, int *__restrict b) {
a[0] = b[0]; a[0] = b[0];
a[1] = b[0]; a[1] = b[0];
} }
movl (%edx), %eax movl (%edx), %edx
movl %eax, (%ecx) movl %edx, (%eax)
movl (%edx), %eax movl %edx, 4(%eax)
movl %eax, 4(%ecx)
In the right column, with restrict
, the compiler did not need to reread b[0]
from memory . It was able to read b[0]
and keep it in register %edx
, and then just store the register twice to memory. In the left column, it didn't know if the store to a
may have changed b
.