Ram*_*mes 0 x86 assembly sse bit-manipulation bitwise-not
如何在XMM寄存器中对值进行逐位否定?据我所知,没有这样的指示.唯一有否定的指令是pandn
,但是要用它来简单地否定一个XMM寄存器中的值,我必须填充另一个填充的XMM寄存器1
.
是否有另一种方法来否定XMM寄存器中的位?或者有没有一种聪明的方法来填充XMM寄存器而1
无需访问内存?
要加载全1的寄存器,请使用
pcmpeqd xmm0, xmm0
Run Code Online (Sandbox Code Playgroud)
之后,您可以简单地xmmX
从中减去xmm0
得到~xmmX
或使用pandn
您还可以轻松地将其他常量加载到xmm寄存器
pcmpeqd xmm0, xmm0
psrld xmm0, 30 ; 3 (32-bit)
pcmpeqd xmm0, xmm0 ; -1
pcmpeqw xmm0, xmm0 ; 1.5f
pslld xmm0, 24
psrld xmm0, 2
pcmpeqw xmm0, xmm0 ; -2.0f
pslld xmm0, 30
Run Code Online (Sandbox Code Playgroud)
阅读Agner Fog的优化指南,13.4生成常量-在XMM寄存器中为整数矢量生成常量
使用pxor
全1寄存器.
pandn
也是可用的,但没有任何优点.没有任何情况下,pandn
使用全能常量可以让你做任何你无法做到的事情pxor
.
psubd
也是可用的(2的补码标识),但更糟糕的是pandn
因为它在某些CPU上具有较低的吞吐量(较少的执行端口).
pcmpedq xmm1, xmm1 ; create the all-ones. No false dependency.
pxor xmm0, xmm1 ; flip all the bits in XMM0. Doesn't destroy XMM1
;pandn xmm0, xmm1 ; equivalent but no advantage. (~xmm0) & xmm1
Run Code Online (Sandbox Code Playgroud)
PXOR很好,因为它是可交换的.使用AVX,您可以使用一个微融合uop加载和取消:
vpxor xmm0, xmm1, [rdi]
Run Code Online (Sandbox Code Playgroud)
你不能用VPANDN做到这一点,因为可以是内存或寄存器的操作数是非反转操作数.(无AVX,虽然,刚刚movdqa
或dqu
负载,然后pxor
负载结果.一个reg拷贝和微稠负载+ PXOR是3总未融合结构域的uop对2)
或者没有AVX,如果你想破坏所有的常数而不是你正在反转的数据,那么pxor
再次获胜:
movdqa xmm2, xmm1 ; copy the all-ones constant. Off the critical path for latency
pxor xmm2, xmm0
Run Code Online (Sandbox Code Playgroud)
你可以采取movdqa
关键路径与movdqa xmm2, xmm0
/ pandn xmm2,xmm1
.(只有IvyBridge +和Bulldozer-family/Ryzen movdqa
对矢量寄存器的延迟为零.)或者如果你每次都pcmpeqd
在目标寄存器中重新实现所有的那些(可能是因为寄存器压力或因为你没有在循环),这将是你想要的另一种情况pxor
而不是pandn
.
生成一个all-one常量pcmpeqb/w/d
是特殊的,不会对旧值有错误依赖(Silvermont除外),但仍然需要一个执行单元(与Sandybridge-family上的xor-zeroing不同).尽管如此,它还是便宜的,而这正是编译器所使用的_mm_set1_epi32(-1)
.
每次你需要它时重新创建常量,而不是从另一个寄存器复制,在IvyBridge和更高版本以及Bulldozer家族和Ryzen上稍微差一点. mov
- 消除XMM副本避免占用向量执行单元/端口,以防vector-ALU执行端口是您的瓶颈.
但是在英特尔P6系列(Core2/Nehalem)上稍微好一些:当在一个问题组中读取太多"冷"寄存器时,寄存器读取停顿可能是一个问题.(参见Agner Fog的微格式pdf https://agner.org/optimize/).P6系列已经过时但仍在某些旧机器中使用.如果您的AVX版本在带有AVX的CPU上运行,您可能希望在非AVX版本的代码中进行调整.(但Haswell/Skylake"pentium"/"celeron"仍然是一个东西,他们没有AVX,所以no-AVX并不意味着旧CPU.)