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

7
如何将一个128位的xmm寄存器分成两个64位的四字节?
我有一个非常大的数字在xmm1中,想要将高四字节传送到r9中,将低四字节传送到r10中,或者传送到RAXRDX中。 movlpdmovhpd只能用于从寄存器到内存或反之。

1
使用gcc编译long long f(long long __attribute__((vector_size(16))) x){return x[1];}(包括版本为0的)以获取一些建议... - Marc Glisse
1个回答

8

SSE2(x86-64的基准)具有直接在XMM和整数寄存器之间移动数据的指令(无需通过内存反弹)。对于向量的低位元素,使用MOVD或MOVQ非常容易。要提取更高的元素,您可以将所需元素向下移动到向量的低位元素。

SSE4.1还添加了除16位以外的其他插入/提取大小的功能(例如PEXTRQ)。除了代码大小外,在任何现有CPU上与分别进行洗牌和movq相比,实际上并不快,但这意味着您不需要额外的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位的元素大小时,像65纳米的Core2(Merom/Conroe)这样具有缓慢洗牌的旧CPU上也很快速。关于此详情请参见我的水平总和答案。PUNPCKHQDQ没有立即操作数,并且只有SSE2,因此它只有4个字节的代码大小。
为了保留xmm0的原始值,请使用指令并使用不同的目标寄存器。或者可以就地交换高低半部分等操作。

movlpd或movhpd...

永远没有使用它们的必要。请改用movlps/movhps,因为它们更短,并且没有任何CPU关心浮点数与双精度之间的区别。
您可以使用movhlps xmm1, xmm0将xmm0的高半部分提取到另一个寄存器中,但是混合FP shuffle与整数向量操作会导致某些CPU(特别是Intel Nehalem)出现旁路延迟。还要注意xmm1的依赖性会导致延迟瓶颈。
通常情况下,最好使用pshufd进行操作。但是,如果您正在针对像Core2这样的特定CPU进行调优,则可以使用movhlps(在整数域中快速运行)而pshufd缓慢的特点会导致不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接