Я смотрю на сборку, сгенерированную для атомных операций 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
. В чем причина этого генерации кода, которая отличается от той, которая предусмотрена архитектурой x86 в соответствии с Herb Sutter?