我有以下代码:
static _Atomic float testf;
void func() {
testf=1.0f;
float f=testf;
printf("%f\n", f);
}
运行它会导致程序在 vcruntime_c11_atomic_support.h:417 处命中调试断言、内存顺序无效。 (MSVC 版本 19.37.32822.0)。
我不太熟悉 x64 调用约定,但看起来生成的程序集没有正确调用 _Atomic_store32 或 _Atomic_load32 之一:
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
MSVC 原子支持是否有问题,或者我做错了什么?
该 asm 输出看起来像是编译器错误。
就像编译器想要调用
_Atomic_store32(void*, float)
一样,因为它在 XMM1 中传递第二个参数。但这与它用于整数的函数相同,我认为是的,实际的 arg 需要位于 EDX 中。将其视为可变参数函数将适用于 Win x64 调用约定,因为这些函数需要将 XMM 参数复制到相应的整数寄存器。
对于加载,
movss xmm1, DWORD PTR __real@40a00000
正在将具有位模式0x40a00000
的浮点常量加载到第二个参数传递寄存器(对于FP参数)。该位模式代表 5.0f
,因此 MSVC 对某些事情感到非常困惑,对这些参数类型执行 _Atomic_load32(&testf, (float)memory_order_seq_cst)
。
发出这样的代码绝对是编译器错误的迹象。 (构建一个最小的测试用例并显示相关的汇编,这真是太好了。您可以将这个确切的示例提交给 MS 的编译器团队,他们很快就会看到错误的症状。)