My memory says that somebody (Valdis?) reported crashes with the
AIX compiler at high optimization because it started assuming
that pointers were not aliased. The optimization (I guess) is
that a value does not ever have to hit memory if the compiler can
determine that no pointer could ever reference it. The value can
live entirely in a register, which is a win.
This looks insane. Am I misreading it, or does it really say that
`*(&t.i)' is different than `t.i'? Also, why should union type
variables be any different than other variables in this regard? For
instance:
I think they are saying that *((int *)&t.d) is not equal to
*(&t.i). To make it possible for the int value and the floating
point value of the union to live in two different registers, the
compiler writers demand that you explicitly ask for type-punning so
they can only do the expensive memory store when necessary.
To try and answer Hrvoje's question, which was roughly "What is the
difference between these two functions?"
int f() { int f() {
a_union t; int a;
int* ip; int *ip;
t.d = 3.0; a = 10;
ip = &t.i; ip = &a;
return *ip; return *ip;
} }
In the function on the left the optimizer will see that there is
no pointer reference to t.d. &t.i, not &t.d, is copied to ip.
t.d and t.i don't necessarily share storage space unless you
reference the union element directly. Sort of like quantum
states being unresolved until you look at them. So 3.0 never
has to be copied from a register to memory.
In the function on the right, &a is copied to ip. ip is later
dereferenced, so the register contents need to be in memory before
that dereference happens. (ip should really be declared "volatile
int *ip" to keep the ip assignment and subsequent deference from
being optimized away.)