On Wed, 16 Jun 1999, Kyle Jones wrote:
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.
I don't think I understand that. t.i and t.d do share the same memory
space. Since the address of t.i is taken, the compiler must ensure that
at all "places that matter" (function calls, dereferences, etc), that t.d
and t.i are "flushed" to memory, since they occupy the same bits.
A clever optimizer may be able to save the memory store, but it would have
to know how to slice a double into an int. [Remember that f() does not
return 3, but the upper/lower 2/4/8 bytes of the double.]
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.)
Why bother? Let the optimizer do its best:
int f() {
int a;
int *ip;
a = 10;
return *(ip = &a);
}
"ip isn't used again. Don't store."
return *&a
"I know that *&a == 10 in all cases"
int f() {
int a;
a = 10;
return 10;
}
"a is set without side effects optimize it away, and unused again" =>
int f() {
return 10;
}
-Justin
vallon(a)mindspring.com