Luk*_*ohl 3 x86 assembly sse simd micro-optimization
我使用 xmm0 有 128 位的系统。我想将 [63...0] 设置为零,而不影响 [127...64]。我用:
MOV RAX, 0xFFFFFFFFFFFFFFFF
MOVQ xmm2, RAX
PSHUFD xmm2, xmm2, 0b00001111
PAND xmm1, xmm2
Run Code Online (Sandbox Code Playgroud)
有没有更快的方法?
您可以通过以下方式更有效地创建常量
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
Run Code Online (Sandbox Code Playgroud)
(另请参阅Agner Fog 的优化指南;他有一节关于动态创建常量。还有什么是动态生成向量常量的最佳指令序列?)
或者正如@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.
Run Code Online (Sandbox Code Playgroud)
(作为从内存中加载,movsd零扩展。但对于 reg-reg 移动它并movss保持目标上部不变。)
混合的替代方法更有效,但需要的不仅仅是 SSE2:
pblendw xmm1, xmm2, 0b00001111- 一切都更糟(或相同的速度但更糟糕的代码大小)。仍然只在 Intel 的 port5 上运行。Ryzenmovsd xmm,xmm在比pblendw. 与 pblendw 相比,低功耗 Atom/Silvermont 在更多端口上运行 movsd,但 Goldmont 和 KNL 对此和 movsd 的吞吐量为 2/clock。所以它永远不会比 movsd 更好。blendpd xmm1, xmm2, 0b01(或blendps) - 与 vpblendd 一样有效,但如果在整数指令之间使用,则会导致旁路转发延迟。如果您在吞吐量方面遇到瓶颈,这可能没问题,尤其是在您必须避免后端压力的情况下。vpblendd xmm1, xmm1, xmm2, 0b0011- 在任何 AVX2 CPU 上的任何 ALU 端口上运行。一些 CPU 可能也有movsd整数指令之间的旁路延迟,但 Sandybridge 系列对随机播放非常宽容。
与movsd某些 CPU一样高效,只需要 SSE1:
movhlps xmm1, xmm2 - 用 xmm2 的高 qword(也为零)替换 xmm1 的低 qword。在 Ryzen 或 Silvermont 上效率较低。类似地,shufpd并且shufps可以将 的上半部分复制xmm1到归零寄存器的上半部分。(如果您不想破坏原始 reg,则很有用)。但您可以movsd同样轻松、高效地做到这一点。
也可能:movlps xmm, [mem]加载零,可能是您刚刚存储到堆栈中。它不允许使用寄存器源操作数,并且需要在 Intel 上使用 port5 uop(shuffle / uncommon blend)。它可以微融合到一个融合域 uop 中,但它通常比pand使用内存源更糟糕,因为它可以在更少的端口上运行。
| 归档时间: |
|
| 查看次数: |
214 次 |
| 最近记录: |