User: Password:
|
|
Subscribe / Log in / New account

The trouble with volatile

The trouble with volatile

Posted May 10, 2007 22:04 UTC (Thu) by ncm (subscriber, #165)
Parent article: The trouble with volatile

People who think they want something volatile should know that assigning to a volatile variable, or through a pointer to volatile, generates a store instruction followed by a load instruction. The load is normally optimized away, but the language definition says it's there (because an assignment has a value), and you said you didn't want optimization. Sometimes the extra load just slows things down, but if the address is really a register, it may be actively wrong.


(Log in to post comments)

The trouble with volatile

Posted May 11, 2007 5:54 UTC (Fri) by jzbiciak (subscriber, #5246) [Link]

Huh? That makes no sense. The *assignment statement* has a value, sure, and that's the value referenced in any outer context. For example:

volatile int   a;
volatile short b;
volatile int   c;

a = b = c;

This code will read 'c' cast it to the type of 'b', and then write it to 'b'. That whole expression, 'b = c', takes on the same value as was written to 'b'. That value gets written to 'a'. You aren't reading 'b' and assigning it to 'a', you're assigning the value of the expression 'b = c', plain and simple. That makes sense. Let's suppose 'b' gets modified by an interrupt handler, and the interrupt happens right after the write to 'b'. The code will always write the same value to 'a' regardless of whether 'b' even takes on the value written to it.

Now, on a compiler that doesn't do register allocation, or for which that's disabled, the value of the expression 'b = c' might get written to a compiler temporary in memory, and the compiler issues writes and reads for that location. I assert it's actually incorrect to read 'b' and write it to 'a' when writing 'a = b = c'.

If all assignments had a hidden read behind them, then Duff's Device probably would never have worked. The motivation for Duff's Device was fast writes through a volatile pointer to a hardware FIFO.

Now, C++ on the other hand... they allow assignments to be lvalues, which causes all sorts of wackiness. And so C++ apparently does behave somewhat as you describe, at least in the 'a = b = c' case. (An assignment in isolation still doesn't have a phantom read.) It bolsters my argument above that they consider this a deviation from how C behaves. Take a peek here.

At any rate, since we're talking about the Linux kernel, we're talking C, not C++.

The trouble with volatile

Posted May 11, 2007 6:45 UTC (Fri) by jzbiciak (subscriber, #5246) [Link]

Hmmm...

I did some playing around, and it appears different compilers treat the a = b = c case rather differently than I expected. Some *do* in fact read 'b' after writing it (which just seems crazy to me).

I've asked our compiler optimizer lead developer at work his take on this topic.

In the meantime, allow me to throw a mea culpa out there and then I'll shut up. :-)

The trouble with volatile

Posted May 15, 2007 9:15 UTC (Tue) by IkeTo (subscriber, #2122) [Link]

I think the original response says the following simpler code will cause a store plus load:
volatile int a;
void f() {
        a = 2;
}
The argument is that "a = 2" has a value which requires a load to find, and the compiler is forbidden from optimizing out that load. I don't think the code generated by my 4.1.1 gcc reflects this, however:
        movl    $2, a
        ret
So perhaps the OP is speaking from a rather old experience or a different compiler.

The trouble with volatile

Posted May 15, 2007 12:20 UTC (Tue) by jzbiciak (subscriber, #5246) [Link]

I spoke to the compiler optimizer lead at work. He assures me that assignment ONLY implies a write, even if the value of the assignment expression is used in a subsequent expression.

At least as far as he's concerned, "a = 2" should only compile to a write, and "a = b = 2" should compile to two writes. "a = b = c" should compile to one read (reading 'c'), and two writes (to 'a' and 'b').

That said, our compiler actually compiled "a = b = c" more like "b = c; a = c" (reading 'c' twice), which he indicated was a bug. GCC seems to compile "a = b = c" more like "b = c; a = b", which is actually pretty close to what the OP was suggesting would happen. (Read 'c', Write 'b'. Read 'b', write 'a'.) Fun stuff.

So... a secondary lesson is, "However YOU might have interpreted the C specification, chances are your compiler treats it differently for anything other than the simplest of expressions."


Copyright © 2018, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds