如何将XMM 128位寄存器拆分为两个64位整数寄存器?

时间:2016-12-19 12:25:54

标签: assembly x86 sse

如何将128位xmm寄存器拆分为两个64位四字?

我在xmm1中有一个非常大的数字,并希望将更高的四字变为r9,将低四字变为r10,或RAXRDX

movlpdmovhpd仅适用于reg或mem,反之亦然。

1 个答案:

答案 0 :(得分:5)

SSE2(x86-64的基线)具有在XMM和整数寄存器之间直接移动数据的指令(不通过内存反弹)。矢量的低元素很容易:MOVD or MOVQ。要提取更高的元素,您可以将所需的元素随机播放到向量的低元素。

SSE4.1还为16位以外的大小添加了插入/提取(例如PEXTRQ)。除了代码大小之外,它是not actually faster than a separate shuffle and movq on any existing CPUs,但这意味着您不需要任何额外的tmp寄存器。

#SSE4.1
movq    rax, xmm0       # low qword
pextrq  rdx,  xmm0, 1   # high qword
# 128b result in rdx:rax, ready for use with div r64 for example.
# (But watch out for #DE on overflow)
# also ready for returning as a __int128_t in the SystemV x86-64 ABI

#SSE2
movq       r10, xmm0
punpckhqdq xmm0, xmm0    # broadcast the high half of xmm0 to both halves
movq       r9,  xmm0

PUNPCKHQDQ是最有效的方法。即使在旧的CPU上,对于元素大小小于64位的缓慢混洗,它也很快,如65nm Core2(Merom / Conroe)。有关详细信息,请参阅my horizontal sum answer。 PUNPCKHQDQ没有立即操作数,只有SSE2,所以它只有4个字节的代码大小。

要保留xmm0的原始值,请将pshufd与不同的目的地一起使用。或者在原地或者其他任何地方交换高低两半。

  

movlpd或movhpd ...

没有必要使用它们。请改用movlps / movhps,因为它们更短,没有CPU关心float与double。

您可以使用movhlps xmm1, xmm0将xmm0的高半部分提取到另一个寄存器中,但将FP shuffle与整数向量运算混合将导致某些CPU(特别是Intel Nehalem)的旁路延迟。还要注意对xmm1的依赖导致延迟瓶颈。

一般来说,绝对更喜欢pshufd。但是,如果您正在调整特定CPU(如Core {2},movhlps速度很快且在整数域中运行,movhlps速度很慢,则可以使用pshufd