Consider the following snippet as an example:
*pInt = 0xFFFF;
*pFloat = 5.0;
Since they are int
and float
pointers, the compiler will assume they don't alias and can exchange them for example.
Now let's assume we spice it up with this:
*pInt = 0xFFFF;
*pChar = 'X';
*pFloat = 5.0;
Since char*
is allowed to alias anything, it may point to *pInt
, so the assignment to *pInt
cannot be moved beyond the assignment of *pChar
, because it may legitimately point to *pInt
and set its first byte to 'X'.
Similarly pChar
may point to *pFloat
, assignment to *pFloat
cannot be moved before the char assignment, because the code may intend to nullify the effects of the previous byte setting by reassigning the *pFloat
.
Does this mean I can write and read through char*
to create barriers for rearrangement and other strict aliasing related optimizations?
Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias eachother.) Here are some basic examples of assumptions that may be made by the compiler when strict aliasing is enabled:
Aliasing: Aliasing refers to the situation where the same memory location can be accessed using different names. For Example, if a function takes two pointers A and B which have the same value, then the name A [0] aliases the name B [0] i.e., we say the pointers A and B alias each other. Below is the program to illustrate aliasing in C:
It is unlikely that code that does not enable strict aliasing would be able to take advantage of the restrict keyword. Using the restrict keyword allows a significant class of memory access optimizations critical to high performance code.
The memory referred to by sp is an alias of arg because they refer to the same address in memory. In C99, it is illegal to create an alias of a different type than the original. This is often refered to as the strict aliasing rule. The rule is enabled by default in GCC at optimization levels at or above O2.
Pointer aliasing mostly makes sense in scenarios when the compiler can't know if a pointer variable alias another pointer or not. As in the case when you compile a function located in a different translation unit than the caller.
void func (char* pChar, float* pFloat)
{
*pChar = 'X';
*pFloat = 5.0;
}
Here the pFloat
assignment can indeed not be sequenced before the pChar
one, because the compiler can't deduct that pChar
does not point at the same location as pFloat
.
However, when facing this scenario, the compiler can (and probably will) add a run-time check to see if the addresses could be pointing at overlapping memory or not. If they do, then the code must be sequenced in the given order. If not, then the code may be re-organized and optimized.
Meaning that you would only get memory barrier-like behavior in case the pointers actually do alias/point at overlapping memory. If not, then all bets regarding instruction ordering would be off. So this is probably not a mechanism that you should rely upon.
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