如何将128位xmm
寄存器拆分为两个64位quadwords?
我的xmm1
数量很多,并且想要将较高的四字设为r9
,将较低的四字设为r10
或RAX
和RDX
。movlpd
或movhpd
仅在reg到mem时有效,反之亦然。
最佳答案
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是执行此操作的最有效方法。即使是在元素大小小于64位的较慢CPU(如65nm Core2(Merom/Conroe))上进行慢速混洗的情况下,它的速度也很快。有关更多详细信息,请参见my horizontal sum answer。 PUNPCKHQDQ没有立即数,并且只有SSE2,因此它只有4个字节的代码大小。
要保留xmm0的原始值,请将
pshufd
与其他目标一起使用。或就地交换上半部分和下半部分,或进行其他操作。使用它们毫无意义。请改用movlps/movhps,因为它们更短并且没有CPU关心float与double。
您可以使用
movhlps xmm1, xmm0
将xmm0的上半部分提取到另一个寄存器中,但是将FP shuffle与整数矢量操作混合会在某些CPU(特别是Intel Nehalem)上引起旁路延迟。还要注意对xmm1的依赖性,这会导致延迟瓶颈。一般来说,绝对喜欢
pshufd
。但是,如果要针对像Core2这样的特定CPU进行调优,则可以使用movhlps
,其中movhlps
快速并且在整数域中运行,而pshufd
则很慢。关于assembly - 如何将XMM 128位寄存器拆分为两个64位整数寄存器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41222574/