Search code examples
crestrictrestrict-qualifier

Is there a way to tell the C compiler that a pointer has no aliasing stores?


If the C compiler knows that a pointer is not aliased, it can perform many optimizations. For example, if I compile the following function with gcc -O2:

int f_noalias(int *arr, int x)
{
    int res = 0;
    int *p = &arr[17];
    *p = x;
    res += *p;
    res += *p;
    return res;
}

the compiler knows that reading *p will always evaluate to x so the generated code is equivalent to the one generated for the following function:

int f_noalias2(int *arr, int x)
{
    int *p = &arr[17];
    *p = x;
    return 2*x;
}

However, if the compiler thinks the pointer might be aliased, it doesn't perform this optimization anymore. For example, if we modify f so that an unknown function is called between the reads to *p, the generated code will dereference p twice. The compiler assumes that the read_arr function might have modified the value that p points to.

int f_withalias(int *arr, int x)
{
    int res = 0;
    int *p = &arr[17];
    *p = x;
    res += *p;
    read_array(arr);
    res += *p;
    return res;
}

In my particular program, when the f function is running the p pointer that it holds is the only one that writes to that element of the arr array. Other functions in the code might read from arr during this time, but won't write to it. (They might write other values to arr after f finishes running though.)

So now I have three questions:

First: Is there a way I can declare my variables to give this hint to the C compiler? I tried adding a restrict annotation to p but the generated code under gcc -O2 was identical to the generated code for f_withalias

int f_restrict(int *arr, int x)
{
    int res = 0;
    int * restrict p = &arr[17];
    *p = x;
    res += *p;
    read_array(arr);
    res += *p;
    return res;
}

Second: Is my attempt to use restrict here valid? My understanding is that restrict means that no other pointers can alias p, both for reading or writing. But in my case the read_arr function clearly can also access the arr array that p is pointing to.

Third: If the answer to the previous question is "no", is there something different I can try instead of restrict?

Basically, I need to make sure that if I do *p = x in f then that write will be immediately noticed by other functions reading from arr[17]. However, I want GCC to feel free to optimize things like x = *p; y = *p to x = *p; y = x, even if there are function calls between the two reads.


Solution

  • First: Is there a way I can declare my variables to give this hint to the C compiler?

    int * restrict p = &arr[17]; asserts that only p and pointer expressions based on p will be used to access any object p points to for the duration of the block (except for objects that are not modified in any way). This enables the optimization of res += *p; that you propose. The fact that GCC does not so optimize is a quality issue in GCC.

    Second: Is my attempt to use restrict here valid? … Basically, I need to make sure that if I do *p = x in f then that write will be immediately noticed by other functions reading from arr[17].

    The latter property is not a valid use of restrict. The fact that p is declared restrict and arr[17] is modified via p means that no pointer not based on p should be used to access arr[17] during the execution of the block containing p, not even for reading. So, if something in read_array did read arr[17] (using arr, which is not based on p), it would be a violation of the restrict assertion.