Search code examples
cvisual-c++c11stdatomiccompiler-bug

MSVC compiled code hits debug assert when using _Atomic float


I have the following code:

static _Atomic float testf;
void func() {
   testf=1.0f;
   float f=testf;
   printf("%f\n", f);
}

Running it causes the program to hit a Debug Assert, Invalid memory order, at vcruntime_c11_atomic_support.h:417. (MSVC version 19.37.32822.0).

I'm not that familiar with x64 calling conventions, but it looks like the generated assembly isn't calling either one of _Atomic_store32 or _Atomic_load32 correctly:

inline void _Atomic_store32(volatile int* _Ptr, int _Desired, int _Order);
inline int _Atomic_load32(const volatile int* _Ptr, int _Order);
; 41   :     testf=1.0f;

    mov r8d, 5    ; !!This seems to be _Order, corresponding to _Atomic_memory_order_seq_cst
    movss   xmm1, DWORD PTR __real@3f800000
    lea rcx, OFFSET FLAT:testf
    call    _Atomic_store32   ; !!Where is EDX? That should contain _Desired.

; 42   :     float f=testf;

    movss   xmm1, DWORD PTR __real@40a00000
    lea rcx, OFFSET FLAT:testf
    call    _Atomic_load32    ; !!EDX should have _Order.
    movss   DWORD PTR f$[rsp], xmm0

Is MSVC atomic support bugged, or am I doing something wrong?


Solution

  • Looks like a compiler bug from that asm output.

    It's like the compiler wants to call _Atomic_store32(void*, float) since it's passing the second arg in XMM1. But that's the same function it uses for integers, I assume, so yeah the actual arg needs to be in EDX. Treating it like a variadic function would work for the Win x64 calling convention, since those functions need XMM args to be copied to the corresponding integer reg.

    For the load, movss xmm1, DWORD PTR __real@40a00000 is loading a float constant with bit-pattern 0x40a00000 into the second arg-passing register (for FP args). That bit-pattern represents 5.0f, so MSVC has got itself very confused about something, doing _Atomic_load32(&testf, (float)memory_order_seq_cst) with those arg types.

    Emitting code like that is definitely a sign of a compiler bug. (And nice job constructing a minimal test-case and showing the relevant asm. You could submit this exact example to MS's compiler team and they'd very quickly see the symptoms of something being wrong.)