我使用xmm0具有128位的系统。我想将[63 ... 0]设置为零,而不会影响[127 ... 64]。我使用:
MOV RAX, 0xFFFFFFFFFFFFFFFF
MOVQ xmm2, RAX
PSHUFD xmm2, xmm2, 0b00001111
PAND xmm1, xmm2
有更快的方法吗?
您可以通过]稍微有效地创建常量。
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所需的更多:
movss
-一切都变差(或相等的速度,但代码大小更差)。仍然只能在Intel的port5上运行。 Ryzen在比pblendw xmm1, xmm2, 0b00001111
更多的端口上运行movsd xmm,xmm
。与pblendw相比,低功率Atom / Silvermont在movsd上运行的端口更多,但是Goldmont和KNL对此端口和movsd的吞吐量为2 /时钟。因此它仍然永远比movsd更好。pblendw
blendpd xmm1, xmm2, 0b01
)-与vpblendd一样有效,但是如果在整数指令之间使用,则会产生旁路转发延迟。如果您遇到吞吐量瓶颈,可以这样做,尤其是在必须避免后端压力的情况下。blendpd xmm1, xmm2, 0b01
-在任何AVX2 CPU的任何ALU端口上运行。某些整数指令之间的某些CPU可能也有blendps
的旁路延迟,但是Sandybridge系列对于混洗相当宽容。
[在某些CPU上与vpblendd xmm1, xmm1, xmm2, 0b0011
等效,仅需要SSE1:
movsd
-将xmm1的低位qword替换为xmm2的高位qword(也为零)。在Ryzen或Silvermont上效率较低。类似地,movsd
和movhlps xmm1, xmm2
可以将shufpd
的上半部分复制到清零寄存器的上半部分。 (如果您不想破坏原始reg,则很有用)。但是您可以使用shufps
轻松而高效地完成此操作。
也可能:xmm1
加载零,可能是您刚刚存储到堆栈中。它不允许寄存器源操作数,并且需要Intel上的port5 uop(随机/不常见的混合)。它可以微融合到一个融合域uop中,但是它比带有内存源的movsd
更糟糕,因为它可以在更少的端口上运行。