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?
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@40a00000is loading a float constant with bit-pattern0x40a00000into the second arg-passing register (for FP args). That bit-pattern represents5.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.)