是否存在快速检查SIMD向量是否为零向量(所有组件等于+ -zero)的方法。我目前正在使用一种算法,使用在log2(N)时间内运行的移位,其中N是向量的维数。有没有更快的东西?请注意,我的问题比提出的答案更广泛(标签),它引用了所有类型的向量(整数,浮点数,双精度......)。
答案 0 :(得分:1)
如果要测试浮点数为+/- 0.0,则可以检查除符号位之外的所有位为零。除符号位之外的任何位置都意味着浮点数不为零。 (http://www.h-schmidt.net/FloatConverter/IEEE754.html)
Agner Fog的asm optimization guide指出你可以使用整数指令测试浮点数或加倍为零:
; Example 17.4b
mov eax, [rsi]
add eax, eax ; shift out the sign bit
jz IsZero
对于向量,使用带有符号位掩码的ptest
比使用paddd
去掉符号位要好。实际上,test [rsi], $0x7fffffff
可能比Agner Fog的加载/添加序列更有效,但32位立即可能会阻止英特尔微融合的负载,并且可能具有更大的代码大小。
x86 PTEST
(SSE4.1)执行按位AND并根据结果设置标志。
movdqa xmm0, [mask]
.loop:
ptest xmm0, [rsi+rcx]
jnz nonzero
add rcx, 16 # count up towards zero
jl .loop # with rsi pointing to past the end of the array
...
nonzero:
或cmov
可能有助于使用ptest
设置的标记。
IDK如果可以使用没有设置零标志的循环计数器指令,那么你可以使用一个跳转指令进行两个测试。可能不是。并且用于合并标志的额外uop(或早期CPU上的部分标志停止)将抵消该好处。
@Iwillnotexist Idonotexist:你对OP的评论之一:你不能只先移动pcmpeq
,或cmpps
。非零位可能不在高位!你可能知道这一点,但你的一条评论似乎已经废除了。
我确实喜欢在实际测试之前将多个值进行ORing的想法。你是对的,符号位会与其他符号位进行或运算,然后你就像你一次测试一样符号一样忽略它们。在POR
之前PTEST
4或8个向量的循环可能会更快。 (PTEST
是2 uops,不能与jcc
进行宏观融合。)