Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

volatile and double confusion

int x = 2;
volatile int y = 2;

const int z = x/y;

int main(){
    int x = 2 + 3;

    double d = 7 / 3;
}

I have three questions here:

Firstly, can the compiler calculate the value of the 'z' at compile time to be 1 in this case?

Secondly, I observed that the compiler does not generate assembly instructions for adding 2 and 3 to initialize x. It directly initializes x with 5. Can the same be done with 'd'?

Thirdly, Is there any good book to read on these two concepts? Any quotes from the Standard would be helpful (The standard document seems to be an interesting place though very scary)

like image 885
Nivhus Avatar asked Oct 02 '10 13:10

Nivhus


2 Answers

Firstly, can the compiler calculate the value of the 'z' at compile time to be 1 in this case?

No. reading or writing to volatile variables considered having side effects, so the compiler is not allowed to do this.

Secondly, I observed that the compiler does not generate assembly instructions for adding 2 and 3 to initialize x. It directly initializes x with 5. Can the same be done with 'd'?

Yes. As long as the compiler can prove that there are no side effect. E.g. if overflow or a divide by zero happens during the computation, it can't compute it at compile time since the computation should trigger a CPU exception at runtime.

Thirdly, Is there any good book to read on these two concepts?

Yes. C++ ISO standard describes exactly what you're asking. Books are good to learn the basics or the theory. It makes no sense writing books that rephrase all the technical details described in the standard.

like image 96
Yakov Galka Avatar answered Sep 29 '22 06:09

Yakov Galka


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:

  1. it's modified by a debugger or other interference with the program.
  2. 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.

like image 37
Steve Jessop Avatar answered Sep 29 '22 06:09

Steve Jessop