gpt4 book ai didi

assembly - 如何在 x86 ASM 中自动移动 64 位值?

转载 作者:行者123 更新时间:2023-12-02 19:14:13 26 4
gpt4 key购买 nike

首先,我发现了这个问题:How do I atomically read a value in x86 ASM?但它有点不同,在我的例子中,我想在 32 位应用程序中自动分配一个浮点(64 位 double )值。

来自:“英特尔® 64 和 IA-32 架构软件开发人员手册,第 3 卷 A”

The Pentium processor (and newer processors since) guarantees that the following additional memory operations will always be carried out atomically:

Reading or writing a quadword aligned on a 64-bit boundary

实际上可以使用一些组装技巧吗?

最佳答案

在 64 位 x86 asm 中,可以使用整数 mov rax, [rsi] 、或 x87 或 SSE2。 As long as the address is 8-byte aligned (or on Intel P6 and later CPUs: doesn't cross a cache-line boundary) the load or store will be atomic .

请注意,AMD 和 Intel 的共同基线仍然只是 8 字节对齐; 英特尔保证未对齐但不跨缓存线分割的可缓存负载的原子性。 (AMD 可能会保证更广泛的边界,或者至少在实践中为某些更高版本的 CPU 做到这一点)。

<小时/>

在 32 位 x86 asm 中,仅使用整数寄存器的唯一选择是 lock cmpxchg8b ,但这对于纯负载或纯存储来说很糟糕。 (您可以通过设置 Expected=desired = 0 将其用作负载,但只读内存除外)。 (gcc/clang 在 64 位模式下使用 lock cmpxchg16b 代替 atomic<struct_16_bytes>,但有些编译器只是选择使 16 字节对象不无锁。)

所以答案是:不要使用整数寄存器:fild qword/fistp qword可以复制任何位模式而不改变它。 (只要x87精度控制设置为全64位尾数)。对于 Pentium 及更高版本上的对齐地址来说,这是原子的。

在现代 x86 上,使用 SSE2 movq加载或存储。例如

; atomically store edx:eax to qword [edi], assuming [edi] is 8-byte aligned
movd xmm0, eax
pinsrd xmm0, edx ; SSE4.1
movq [edi], xmm0

仅 SSE1 可用时,请使用 movlps 。 (对于加载,您可能希望使用 xorps 打破对 xmm 寄存器旧值的错误依赖)。

使用 MMX,movq往返 mm0-7有效。

<小时/>

gcc 使用 SSE2 movq ,上证1 movlps ,或 x87 fild/fstp按照 std::atomic<int64_t> 的优先顺序在 32 位模式下。叮 -m32不幸的是使用lock cmpxchg8b即使 SSE2 可用:LLVM bug 33109 。 .

某些版本的 gcc 配置为 -msse2即使使用-m32,默认情况下也是打开的(在这种情况下,您可以使用 -mno-sse2-march=i486 来查看 gcc 在没有它的情况下会做什么)。

我输入load and store functions on the Godbolt compiler explorer使用 x87、SSE 和 SSE2 查看 gcc 的 asm。以及来自 clang4.0.1 和 ICC18。

即使 SSE4 ( pinsrd/pextrd ) 可用,gcc 作为 int->xmm 或 xmm->int 的一部分在内存中反弹。这是一个错过的优化( gcc bug 80833 )。在 64 位模式下,它支持 ALU movd +pinsrd/pextrd 和 -mtune=intel-mtune=haswell ,但显然不是在 32 位模式下,或者不适合此用例(XMM 中的 64 位整数而不是正确的向量化)。无论如何,请记住只能从 atomic<long long> shared 加载或存储必须是原子的,堆栈的其他加载/存储是私有(private)的。

<小时/>

在 MSVC 中,有一个 __iso_volatile_load64 Visual C++ 2019 更高版本中的内在函数,可以编译为适当的指令序列。

关于assembly - 如何在 x86 ASM 中自动移动 64 位值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48046591/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com