SSE2 直接测试 xmm 位掩码而不使用 'pmovmskb'

SSE2 test xmm bitmask directly without using 'pmovmskb'

考虑一下我们有这个:

....
pxor            xmm1, xmm1
movdqu          xmm0, [reax]
pcmpeqb         xmm0, xmm1
pmovmskb        eax,  xmm0
test            ax , ax
jz              .zero
...

有什么方法可以不使用 'pmovmskb' 并直接从 xmm0 测试位掩码(检查它是否为零)? 此操作是否有任何 SSE 说明?

事实上,我正在搜索类似 'ptest xmm0, xmm0' 的操作,但在 SSE2 中……不是 SSE4

使用ptest:

ptest xmm0, xmm0
jz .zero

ptest a, b 如果 ab 为零,则设置 ZF,如果 a ∧ ¬ b 为零,则设置 CF。

但请注意,ptest 需要 SSE 4.1。

否则,我想你的做法是as good as it gets

通常不值得在 pcmpeqb 结果上使用 SSE4.1 ptest xmm0,xmm0,尤其是在分支时。

pmovmskb 是 1 uop,并且 cmptest 可以与 jnz 宏融合到 Intel 和 AMD CPU 上的另一个单 uop。 使用 pmovmsk + test/jcc

在 pcmpeqb 结果上分支的总计 2 微指令

但是 ptest 是 2 微指令,它的第二微指令 不能 宏与后续分支融合。 使用 ptest + jcc.

在向量上分支的总计 3 微指令

当您可以直接使用 ptest 而无需 pcmp 时,这就是收支平衡,例如测试整个向量中的任何/所有位(或使用掩码,一些位)。如果您将它用于 cmov 或 setcc 而不是分支,则实际上是一场胜利。这也是代码大小的胜利,即使相同数量的 uops。


您可以分摊对多个向量的检查。 例如por 将一些向量放在一起,然后检查所有字节是否为零。或者 pminub 一些向量在一起,然后检查 any 零。 (像 strlen 和 strchr 这样的 glibc 字符串函数使用这个技巧来并行检查整个缓存行的向量,然后在离开循环后找出它来自哪里。)

您可以合并 pcmpeq 结果而不是原始输入,例如对于 memchr。在这种情况下,您可以使用 pand 而不是 pminubany 输入具有零的元素中获得零。一些 CPU 运行 pand 在比 pminub 更多的端口上,因此向量 ALU 的竞争较少。


另请注意,pmovmskb 零扩展到 EAX;您可以 test eax,eax 而不是浪费前缀字节来仅测试 AX。