XMM寄存器的按位否定

Ram*_*mes 0 x86 assembly sse bit-manipulation bitwise-not

如何在XMM寄存器中对值进行逐位否定?据我所知,没有这样的指示.唯一有否定的指令是pandn,但是要用它来简单地否定一个XMM寄存器中的值,我必须填充另一个填充的XMM寄存器1.

是否有另一种方法来否定XMM寄存器中的位?或者有没有一种聪明的方法来填充XMM寄存器而1无需访问内存?

phu*_*clv 6

要加载全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”。 (2认同)

Pet*_*des 5

使用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,虽然,刚刚movdqadqu负载,然后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.)