Assembly XMM寄存器的位求反
如何在XMM寄存器中获得值的位求反?据我所知,没有这样的指示。唯一带否定的指令是Assembly XMM寄存器的位求反,assembly,x86,bit-manipulation,sse,bitwise-not,Assembly,X86,Bit Manipulation,Sse,Bitwise Not,如何在XMM寄存器中获得值的位求反?据我所知,没有这样的指示。唯一带否定的指令是pandn,但要使用它简单地对一个XMM寄存器中的值进行否定,我必须用1填充另一个XMM寄存器 是否有另一种方法对XMM寄存器中的位求反?或者有没有一种聪明的方法可以在不访问内存的情况下用1填充XMM寄存器?要加载一个包含所有1的寄存器,请使用 pcmpeqd xmm0, xmm0 在这之后,您可以简单地从xmm0中减去xmmX,得到~xmmX,或者使用pandn 您还可以轻松地将其他常量加载到xmm寄存器 pcm
pandn
,但要使用它简单地对一个XMM寄存器中的值进行否定,我必须用1
填充另一个XMM寄存器
是否有另一种方法对XMM寄存器中的位求反?或者有没有一种聪明的方法可以在不访问内存的情况下用
1
填充XMM寄存器?要加载一个包含所有1的寄存器,请使用
pcmpeqd xmm0, xmm0
在这之后,您可以简单地从xmm0
中减去xmmX
,得到~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
阅读Agner Fog的优化指南,要加载所有1的寄存器,请使用
pcmpeqd xmm0, xmm0
在这之后,您可以简单地从xmm0
中减去xmmX
,得到~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
阅读Agner Fog的优化指南,使用
pxor
和“全一”寄存器。
pandn
也可用,但没有任何优势。在任何情况下,pandn
使用“全一”常量都可以执行pxor
无法执行的操作
psubd
也可用(2的补码标识),但比pandn
更糟糕,因为它在某些CPU上的吞吐量更低(执行端口更少)
PXOR很好,因为它是可交换的。使用AVX,您可以加载一个微型熔断uop,而不是:
vpxor xmm0, xmm1, [rdi]
VPANDN不能这样做,因为可以是内存或寄存器的操作数是非反转操作数。(但是,如果没有AVX,只需加载movdqa
或dqu
然后加载pxor
加载结果。一个reg拷贝和一个微融合加载+pxor是3个未使用的域UOP,而不是2个)
或者在没有AVX的情况下,如果要销毁all ones常量而不是正在反转的数据,
pxor
再次获胜:
movdqa xmm2, xmm1 ; copy the all-ones constant. Off the critical path for latency
pxor xmm2, xmm0
您可以将movdqa
与movdqa xmm2、xmm0
/pandn xmm2、xmm1
相比,从关键路径中移除。(对于矢量寄存器,只有IvyBridge+和推土机系列/Ryzen具有零延迟movdqa
),或者如果您每次都在目标寄存器中使用pcmpeqd
对所有延迟进行重物质化(可能是因为寄存器压力,或者因为您没有在循环中执行此操作),这将是另一种情况,您需要pxor
而不是pandn
使用
pcmpeqb/w/d
生成一个全一常量是一种特殊情况,它不会对旧值产生错误依赖(Silvermont除外),但仍然需要一个执行单元(与Sandybridge系列上的xor归零不同)。尽管如此,它还是很便宜,而且它是编译器用于\u mm\u set1\u epi32(-1)
的
在IvyBridge和更高版本上,以及在推土机系列和Ryzen上,每次需要时重新创建常量而不是从另一个寄存器中复制,情况稍差mov
-消除XMM拷贝可避免占用向量执行单元/端口,以防向量ALU执行端口成为瓶颈
但在Intel P6系列(Core2/Nehalem)上稍好一些:在问题组中读取太多“冷”寄存器时,寄存器读取暂停可能是一个问题。(参见Agner Fog的Microach pdf)。P6系列已过时,但仍在一些旧机器中使用。如果有一个AVX版本运行在带有AVX的CPU上,您可能希望在非AVX版本的代码中对其进行调优。(但是Haswell/Skylake“pentium”/“celeron”仍然是一个东西,而且他们没有AVX,所以没有AVX并不意味着旧CPU。)使用
pxor
和“全一”寄存器。
pandn
也可用,但没有任何优势。在任何情况下,pandn
使用“全一”常量都可以执行pxor
无法执行的操作
psubd
也可用(2的补码标识),但比pandn
更糟糕,因为它在某些CPU上的吞吐量更低(执行端口更少)
PXOR很好,因为它是可交换的。使用AVX,您可以加载一个微型熔断uop,而不是:
vpxor xmm0, xmm1, [rdi]
VPANDN不能这样做,因为可以是内存或寄存器的操作数是非反转操作数。(但是,如果没有AVX,只需加载movdqa
或dqu
然后加载pxor
加载结果。一个reg拷贝和一个微融合加载+pxor是3个未使用的域UOP,而不是2个)
或者在没有AVX的情况下,如果要销毁all ones常量而不是正在反转的数据,
pxor
再次获胜:
movdqa xmm2, xmm1 ; copy the all-ones constant. Off the critical path for latency
pxor xmm2, xmm0
您可以将movdqa
与movdqa xmm2、xmm0
/pandn xmm2、xmm1
相比,从关键路径中移除。(对于矢量寄存器,只有IvyBridge+和推土机系列/Ryzen具有零延迟movdqa
),或者如果您每次都在目标寄存器中使用pcmpeqd
对所有延迟进行重物质化(可能是因为寄存器压力,或者因为您没有在循环中执行此操作),这将是另一种情况,您需要pxor
而不是pandn
使用
pcmpeqb/w/d
生成一个全一常量是一种特殊情况,它不会对旧值产生错误依赖(Silvermont除外),但仍然需要一个执行单元(与Sandybridge系列上的xor归零不同)。尽管如此,它还是很便宜,而且它是编译器用于\u mm\u set1\u epi32(-1)
的
在IvyBridge和更高版本上,以及在推土机系列和Ryzen上,每次需要时重新创建常量而不是从另一个寄存器中复制,情况稍差mov
-消除XMM拷贝可避免占用向量执行单元/端口,以防向量ALU执行端口成为瓶颈
但在英特尔P6上稍好一些