assembly - X86:如何将xmm0的下半部分设置为0,而不影响上半部分?
问题描述
我使用 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 的优化指南;他有一个关于动态创建常量的部分。还有什么是动态生成向量常量的最佳指令序列?)
或者正如@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 上运行。Ryzenmovsd xmm,xmm
在比pblendw
. 低功耗 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 系列对 shuffle 非常宽容。
与某些 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)。它可以微融合到一个融合域 uop 中,但它比pand
内存源更糟糕,因为它可以在更少的端口上运行。
推荐阅读
- java - 如何在不向我抛出 SecurityException 的情况下创建代理类?
- java - javax.sound.sampled.UnsupportedAudioFileException:不支持格式的流
- function - haskell 中的命题
- spring-batch - 我应该如何使用 Spring Batch 和 Spring Cloud Data Flow 对可配置的批处理网络进行切片和编排?
- arrays - 需要将字符串转换为二维数组
- c# - 从两个数组对象中获取不匹配的数组
- ef-core-2.1 - ExecuteSqlCommand 返回 -1?
- gradle - 在 Gradle 构建中确定 JVM 供应商
- reactjs - 在 React 中上传多个文件时出错
- python - 在 TensorFlow 2 中替换“占位符”