How do I prevent an optimizing compiler from disrupting interrupt free critical sections?
===

I have some C macros that disable and enable interrupts so that I can define critical sections of code.  I want to ensure that the optimizer complies with the operations and does not move them or remove them.  

    #define ARM_INT_KEY_TYPE         unsigned int
    #define ARM_INT_LOCK(key_)   ({ \
        asm("MRS %0,cpsr" : "=r" (key_)); \
        asm("MSR cpsr_c,#(0x1F | 0x80 | 0x40)"); \
    })
    #define ARM_INT_UNLOCK(key_) asm("MSR cpsr_c,%0" : : "r" (key_))

The usage is as follows:

    int init_i2c(p_device_i2c dev){
    
    // Interrupts are enabled
    doSomething();
    
    ARM_INT_KEY_TYPE key;
    ARM_INT_LOCK(key);

    // Interrupts are disabled
    pMX27_GPIO i2c_clk = (pMX27_GPIO)(GPIO_BASE_ADDR | I2C_CLK_PORT);
    pMX27_GPIO i2c_sda = (pMX27_GPIO)(GPIO_BASE_ADDR | I2C_DATA_PORT);

    i2c_clk->GIUS	&= ~(1 << I2C_CLK_PIN); 		// I2C Signals
    i2c_sda->GIUS 	&= ~(1 << I2C_DATA_PIN); 		// I2C Signals

    ARM_INT_UNLOCK(key);
    // Interrupts ON again

    // Wait for stable
    ARM_delay_clocks(5000);
    
    i2c_stop(dev);

The code works as expected with optimization turned off but I suspect that there may be problems with optimization turned ON.  

Will adding volatile to the asm statements do the trick?

    #define ARM_INT_UNLOCK(key_) asm volatile ("MSR cpsr_c,%0" : : "r" (key_))