Following is some code to flash LED's on a Pandaboard when running the Barrelfish operating system. My question is that why don't the LED's flash if the 'volatile' keyword is removed from the definitions of gpio_oe
and gpio_dataout
.
static volatile uint32_t *gpio_oe = (uint32_t *)(GPIO_BASE + 0x0134);
static volatile uint32_t *gpio_dataout = (uint32_t *)(GPIO_BASE + 0x013C);
void led_flash
{
// Enable output
*gpio_oe &= (~(1 << 8));
// Toggle LED on and off till eternity
while(true)
{
*gpio_dataout ^= (1 << 8); // Set means LED on; Clear means LED off
time_delay(); // To give blinking effect
}
}
I know that volatile needs to be used if the value of a variable can change spontaneously through a source outside the program. But I can't see such a case here. What optimization does the compiler perform that renders the whole while loop for flashing LED's meaningless? And what is the logic behind such optimization, ie. a legit case where such an optimization would make sense?
Effect of the volatile keyword on compiler optimizationIf you do not use the volatile keyword where it is needed, then the compiler might optimize accesses to the variable and generate unintended code or remove intended functionality.
The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. Objects declared as volatile are omitted from optimization because their values can be changed by code outside the scope of current code at any time.
C's volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time--without any action being taken by the code the compiler finds nearby.
For Java, “volatile” tells the compiler that the value of a variable must never be cached as its value may change outside of the scope of the program itself.
You also need volatile
to force a memory write and order in which generated code would access volatile
variables. With regular variables the compiler may decide that the writes are unnecessary and either throw them away or only keep the last one.
Moved from the comments: The compiler may write nothing at all if it sees no reads of the variable, it may even remove the variable.
As far as the compiler can tell, the values *gpio_oe
and *gpio_dataout
are written but never read. For normal data memory such an access pattern is entirely redundant so can be optimised out. Similarly for locations that are read but never written.
For memory mapped I/O however access to the "memory" location has side effects that the compiler is not aware of. Declaring the location volatile
tells the compiler that the location must be explicitly accessed exactly as described by the code.
As well as memory mapped I/O, a similar issue occurs with memory shared between separate threads (RTOS tasks or interrupt handlers for example) since the language is similarly unaware of these contexts.
Embedded.com covers the subject in a number of articles:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With