我正在查看 gcc 为原子操作生成的一些程序集。我尝试了以下简短的序列:
int x1;
int x2;
int foo;
void test()
{
__atomic_store_n( &x1, 1, __ATOMIC_SEQ_CST );
if( __atomic_load_n( &x2 ,__ATOMIC_SEQ_CST ))
return;
foo = 4;
}
看看 Herb Sutter 关于代码生成的原子武器演讲,他提到 X86 手册要求使用xchg
对于原子商店和一个简单的mov
用于原子读取。所以我期待一些类似的事情:
test():
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $1, %eax
xchg %eax, x1(%rip)
movl x2(%rip), %eax
testl %eax, %eax
setne %al
testb %al, %al
je .L2
jmp .L1
.L2:
movl $4, foo(%rip)
.L1:
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
由于锁定,内存栅栏是隐式的xchg
操作说明。
但是如果我使用编译它gcc -march=core2 -S test.cc
我得到以下信息:
test():
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $1, %eax
movl %eax, x1(%rip)
mfence
movl x2(%rip), %eax
testl %eax, %eax
setne %al
testb %al, %al
je .L2
jmp .L1
.L2:
movl $4, foo(%rip)
.L1:
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
所以不要使用xchg
操作 gcc 这里使用mov + mfence
组合。这种代码生成与 Herb Sutter 所说的 x86 架构所要求的不同的原因是什么?