X86:如何将xmm0的下半部分设置为0,而不影响上半部分?
Posted
技术标签:
【中文标题】X86:如何将xmm0的下半部分设置为0,而不影响上半部分?【英文标题】:X86: How to set lower half of xmm0 to 0, without affecting the upper half? 【发布时间】:2019-12-25 17:58:53 【问题描述】:我使用 xmm0 具有 128 位的系统。 我想将 [63...0] 设置为零,而不影响 [127...64]。 我用:
MOV RAX, 0xFFFFFFFFFFFFFFFF
MOVQ xmm2, RAX
PSHUFD xmm2, xmm2, 0b00001111
PAND xmm1, xmm2
有没有更快的方法?
【问题讨论】:
【参考方案1】:您可以通过
更有效地创建常量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 移动它并且movss
保持目标上部不变。)
其他混合方式更有效,但比 SSE2 需要更多:
SSE4.1:pblendw xmm1, xmm2, 0b00001111
- 一切都更糟(或速度相同但代码大小更差)。仍然只在 Intel 的 port5 上运行。 Ryzen 在比pblendw
更多的端口上运行movsd xmm,xmm
。低功耗 Atom/Silvermont 在比 pblendw 更多的端口上运行 movsd,但 Goldmont 和 KNL 对此和 movsd 有 2 个/时钟的吞吐量。所以它仍然永远不会比 movsd 更好。
SSE4.1 blendpd xmm1, xmm2, 0b01
(或blendps
) - 与 vpblendd 一样高效,但如果在整数指令之间使用会产生绕过转发延迟。如果您在吞吐量方面遇到瓶颈,这可能没问题,尤其是在您必须避免后端压力的情况下。
AVX2:vpblendd xmm1, xmm1, xmm2, 0b0011
- 在任何 AVX2 CPU 的任何 ALU 端口上运行。
某些 CPU 可能还会在整数指令之间对 movsd
进行旁路延迟,但 Sandybridge 系列对随机播放非常宽容。
在某些 CPU 上与 movsd
一样高效,只需要 SSE1:
movhlps xmm1, xmm2
- 将 xmm1 的低 qword 替换为 xmm2 的高 qword(也为零)。在 Ryzen 或 Silvermont 上效率较低。
同样,shufpd
和shufps
可以将xmm1
的上半部分复制到零寄存器的上半部分。 (如果您不想破坏原始注册,则很有用)。但是您可以使用movsd
轻松高效地做到这一点。
也可能:movlps xmm, [mem]
加载零,可能是您刚刚存储到堆栈中。它不允许注册源操作数,并且需要 Intel 上的 port5 uop(shuffle / uncommon blend)。它可以微融合到一个融合域微指令中,但它比带有内存源的pand
差很多,因为它可以在更少的端口上运行。
【讨论】:
以上是关于X86:如何将xmm0的下半部分设置为0,而不影响上半部分?的主要内容,如果未能解决你的问题,请参考以下文章
css 已经定义上面一部分 下半部分想使高度占下半区域100%怎么办
如何将半透明的“图片/图像”设置为黑白,而不影响子元素和背景颜色? [复制]
在 UITableView 上为 layoutIfNeeded 设置动画而不为 UITableViewCells 设置动画