GCC inline assembler: какой вариант кода более корректный?

Я давно откладывал вопрос применения встроенного ассемблера в своих программах на GNU C++, но наконец решил, что пора. И вот, я имею два варианта написания функций для синхронизации потоков через атомарные флаги.

Первый вариант:

INLINE void AtomicFlagLock(UINT* pFlagsDword, UINT iBit)
{
    asm volatile (
        ".intel_syntax noprefix\n"
        "0:     lock bts    dword ptr %0, %1    \n"
        "       jc          0b                  \n"
        :
        :"m"(*pFlagsDword), "ri"(iBit)
    );
}

INLINE void AtomicFlagUnlock(UINT* pFlagsDword, UINT iBit)
{
    asm volatile (
        ".intel_syntax noprefix\n"
        "       lock btr    dword ptr %0, %1    \n"
        :
        :"m"(*pFlagsDword), "ri"(iBit)
    );
}

Второй вариант:

INLINE void AtomicFlagLock(UINT* pFlagsDword, UINT iBit)
{
    asm volatile (
        ".intel_syntax noprefix\n"
        "0:     lock bts    dword ptr %0, %1    \n"
        "       jc          0b                  \n"
        :"+m"(*pFlagsDword)
        :"ri"(iBit)
    );
}

INLINE void AtomicFlagUnlock(UINT* pFlagsDword, UINT iBit)
{
    asm volatile (
        ".intel_syntax noprefix\n"
        "       lock btr    dword ptr %0, %1    \n"
        :"+m"(*pFlagsDword)
        :"ri"(iBit)
    );
}

Собственно, мой вопрос: какой из этих вариантов более корректный? В тестовой программе код генерируется в обоих случаях одинаковый и верный. Однако, насколько мне удалось правильно постичь логику оператора asm() в GCC, второй вариант кода этих функций, где выражение *pFlagsDword объявляется в секции output с модификатором "+m", мне кажется более предпочтительным, так как в этом случае компилятору явно указывается, что значение *pFlagsDword в блоке asm() модифицируется, в то время как в первом варианте компилятор об этом не знает и в теории может что-то накуролесить с оптимизацией. Я прав, или не очень?

Так как тема новая для меня, мне будут полезны ваши ответы, советы и замечания по выше приведённому коду.

Вот тестовая программа:

#define INLINE __attribute__ ((always_inline)) inline
#define NOINLINE __attribute__ ((noinline))
typedef unsigned int UINT;


INLINE void AtomicFlagLock(UINT* pFlagsDword, UINT iBit)
{
    asm volatile (
        ".intel_syntax noprefix\n"
        "0:     lock bts    dword ptr %0, %1    \n"
        "       jc          0b                  \n"
        :"+m"(*pFlagsDword)
        :"ri"(iBit)
    );
}

INLINE void AtomicFlagUnlock(UINT* pFlagsDword, UINT iBit)
{
    asm volatile (
        ".intel_syntax noprefix\n"
        "       lock btr    dword ptr %0, %1    \n"
        :"+m"(*pFlagsDword)
        :"ri"(iBit)
    );
}


void lock_fl(UINT* pfl, UINT iBit);
void unlock_fl(UINT* pfl, UINT iBit);


int main()
{
    UINT fl = 0;

    AtomicFlagLock(&fl,2);
    lock_fl(&fl,3);

    AtomicFlagUnlock(&fl,3);
    unlock_fl(&fl,2);

    return 0;
}


NOINLINE void lock_fl(UINT* pfl, UINT iBit)
{
    AtomicFlagLock(pfl,iBit);
}

NOINLINE void unlock_fl(UINT* pfl, UINT iBit)
{
    AtomicFlagUnlock(pfl,iBit);
}

Вот згенерированный компилятором код (одинаковый для обоих вариантов):

