Is there a way to tell GCC not to reorder any instructions, not just load/stores? : <p>I'm working on the irq_lock() / irq_unlock() implementation for an RTOS and found an issue. We want to absolutely minimize how much time the CPU spends with interrupts locked. Right now, our irq_lock() inline function for x86 uses "memory" clobber:</p>

<pre><code>static ALWAYS_INLINE unsigned int _do_irq_lock(void)
{
    unsigned int key;

    __asm__ volatile (
        "pushfl;\n\t"
        "cli;\n\t"
        "popl %0;\n\t"
        : "=g" (key)
        :
        : "memory"
        );

    return key;
}
</code></pre>

<p>The problem is that the compiler will still reorder potentially expensive operations into the critical section if they just touch registers and not memory. A specific example is here in our kernel's sleep function:</p>

<pre><code>void k_sleep(int32_t duration)
{
    __ASSERT(!_is_in_isr(), "");
    __ASSERT(duration != K_FOREVER, "");

    K_DEBUG("thread %p for %d ns\n", _current, duration);

    /* wait of 0 ns is treated as a 'yield' */
    if (duration == 0) {
        k_yield();
        return;
    }

    int32_t ticks = _TICK_ALIGN + _ms_to_ticks(duration);
    int key = irq_lock();

    _remove_thread_from_ready_q(_current);
    _add_thread_timeout(_current, NULL, ticks);

    _Swap(key);
}
</code></pre>

<p>The 'ticks' calculation, which does expensive math, gets reordered inside where we lock interrupts, so we are calling __divdi3 with interrupts locked which is <em>not</em> what we want:</p>

<pre><code>Dump of assembler code for function k_sleep:
   0x0010197a &lt;+0&gt;: push   %ebp
   0x0010197b &lt;+1&gt;: mov    %esp,%ebp
   0x0010197d &lt;+3&gt;: push   %edi
   0x0010197e &lt;+4&gt;: push   %esi
   0x0010197f &lt;+5&gt;: push   %ebx
   0x00101980 &lt;+6&gt;: mov    0x8(%ebp),%edi
   0x00101983 &lt;+9&gt;: test   %edi,%edi
   0x00101985 &lt;+11&gt;:    jne    0x101993 &lt;k_sleep+25&gt;
   0x00101987 &lt;+13&gt;:    lea    -0xc(%ebp),%esp
   0x0010198a &lt;+16&gt;:    pop    %ebx
   0x0010198b &lt;+17&gt;:    pop    %esi
   0x0010198c &lt;+18&gt;:    pop    %edi
   0x0010198d &lt;+19&gt;:    pop    %ebp
   0x0010198e &lt;+20&gt;:    jmp    0x101944 &lt;k_yield&gt;
   0x00101993 &lt;+25&gt;:    pushf  
   0x00101994 &lt;+26&gt;:    cli    
   0x00101995 &lt;+27&gt;:    pop    %esi
   0x00101996 &lt;+28&gt;:    pushl  0x104608
   0x0010199c &lt;+34&gt;:    call   0x101726 &lt;_remove_thread_from_ready_q&gt;
   0x001019a1 &lt;+39&gt;:    mov    $0x64,%eax
   0x001019a6 &lt;+44&gt;:    imul   %edi
   0x001019a8 &lt;+46&gt;:    mov    0x104608,%ebx
   0x001019ae &lt;+52&gt;:    add    $0x3e7,%eax
   0x001019b3 &lt;+57&gt;:    adc    $0x0,%edx
   0x001019b6 &lt;+60&gt;:    mov    %ebx,0x20(%ebx)
   0x001019b9 &lt;+63&gt;:    movl   $0x0,(%esp)
   0x001019c0 &lt;+70&gt;:    push   $0x3e8
   0x001019c5 &lt;+75&gt;:    push   %edx
   0x001019c6 &lt;+76&gt;:    push   %eax
   0x001019c7 &lt;+77&gt;:    call   0x1000a0 &lt;__divdi3&gt;
   0x001019cc &lt;+82&gt;:    add    $0x10,%esp
   0x001019cf &lt;+85&gt;:    inc    %eax
   0x001019d0 &lt;+86&gt;:    mov    %eax,0x28(%ebx)
   0x001019d3 &lt;+89&gt;:    movl   $0x0,0x24(%ebx)
   0x001019da &lt;+96&gt;:    lea    0x18(%ebx),%edx
   0x001019dd &lt;+99&gt;:    mov    $0x10460c,%eax
   0x001019e2 &lt;+104&gt;:   add    $0x28,%ebx
   0x001019e5 &lt;+107&gt;:   mov    $0x10162b,%ecx
   0x001019ea &lt;+112&gt;:   push   %ebx
   0x001019eb &lt;+113&gt;:   call   0x101667 &lt;sys_dlist_insert_at&gt;
   0x001019f0 &lt;+118&gt;:   mov    %esi,0x8(%ebp)
   0x001019f3 &lt;+121&gt;:   pop    %eax
   0x001019f4 &lt;+122&gt;:   lea    -0xc(%ebp),%esp
   0x001019f7 &lt;+125&gt;:   pop    %ebx
   0x001019f8 &lt;+126&gt;:   pop    %esi
   0x001019f9 &lt;+127&gt;:   pop    %edi
   0x001019fa &lt;+128&gt;:   pop    %ebp
   0x001019fb &lt;+129&gt;:   jmp    0x100f77 &lt;_Swap&gt;
