"volatile" is really insufficient to work with modern memory systems. Is there total ordering, or is it another episode of Bus Master Wild West? Are writes combined? Do reads bypass the write queue, stall, or dig out as-yet-uncommitted values? How sensitive is the hardware to "harmless" extra reads or writes? Let's not forget cache protocols, and what happens to in-flight operations on a fault (sometimes partially executed instructions have to be "finished-up" by fault handlers, whose memory operations can be different in emulation from the actual native instructions).
volatile is a weak tool in the face of all the stuff that hardware folks do to achieve performance or cost goals. Most of the platforms I've worked with use abstraction layers that bottom-out in compiler intrinsics or assembly language. I'm deeply suspicious when I see code using bare volatile declarations, as the code is often wrong.