.text:00403BB0 ; =============== S U B R O U T I N E =======================================
.text:00403BB0
.text:00403BB0 ; Attributes: bp-based frame
.text:00403BB0
.text:00403BB0 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00403BB0                 public _main
.text:00403BB0 _main           proc near               ; CODE XREF: sub_4011A0+91↑p
.text:00403BB0
.text:00403BB0 fl              = dword ptr -4
.text:00403BB0 argc            = dword ptr  8
.text:00403BB0 argv            = dword ptr  0Ch
.text:00403BB0 envp            = dword ptr  10h
.text:00403BB0
.text:00403BB0 ; __unwind {
.text:00403BB0                 push    ebp
.text:00403BB1                 mov     ebp, esp
.text:00403BB3                 and     esp, 0FFFFFFF0h
.text:00403BB6                 sub     esp, 20h
.text:00403BB9                 call    ___main
.text:00403BBE                 mov     [esp+20h+fl], 0
.text:00403BC6
.text:00403BC6 L0:                                     ; CODE XREF: _main+1D↓j
.text:00403BC6                 lock bts [esp+20h+fl], 2
.text:00403BCD                 jb      short L0
.text:00403BCF                 lea     ecx, [esp+20h+fl]
.text:00403BD3                 mov     dword ptr [esp+4], 3 ; iBit
.text:00403BDB                 mov     [esp], ecx      ; pfl
.text:00403BDE                 call    __Z7lock_flPjj  ; lock_fl(uint *,uint)
.text:00403BE3                 lock btr [esp+20h+fl], 3
.text:00403BEA                 mov     dword ptr [esp+4], 2 ; iBit
.text:00403BF2                 mov     [esp], ecx      ; pfl
.text:00403BF5                 call    __Z9unlock_flPjj ; unlock_fl(uint *,uint)
.text:00403BFA                 xor     eax, eax
.text:00403BFC                 leave
.text:00403BFD                 retn
.text:00403BFD ; } // starts at 403BB0
.text:00403BFD _main           endp

.text:00401410 ; =============== S U B R O U T I N E =======================================
.text:00401410
.text:00401410
.text:00401410 ; _DWORD __cdecl lock_fl(unsigned int *pfl, unsigned int iBit)
.text:00401410                 public __Z7lock_flPjj
.text:00401410 __Z7lock_flPjj  proc near               ; CODE XREF: _main+2E↓p
.text:00401410
.text:00401410 pfl             = dword ptr  4
.text:00401410 iBit            = dword ptr  8
.text:00401410
.text:00401410 ; __unwind {
.text:00401410                 mov     eax, [esp+pfl]
.text:00401414                 mov     edx, [esp+iBit]
.text:00401418
.text:00401418 loc_401418:                             ; CODE XREF: lock_fl(uint *,uint)+C↓j
.text:00401418                 lock bts [eax], edx
.text:0040141C                 jb      short loc_401418
.text:0040141E                 retn
.text:0040141E ; } // starts at 401410
.text:0040141E __Z7lock_flPjj  endp
.text:0040141E
.text:0040141E ; ---------------------------------------------------------------------------
.text:0040141F                 align 10h
.text:00401420
.text:00401420 ; =============== S U B R O U T I N E =======================================
.text:00401420
.text:00401420
.text:00401420 ; _DWORD __cdecl unlock_fl(unsigned int *pfl, unsigned int iBit)
.text:00401420                 public __Z9unlock_flPjj
.text:00401420 __Z9unlock_flPjj proc near              ; CODE XREF: _main+45↓p
.text:00401420
.text:00401420 pfl             = dword ptr  4
.text:00401420 iBit            = dword ptr  8
.text:00401420
.text:00401420 ; __unwind {
.text:00401420                 mov     eax, [esp+pfl]
.text:00401424                 mov     edx, [esp+iBit]
.text:00401428                 lock btr [eax], edx
.text:0040142C                 retn
.text:0040142C ; } // starts at 401420
.text:0040142C __Z9unlock_flPjj endp

Ответы (0 шт):