我有几个与将 XMM 值移动到通用寄存器相关的问题。在 SO 上发现的所有问题都集中在相反的方面,即将 gp 寄存器中的值传输到 XMM。
movq RAX XMM1 ; 0th bit to 63th bit
mov? RCX XMM1 ; 64th bit to 127th bit
movd EAX XMM1 ; 0th bit to 31th bit
mov? ECX XMM1 ; 32th bit to 63th bit
mov? EDX XMM1 ; 64th bit to 95th bit
mov? ESI XMM1 ; 96th bit to 127 bit
最佳答案
您不能将 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 差多少。)这为您提供了不同后端执行单元的 uops 平衡。当您需要大量小元素时,存储/重新加载尤其有用。 ( 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。
关于assembly - 128 位值 - 从 XMM 寄存器到通用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44018590/