As for "first" - y
must be accessed, when z
is initialized, but I don't think the result of that access has to be used to calculate z
, if the implementation somehow knows that it must be 2. For this program there are (I think) only 2 ways it can have any other value:
- it's modified by a debugger or other interference with the program.
- the loader places volatile globals in some region of memory that doesn't behave like normal memory on your hardware. (in this case that would be very odd implementation-defined behavior indeed, to the point I don't think it's legal for the code as written, but it's relevant if the program, or some part of the build process outside the program, can somehow control where the object ends up).
Both of those are things that the implementation can rule out - in the second case by knowing how the loader behaves, in the first place by placing limitations on what you can hope to achieve with a debugger ("writing volatile variables results in surprising behavior"). Disappointing for the user of the debugger, but the standard doesn't constrain how debuggers work, or what memory "actually" contains, it just constrains what valid C++ implementations and programs do, and what C++ "sees".
In practice you'd think the compiler wouldn't bother treating a volatile object as subject to optimisations. It's a non-const object, and you've got to suspect that the only reason for defining a non-const volatile object is because it's going to change in ways the compiler doesn't expect[*]. You'd hope it will just read y
and do the division, but I reckon a case could be made for optimisation being legal.
As for "second" - in the case of your program, the compiler can initialize d
with a pre-computed value under the "as-if" rule, provided it knows what value division produces. For that matter in your program it can remove d
entirely.
"Provided it knows what value division produces" depends on the implementation - if it supports changes to IEEE rounding modes or equivalent, and if it doesn't know what mode should be in force, then in general it doesn't know in advance the result of even simple arithmetic.
The "as-if" rule covers, say, 85% of compiler optimisations. It's covered in section 1.9 of the standard, which is worth a look. I agree that the document as a whole is pretty intimidating, and the language it uses is sometimes impenetrable, but you have to start somewhere, so start with whatever you're currently interested in ;-)
[*] Specifically, and this is not something that's addressed in the C++03 standard in any way, some compilers (Microsoft) involve volatile
in their definition of threading semantics.