X86 操作码将 xmm 寄存器移动到通用寄存器

Posted

技术标签:

【中文标题】X86 操作码将 xmm 寄存器移动到通用寄存器【英文标题】:X86 opcodes to move xmm register to general registers 【发布时间】:2016-06-10 04:47:32 【问题描述】:

将 xmm0 寄存器移动到 eax 和 edx 的短 x86 指令序列是什么?

【问题讨论】:

除非必要,否则不要在不同的域之间移动 【参考方案1】:

你想要 xmm0 的哪些部分?

movd     eax, xmm0
pextrd   edx, xmm0, 1    ; SSE4.1

将 xmm0 的低 64 位获取到 edx:eax。如果您需要所有 4 个部分,请考虑存储到内存并重新加载:存储转发到加载具有更多延迟,但比随机播放具有更好的吞吐量(总 uops 更少),特别是如果您可以将它们用作内存源操作数而不仅仅是 mov

(但是如果你想要一个水平和什么的,通常do that with SIMD shuffles像pshufd/paddd两次将4个元素减少到2然后到1。虽然movd eax, xmm0/movdqa [esp], xmm0存储和3个标量在这种情况下,add eax, [esp + 4/8/12] 实际上对于总 uops 或延迟来说还不错,不像标量 FP,其中延迟更高,并且无论如何您都希望在 XMM reg 中得到结果。)


在 64 位代码中,movq rax, xmm0 / shld rdx, rax, 32 可能优于 pextrd,并且不需要 SSE4.1。

更普通的mov rdx, rax / shr rdx, 32 可能比 SHLD 更有效,即使它在 Intel CPU 上花费更多微指令。 shld 在 AMD CPU 上很慢,在 Zen 上是 8 uops。 (https://uops.info/)

BMI2 rorx rdx, rax, 32 是一种复制和移位的好方法,并且在所有支持它的 CPU 上都很有效。当然,RDX 的高半部分可能不为零,但这很好。

另一个选择是movd/movq,如果您没有接近他们竞争的单个端口的吞吐量瓶颈。在大多数 CPU 上,它们实际上不能并行运行,因此 movd/movq 竞争一个端口仍然会花费第二个端口的延迟。在具有 mov-elimination(Zen 或 IvyBridge)的现代 CPU 上,零延迟的mov rdx, rax 更好。但这确实会使您在 EAX 和 EDX 中的值零扩展为 RAX 和 RDX。

    movq  rdx, xmm0
    movd  eax, xmm0       ; or schedule this first if you can use EAX right away
    shr   rdx, 32

请参阅x86 标签 wiki 以获取指令集参考和其他内容。

请参阅Agner Fog's excellent Optimizing Assembly guide,了解使用说明的提示。

【讨论】:

希望在 x86(32 位)上的 xmm0 中从 64 位双精度中获取位。 @tgiphil:好的,我猜的是低 64。你有什么理由不接受这个答案吗?您是否需要使用矢量移位或随机播放的 32 位 SSE2 版本来将第二个单词降到元素 0 以获得另一个 movd 有什么方法可以在没有 SSE4.1 的 x86 上做到这一点? @tgiphil: pshufd + movd,或任何其他方便的随机播放将您想要的元素带到低 64 位或 32 位。

以上是关于X86 操作码将 xmm 寄存器移动到通用寄存器的主要内容,如果未能解决你的问题,请参考以下文章