assembly - 是否存在使用 MOVDQU 和 MOVUPD 优于 MOVUPS 的情况?

标签 assembly x86 x86-64 intel sse

我试图了解英特尔 x86-64 上 SSE 的不同 MOV 指令。

根据 this在 2 个寄存器之间移动数据时,您应该使用对齐指令(MOVAPS、MOVAPD 和 MOVDQA),并使用适合您操作的类型的正确指令。并在将寄存器移动到内存时使用 MOVUPS/MOVAPS,反之亦然,因为类型在移入/移出内存时不会影响性能。

那么有什么理由使用 MOVDQU 和 MOVUPD 吗?我在链接上得到的解释是错误的吗?

最佳答案

摘要:我不知道最近有任何 x86 架构在使用“错误”加载指令(即加载指令后跟来自相反域的 ALU 指令)时会导致额外的延迟。

这是什么 Agner has to say关于旁路延迟,这是您在 CPU 中的各个执行域之间移动时可能产生的延迟(有时这些是不可避免的,但有时它们可​​能是由于使用了此处有问题的指令的“错误”版本引起的):

Data bypass delays on Nehalem On the Nehalem, the execution units are divided into five "domains":

The integer domain handles all operations in general purpose registers. The integer vector (SIMD) domain handles integer operations in vector registers. The FP domain handles floating point operations in XMM and x87 registers. The load domain handles all memory reads. The store domain handles all memory stores. There is an extra latency of 1 or 2 clock cycles when the output of an operation in one domain is used as input in another domain. These so-called bypass delays are listed in table 8.2.



Table 8.2

There is still no extra bypass delay for using load and store instructions on the wrong type of data. For example, it can be convenient to use MOVHPS on integer data for reading or writing the upper half of an XMM register.



最后一段的重点是我的,也是关键部分:旁路延迟不适用于 Nehalem 加载和存储指令。直观地说,这是有道理的:加载和存储单元专用于整个内核,并且必须以适合任何执行单元的方式提供它们的结果(或将其存储在 PRF 中)——与 ALU 情况不同,与转发不存在。

现在不再真正关心 Nehalem,但在 Sandy Bridge/Ivy Bridge、Haswell 和 Skylake 的部分中,您会发现这些域与针对 Nehalem 讨论的域相同,并且总体延迟更少。因此,可以假设加载和存储不会因指令类型而受到延迟的行为仍然存在。

我们也可以测试一下。我写了一个这样的基准:
bypass_movdqa_latency:
    sub     rsp, 120
    xor     eax, eax
    pxor    xmm1, xmm1
.top:
    movdqa  xmm0, [rsp + rax] ; 7 cycles
    pand    xmm0, xmm1        ; 1 cycle
    movq    rax, xmm0         ; 1 cycle
    dec     rdi
    jnz     .top
    add     rsp, 120
    ret

这使用 movdqa 加载一个值,对其进行整数域操作( pand ),然后将其移动到通用寄存器 rax所以它可以用作 movdqa 地址的一部分在下一个循环中。我还创建了 3 个与上述相同的其他基准测试,除了 movdqa替换为 movdqu , movupsmovupd .

Skylake-client(i7-6700HQ 与最近的微码)上的结果:
** Running benchmark group Vector unit bypass latency **
                     Benchmark   Cycles
  movdqa [mem] -> pxor latency     9.00
  movdqu [mem] -> pxor latency     9.00
  movups [mem] -> pxor latency     9.00
  movupd [mem] -> pxor latency     9.00

在每种情况下,往返延迟都是相同的:9 个周期,正如预期的那样:负载为 6 + 1 + 2 个周期,pxormovq分别。

所有这些测试都添加在 uarch-bench 中如果您想在任何其他架构上运行它们(我会对结果感兴趣)。我使用了命令行:
./uarch-bench.sh --test-name=vector/* --timer=libpfc

关于assembly - 是否存在使用 MOVDQU 和 MOVUPD 优于 MOVUPS 的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40854819/

相关文章:

windows - Windows 上的 CMake -G Ninja 指定 x64

c - 如何修复 'request for member in something not a structure or union'错误?

assembly - UEFI 机器可以使用 BIOS 中断吗?

assembly - 为什么全局描述符表的第一个段描述符只包含零?

assembly - 如何在x86汇编中获得没有堆栈的eip

ios - 使用 Parse 的 undefined symbol

assembly - 如何在 NASM 中编写 'Hello_world' EFI 应用程序?

c - ARM GCC 生成的函数序言

c++ - 什么时候会在编译过程中删除琐碎的(没有效果的代码)代码?

gcc - 减去并检测下溢,最有效的方法? (带有 GCC 的 x86/64)