您不能将 XMM 寄存器的高位直接移动到通用寄存器中。
您必须遵循一个两步过程,这可能涉及也可能不涉及到内存的往返或寄存器的销毁。
在寄存器中 (SSE2)
movq rax,xmm0 ;lower 64 bits
movhlps xmm0,xmm0 ;move high 64 bits to low 64 bits.
movq rbx,xmm0 ;high 64 bits.
punpckhqdq xmm0,xmm0 是 movhlps xmm0,xmm0 的 SSE2 整数等价物。如果 xmm0 最后由整数指令而不是 FP 写入,则某些 CPU 可能会避免一两个周期的旁路延迟。
通过内存 (SSE2)
movdqu [mem],xmm0
mov rax,[mem]
mov rbx,[mem+8]
慢,但不会破坏 xmm 寄存器 (SSE4.1)
mov rax,xmm0
pextrq rbx,xmm0,1 ;3 cycle latency on Ryzen! (and 2 uops)
混合策略是可能的,例如存储到内存中,movd/q e/rax,xmm0 以便快速准备好,然后重新加载更高的元素。 (不过,存储转发延迟并不比 ALU 差多少。)这为您提供了不同后端执行单元的微指令平衡。当您需要大量小元素时,存储/重新加载特别好。 (mov / movzx 加载到 32 位寄存器很便宜,并且具有 2 个时钟的吞吐量。)
对于32位,代码类似:
在寄存器中
movd eax,xmm0
psrldq xmm0,xmm0,4 ;shift 4 bytes to the right
movd ebx,xmm0
psrldq xmm0,xmm0,4 ; pshufd could copy-and-shuffle the original reg
movd ecx,xmm0 ; not destroying the XMM and maybe creating some ILP
psrlq xmm0,xmm0,4
movd edx,xmm0
通过记忆
movdqu [mem],xmm0
mov eax,[mem]
mov ebx,[mem+4]
mov ecx,[mem+8]
mov edx,[mem+12]
不破坏 xmm 寄存器 (SSE4.1)(像 psrldq / pshufd 版本一样慢)
movd eax,xmm0
pextrd ebx,xmm0,1 ;3 cycle latency on Skylake!
pextrd ecx,xmm0,2 ;also 2 uops: like a shuffle(port5) + movd(port0)
pextrd edx,xmm0,3
64 位移位变体可以在 2 个周期内运行。 pextrq 版本最少需要 4 个。对于 32 位,数字分别为 4 和 10。