Re: Volatile variable as initializer for non-volatile variable?
On Mon, 15 Mar 2010 05:36:23 CST, "Johannes Schaub (litb)"
<schaub-johannes@web.de> wrote:
Hello all. Here is what i came across in some code the other day
int volatile some_magic;
int f() {
int j = some_magic;
// now do some nonsense calculus
for(int i=0;i<10;i++)
j += i;
return j;
}
int main() {
// do some loops and call f...
for(int j = 0;j<100;j++) f();
// ... (carefully crafted timings here)
}
Now, what are the conditions on the read of "some_magic"? It acts as an
initializer for "j", so it seems it somehow "depends" on its life. Can the
compiler, if it optimizes out "j" entirely, remove the read of "some_magic"?
No. Volatile reads and writes must occur as you would expect from
reading the source code, and may never be reordered/invented/elided.
For example, imagine some_magic mapped to a hardware counter than
returned the next highter integer on each read, and could be visible
to another thread or process after this program runs.
It appears to me optimizing this out is not valid, because in the abstract
machine "some_magic" is actually read there. And optimizing out "j" can only
be done if it wouldn't disturb the observable behavior, but exactly that is
*not* the case. The observable behavior is different.
I assume you mean the j in f? But both j's can be eliminated. A
compiler can eliminate main's j trivially, and eliminate f's j if it
can see that here the return value is never used, e.g., if it can see
across the call fo f(), say because f is inlined or it can see the
whole program. That is, the program above is equivalent to the
following if we assume the commented parts don't do any work:
int volatile some_magic;
int main() {
int r1 = some_magic; // read into some register and discard
r1 = some_magic; // 2nd time
...
r1 = some_magic; // 100th time
}
The compiler that was used (intel compiler, so it's the EDG frontend, i
suspect) optimized out the *entire code* but when "j" itself was made
volatile in addition it didn't optimize anymore. The reason that
"some_magic" was volatile is that it was some sort of intialization timer,
and the reason "j" wasn't volatile is because we wanted all the other code
to be as fast as possible, just the read from "some_magic" should be "real".
Assuming it really did optimize away some_magic: Perhaps the compiler
could see that some_magic was a variable that was only used in this
program, and couldn't be accessed outside this program because no
pointer/reference to it was shared anywhere, it wasn't in
inter-process shared memory, and in particular it wasn't mapped to a
specific hardware address (as it would be with, e.g., int volatile *
some_magic = 0xbaadd00d). If so, even though some_magic was declared
volatile, the compiler may have been able to prove that eliding it
could have no visible effect on this or any other program and so could
elide it under the as-if rule. Just guessing here, though.
Herb
---
Herb Sutter (herbsutter.wordpress.com)
(www.gotw.ca)
Convener, ISO/IEC JTC1/SC22/WG21 (C++) (www.gotw.ca/iso)
Visual C++ architect, Microsoft (www.gotw.ca/microsoft)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]