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.
In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.
Pointer aliasing is a hidden kind of data dependency that can occur in C, C++, or any other language that uses pointers for array addresses in arithmetic operations. Array data identified by pointers in C can overlap, because the C language puts very few restrictions on pointers.
In C++, references are just aliases for the thing that they refer to, the standard doesn't even require them to take up any storage. Trying to use a reference alias to make a reference to a pointer will not work because using the alias will only ever give you a pointer to a reference type.
The NoAlias Attribute. Burst has a [NoAlias] attribute that can be used to give the compiler additional information on the aliasing of pointers and structs. There are four uses of this attribute: On a function parameter it signifies that the parameter does not alias with any other parameter to the function.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With