为什么 MSVC 为 x64 上的原子加载生成 nop 指令?

Meh*_*dad 8 c++ x86-64 atomic visual-c++ no-op

如果您编译如下代码

#include <atomic>

int load(std::atomic<int> *p) {
    return p->load(std::memory_order_acquire) + p->load(std::memory_order_acquire);
}
Run Code Online (Sandbox Code Playgroud)

您会看到MSVC在每次内存加载后都会生成 NOP 填充:

int load(std::atomic<int> *) PROC
        mov     edx, DWORD PTR [rcx]
        npad    1
        mov     eax, DWORD PTR [rcx]
        npad    1
        add     eax, edx
        ret     0
Run Code Online (Sandbox Code Playgroud)

为什么是这样?有什么办法可以避免它而不放松内存顺序(这会影响代码的正确性)?

Art*_*yer 9

p->load()最终可能会使用_ReadWriteBarrier编译器内部函数。

\n

据此: https: //developercommunity.visualstudio.com/t/-readwritebarrier-intrinsic-eits-unnecessary-code/1538997

\n
\n

nops 被插入是因为现在默认情况下启用了/volatileMetadata 标志。您可以通过添加 /volatileMetadata- 返回到旧的行为,但如果您的代码曾经被模拟运行,这样做会导致性能更差。它\xe2\x80\x99仍将被正确模拟,但模拟器将不得不悲观地假设每个加载/存储都需要一个屏障。

\n
\n

编译/volatileMetadata-确实删除了npad.

\n