【发布时间】:2019-10-07 13:40:17
【问题描述】:
最近我一直在浏览 Go 的源代码,尤其是 runtime/internal/atomic/asm_386.s。
下面是一个internal.atomic.Store64 函数的实现。
// void runtime∕internal∕atomic·Store64(uint64 volatile* addr, uint64 v);
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
MOVL 0, AX // crash with nil ptr deref
// MOVQ and EMMS were introduced on the Pentium MMX.
MOVQ val+4(FP), M0
MOVQ M0, (AX)
EMMS
// This is essentially a no-op, but it provides required memory fencing.
// It can be replaced with MFENCE, but MFENCE was introduced only on the Pentium4 (SSE2).
XORL AX, AX
LOCK
XADDL AX, (SP)
RET
问题与函数中的第二条评论有关。有人能解释一下XORL AX, AX 是如何作为记忆栅栏工作的吗?
我想这与紧随其后的LOCK 有关,但它是如何工作的?
谢谢。
【问题讨论】:
-
这很愚蠢,普通人使用
lock addl $0, (SP)作为 MFENCE 的(有时更快)等价物。另一个效率低下是使用testl而不是testb来检查EAX 的低位:没有test r32, imm8编码所以它浪费了几个字节的代码大小。 -
另外,如果我需要避免 SSE2,我会使用
fild/fistp而不是需要 MMX EMMS。或 SSE1 movlps 加载/存储到 xmm0,尽管与 SSE2movq或movsd加载到 xmm0 相比,它具有错误的依赖性。而且我会在ret之后放置崩溃时未对齐负载,因此在正常情况下不会采用分支。
标签: multithreading go assembly parallel-processing x86