Some time ago, in a (probably misguided) attempt to adapt at runtime to a bit of endian weirdness, I wrote some code that looked more or less like
int64_t buffer[2]; ... volatile int64_t *a = (volatile int64_t*)buffer; volatile int32_t *b = (volatile int32_t*)buffer; *a = 1; if( *b == 1 ) doSomeStuff();There was a bit more to it, but this is representative. This code worked well for quite some time, until we needed to move the program that it is part of to machine with a different processor architecture. When we turned on optimization in the compiler, the program stopped working.
Frantic debugging ensued. Eventually I discovered that the optimizing compiler turns the snippet above into something like this (retouched into hypothetical pseudo assembly such as to protect the innocent):
add sp,#24,r13 mov #0,r3 load 0(r13),r5 mov #1,r4 store r3,4(r13) cmp #1,r5 store r4,0(r13) bsr.eq doSomeStuff
Now, an ordinary competent programmer should be able to understand
that C99's strict aliasing rules authorize a compiler
to assume that *a
and *b
refer to different
objects, and therefore the optimizer may reorder the code such that
the read of *b
happens before *a
is written.
I admit it surprised me a bit that the volatile qualifiers did not
prevent this, which seems to violate the letter of the C standard regarding
volatile accesses and sequence points. However, apparently the compiler
in question does not recognize any ordering constraints on accesses to
"different" volatile-qualified objects within a basic block.
However, notice that even though the compiler is not smart enough to know that the two pointers alias, it is smart enough to figure out that they can share the same register! If you think that is perfectly reasonable and understandable, you're seriously at risk of being a compiler writer at heart.
For the record, I do and I am.
P.S. The Right way to code this is type-pun through an union instead:
union { int64_t a[2]; int32_t b; } buffer; ... buffer.a[0] = 1; if( buffer.b == 1 ) doSomeStuff();
which in this case compiled into an uncoditional call to
doSomeStuff
.
Understanding Strict Aliasing
by Mike Acton explains both the rules and the cheats that nevertheless
work with admirable clarity. Respectfully recommended for your
edification.
No comments:
Post a Comment