End of assembler dump.
</code></pre>

<p>We discovered that we can get the ordering we want by declaring 'ticks' volatile:</p>

<pre><code>Dump of assembler code for function k_sleep:
   0x0010197a &lt;+0&gt;: push   %ebp
   0x0010197b &lt;+1&gt;: mov    %esp,%ebp
   0x0010197d &lt;+3&gt;: push   %ebx
   0x0010197e &lt;+4&gt;: push   %edx
   0x0010197f &lt;+5&gt;: mov    0x8(%ebp),%edx
   0x00101982 &lt;+8&gt;: test   %edx,%edx
   0x00101984 &lt;+10&gt;:    jne    0x10198d &lt;k_sleep+19&gt;
   0x00101986 &lt;+12&gt;:    call   0x101944 &lt;k_yield&gt;
   0x0010198b &lt;+17&gt;:    jmp    0x1019f5 &lt;k_sleep+123&gt;
   0x0010198d &lt;+19&gt;:    mov    $0x64,%eax
   0x00101992 &lt;+24&gt;:    push   $0x0
   0x00101994 &lt;+26&gt;:    imul   %edx
   0x00101996 &lt;+28&gt;:    add    $0x3e7,%eax
   0x0010199b &lt;+33&gt;:    push   $0x3e8
   0x001019a0 &lt;+38&gt;:    adc    $0x0,%edx
   0x001019a3 &lt;+41&gt;:    push   %edx
   0x001019a4 &lt;+42&gt;:    push   %eax
   0x001019a5 &lt;+43&gt;:    call   0x1000a0 &lt;__divdi3&gt;
   0x001019aa &lt;+48&gt;:    add    $0x10,%esp
   0x001019ad &lt;+51&gt;:    inc    %eax
   0x001019ae &lt;+52&gt;:    mov    %eax,-0x8(%ebp)
   0x001019b1 &lt;+55&gt;:    pushf  
   0x001019b2 &lt;+56&gt;:    cli    
   0x001019b3 &lt;+57&gt;:    pop    %ebx
   0x001019b4 &lt;+58&gt;:    pushl  0x1045e8
   0x001019ba &lt;+64&gt;:    call   0x101726 &lt;_remove_thread_from_ready_q&gt;
   0x001019bf &lt;+69&gt;:    mov    0x1045e8,%eax
   0x001019c4 &lt;+74&gt;:    mov    -0x8(%ebp),%edx
   0x001019c7 &lt;+77&gt;:    movl   $0x0,0x24(%eax)
   0x001019ce &lt;+84&gt;:    mov    %edx,0x28(%eax)
   0x001019d1 &lt;+87&gt;:    mov    %eax,0x20(%eax)
   0x001019d4 &lt;+90&gt;:    lea    0x18(%eax),%edx
   0x001019d7 &lt;+93&gt;:    add    $0x28,%eax
   0x001019da &lt;+96&gt;:    mov    %eax,(%esp)
   0x001019dd &lt;+99&gt;:    mov    $0x10162b,%ecx
   0x001019e2 &lt;+104&gt;:   mov    $0x1045ec,%eax
   0x001019e7 &lt;+109&gt;:   call   0x101667 &lt;sys_dlist_insert_at&gt;
   0x001019ec &lt;+114&gt;:   mov    %ebx,(%esp)
   0x001019ef &lt;+117&gt;:   call   0x100f77 &lt;_Swap&gt;
   0x001019f4 &lt;+122&gt;:   pop    %eax
   0x001019f5 &lt;+123&gt;:   mov    -0x4(%ebp),%ebx
   0x001019f8 &lt;+126&gt;:   leave  
   0x001019f9 &lt;+127&gt;:   ret    
End of assembler dump.
</code></pre>

<p>However this just fixes it in one spot. We really need a way to modify the irq_lock() implementation such that it does the right thing everywhere, and right now the "memory" clobber is not sufficient.</p>
