On 17/10/17 14:06, Andrew Haley wrote: > On 17/10/17 13:03, David Brown wrote: >> It would be marvellous to be able to mark a statement, block, function, >> function call, etc., as "volatile", meaning "do not re-order with >> respect to other volatile statements, memory accesses or volatile asm >> statements". > > You can achieve that with memory clobbers. > No, you can't - not always. Memory clobbers enforce an ordering on data that is stored in memory or loaded from memory. They don't affect data in registers, and they don't affect code execution and calculations. And memory clobbers are expensive on many targets, as are alternatives like making extra volatile variables. A well-known example is here: <http://www.nongnu.org/avr-libc/user-manual/optimization.html> The key code is this: #define cli() __asm volatile( "cli" ::: "memory" ) #define sei() __asm volatile( "sei" ::: "memory" ) unsigned int ivar; void test2( unsigned int val ) { val = 65535U / val; cli(); ivar = val; sei(); } On the AVR, division is an expensive operation handled by a library call. gcc sees it as a simple arithmetic operation, and does the (perfectly valid) re-arrangement to: __asm volatile( "cli" ::: "memory" ) ivar = 65535U / val; __asm volatile( "sei" ::: "memory" ) The memory clobbers are there, but they don't stop the code movement - the slow division library call is done inside the critical region. What does help here is the addition of an artificial dependency: #define cli() __asm volatile( "cli" ::: "memory" ) #define sei() __asm volatile( "sei" ::: "memory" ) unsigned int ivar; void test2( unsigned int val ) { val = 65535U / val; asm("" :: "" (val)); cli(); ivar = val; sei(); } This gives the optimal and desired code (val is calculated before cli). If there were a way to make a statement "volatile" and restrict its movement, that could be used instead. For example: #define cli() __asm volatile( "cli" ::: "memory" ) #define sei() __asm volatile( "sei" ::: "memory" ) unsigned int ivar; void test2( unsigned int val ) { (volatile void) (val = 65535U / val); cli(); ivar = val; sei(); } Casting the expression to void does nothing to it, but casting to volatile void could be a reasonable way to tell the compiler that it should do this statement /here/ (with respect to other volatiles), and then ignore the result. The syntax is legal in C at the moment (and has no effect in gcc), which would be good for compatibility. I suspect the idea would be difficult to implement, however, since it would mean tracking multiple levels of "volatileness" - code within the volatile statement could be reordered amongst itself, but not outside the boundaries of the volatile statement, and there could be volatile variable accesses within the volatile statement. There could even be sub-statements that are volatile themselves. Yes, it would be complicated :-(