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 寄存器移动到通用寄存器的主要内容,如果未能解决你的问题,请参考以下文章

将XMM寄存器推入堆栈

将浮点数从高 xmm 四字移动到低 xmm 四字

为什么 JVM x86 生成的机器代码有 XMM 寄存器?

为啥将 32 位寄存器移动到堆栈然后从堆栈移动到 xmm 寄存器?

将单个浮点数移动到 xmm 寄存器

如何将浮点常量值移动到 xmm 寄存器中?