int test(bool* flag, int* y)
{
*flag = true;
As-is, it is dubious if this is an allowed optimization. The compiler is not allowed to optimize out or reorder what the standard calls side effects, defined in C17 5.1.2.3:
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects ...
/--/
The presence of a sequence point
between the evaluation of expressions A and B implies that every value computation and side effect associated with A is sequenced before every value computation and side effect associated with B.
In this case, a lvalue access to the object pointed at by flag
modifies an object - it is a side effect. However, reading from *y
is not a side effect, but writing the the same variable twice *flag = true;
... *flag = false;
would introduce a new side effect which wasn't there in the code.
But this is an artificial example. An optimizing compiler wouldn't do such optimizations on a "C level". Instead it would likely use a CPU register as temporary variable, in case freeing one up while setting it to zero would somehow be more efficient. So it wouldn't write to the actual location flag
but to a temporary register.
Even more likely, it would set a register to the value of the boolean expression *y != 0
then copy that register value 1 or 0 into *flag
. Notably if I change your C code to this:
int test(bool* flag, int* y)
{
*flag = *y != 0;
}
Then I get the very same machine code, given that optimizations are enabled. On gcc x86 -O3 it might look like:
mov eax, DWORD PTR [rsi]
test eax, eax
setne BYTE PTR [rdi]
ret
That is, copy flag
into register eax, then depending on if eax is set or not, set some status flag with test
and store the result 1 or 0 into test
depending on that result.
The main optimization to consider here is likely to generate "branch free" code, without any comparisons or conditional jumps etc, since that leads to efficient use of instruction cache on high-end CPUs such as x86.
Regarding multi-threading, none of this code is safe regardless of re-ordering, because a write to a C variable cannot be considered atomic unless explicitly qualified as such (_Atomic
etc).
Regarding strict aliasing as brought up in other answers, it isn't really relevant here. A bool*
and int*
are non-compatible pointer types and may not alias. The compiler cannot assume that a write to *flag
will change *y
or vice versa.