Differences in custom and std fetch_add on floats

Viewed 88

This is an attempt at implementing fetch_add on floats without C++20.

void fetch_add(volatile float* x, float y)
{
    bool success = false;
    auto xi = (volatile std::int32_t*)x;
    while(!success)
    {
        union {
            std::int32_t sumint;
            float sum;
        };
        auto tmp = __atomic_load_n(xi, __ATOMIC_RELAXED);
        sumint = tmp;
        sum += y;
        success = __atomic_compare_exchange_n(xi, &tmp, sumint, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
    }
}

To my great confusion, when I compare the assembly from gcc10.1 -O2 -std=c++2a for x86-64, they differ.

fetch_add(float volatile*, float):
.L2:
        mov     eax, DWORD PTR [rdi]
        movd    xmm1, eax
        addss   xmm1, xmm0
        movd    edx, xmm1
        lock cmpxchg    DWORD PTR [rdi], edx
        jne     .L2
        ret
fetch_add_std(std::atomic<float>&, float):
        mov     eax, DWORD PTR [rdi]
        movaps  xmm1, xmm0
        movd    xmm0, eax
        mov     DWORD PTR [rsp-4], eax
        addss   xmm0, xmm1
.L9:
        mov     eax, DWORD PTR [rsp-4]
        movd    edx, xmm0
        lock cmpxchg    DWORD PTR [rdi], edx
        je      .L6
        mov     DWORD PTR [rsp-4], eax
        movss   xmm0, DWORD PTR [rsp-4]
        addss   xmm0, xmm1
        jmp     .L9
.L6:
        ret

My ability to read assembly is near non-existent, but the custom version looks correct to me, which implies it is either incorrect, inefficient or somehow the standard library is rather broken. I don't quite believe the third case, which leads me to ask, is the custom version incorrect or inefficient?


After some comments, a second version without reloading after cmpxchg is written. They do still differ.

0 Answers
Related