X86:如何将xmm0的下半部分设置为0,而又不影响上半部分?

问题描述 投票:3回答:1

我使用xmm0具有128位的系统。我想将[63 ... 0]设置为零,而不会影响[127 ... 64]。我使用:

MOV RAX, 0xFFFFFFFFFFFFFFFF
MOVQ xmm2, RAX
PSHUFD xmm2, xmm2, 0b00001111
PAND xmm1, xmm2

有更快的方法吗?

assembly x86 sse simd micro-optimization
1个回答
4
投票

您可以通过]稍微有效地创建常量。

pcmpeqd xmm2,xmm2       ; xmm2 = all-ones.  Needs any ALU port
pslldq  xmm2, 8         ; left shift by 8 bytes.  Needs the shuffle port

PAND    xmm1, xmm2

(另请参阅Agner Fog's optimization guide;他有关于动态创建常量的部分。还有What are the best instruction sequences to generate vector constants on the fly?

或@RossRidge建议,如果需要经常使用内存源操作数作为常量,以使其在高速缓存中保持高温,而又不能只是将其从循环中提升并保存在寄存器中,则可能是最有效的。


或混入新的低8字节零

pxor   xmm2, xmm2       ; xmm2=0; very efficient on Intel CPUs; no back-end uop

movsd  xmm1, xmm2       ; runs on port5 only on Intel CPUs, like shuffles.

(作为从内存中加载,movsd零扩展。但是对于reg-reg移动它,movsd保留目标上部不变。)

替代混合方法更有效,但比SSE2所需的更多:

  • SSE4.1:movss-一切都变差(或相等的速度,但代码大小更差)。仍然只能在Intel的port5上运行。 Ryzen在比pblendw xmm1, xmm2, 0b00001111更多的端口上运行movsd xmm,xmm。与pblendw相比,低功率Atom / Silvermont在movsd上运行的端口更多,但是Goldmont和KNL对此端口和movsd的吞吐量为2 /时钟。因此它仍然永远比movsd更好。
  • SSE4.1 pblendw
  • (或blendpd xmm1, xmm2, 0b01)-与vpblendd一样有效,但是如果在整数指令之间使用,则会产生旁路转发延迟。如果您遇到吞吐量瓶颈,可以这样做,尤其是在必须避免后端压力的情况下。
  • AVX2:blendpd xmm1, xmm2, 0b01-在任何AVX2 CPU的任何ALU端口上运行。
  • 某些整数指令之间的某些CPU可能也有blendps的旁路延迟,但是Sandybridge系列对于混洗相当宽容。

[在某些CPU上与vpblendd xmm1, xmm1, xmm2, 0b0011等效,仅需要SSE1:

  • movsd-将xmm1的低位qword替换为xmm2的高位qword(也为零)。在Ryzen或Silvermont上效率较低。
  • 类似地,movsdmovhlps xmm1, xmm2可以将shufpd的上半部分复制到清零寄存器的上半部分。 (如果您不想破坏原始reg,则很有用)。但是您可以使用shufps轻松而高效地完成此操作。


也可能:xmm1加载零,可能是您刚刚存储到堆栈中。它不允许寄存器源操作数,并且需要Intel上的port5 uop(随机/不常见的混合)。它可以微融合到一个融合域uop中,但是它比带有内存源的movsd更糟糕,因为它可以在更少的端口上运行。

© www.soinside.com 2019 - 2024. All rights reserved.