【发布时间】:2021-09-17 03:22:26
【问题描述】:
我wrote this简单的C++代码,看看原子变量是怎么实现的。
#include <atomic>
using namespace std;
atomic<float> f(0);
int main() {
f += 1.0;
}
它正在为 -O3 中的 main 生成此程序集:
main:
mov eax, DWORD PTR f[rip]
movss xmm1, DWORD PTR .LC1[rip]
movd xmm0, eax
mov DWORD PTR [rsp-4], eax ; this line is redundant
addss xmm0, xmm1
.L2:
mov eax, DWORD PTR [rsp-4] ; this line is redundant
movd edx, xmm0
lock cmpxchg DWORD PTR f[rip], edx
je .L5
mov DWORD PTR [rsp-4], eax ; this line is redundant
movss xmm0, DWORD PTR [rsp-4] ; this line can become movd xmm0, eax
addss xmm0, xmm1
jmp .L2
.L5:
xor eax, eax
ret
f:
.zero 4
.LC1:
.long 1065353216
它是使用原子比较和交换技术来实现原子性。但是在那里,旧值存储在 [rsp-4] 的堆栈中。但是在上面的代码中,eax 是不变的。因此,旧值保留在 eax 本身中。为什么编译器为旧值分配额外的空间?即使在-O3!是否有任何特定原因将该变量存储在堆栈中而不是寄存器中?
编辑:逻辑推论-
有 4 行使用rsp-4 -
mov DWORD PTR [rsp-4], eax --- 1
mov eax, DWORD PTR [rsp-4] --- 2 <--.
mov DWORD PTR [rsp-4], eax --- 3 | loop
movss xmm0, DWORD PTR [rsp-4] --- 4 ---'
第 3 行和第 4 行之间绝对没有其他内容,因此可以使用 3 将第 4 行重写为movd xmm0, eax。
现在,当在循环中从第 3 行转到第 2 行时,rsp-4(也没有eax)没有任何修改。所以这意味着第 3 行和第 2 行依次折叠到mov eax, eax
这本质上是多余的。
最后,只剩下第 1 行了,它的目的地不再被使用。所以也是多余的。
【问题讨论】:
-
@Yksisarvinen 是的,这很简单。看到之后,我搬到了花车上;)
-
@SouravKannanthaB 他们回应了我的一个有点误导性的评论,想知道这是否与浮动没有原子加法有关。
-
clang 的代码更合理:godbolt.org/z/qeGK8KzW4。这看起来像是一个简单的错过优化错误,您可以报告它。
标签: c++ assembly gcc x86-64 atomic