测试 xmm 寄存器中的任何字节是否为 0

Liq*_*iqs 3 string x86 assembly simd sse2

我目前正在自学 SIMD 并且正在编写一个相当简单的字符串处理子程序。然而,我仅限于 SSE2,这使我无法利用 ptest 找到空终端。

我目前试图找到空终端的方式使我的 SIMD 循环有 >16 条指令,这违背了使用 SIMD 的目的 - 或者至少使它不那么值得。

//Check for null byte
pxor xmm4, xmm4
pcmpeqb xmm4, [rdi]                                   //Generate bitmask
movq rax, xmm4
test rax, 0xffffffffffffffff                          //Test low qword
jnz .Lepilogue
movhlps xmm4, xmm4                                    //Move high into low qword
movq rax, xmm4
test rax, 0xffffffffffffffff                          //Test high qword
jz .LsimdLoop                                         //No terminal was found, keep looping
Run Code Online (Sandbox Code Playgroud)

我想知道在没有 ptest 的情况下是否有任何更快的方法可以做到这一点,或者这是否是最好的方法,我将不得不再优化循环的其余部分。

注意:我确保输入使用 SIMD 的循环的字符串地址是 16B 对齐的,以允许对齐的指令。

And*_*hev 6

您可以使用_mm_movemask_epi8(pmovmskb指令) 从比较结果中获取位掩码(结果掩码包含向量中每个字节的最高有效位)。然后,测试是否有任何字节为零意味着测试掩码中的 16 位中的任何一个是否为非零。

pxor xmm4, xmm4
pcmpeqb xmm4, [rdi]
pmovmskb eax, xmm4
test eax, eax          ; ZF=0 if there are any set bits = any matches
jnz .found_a_zero
Run Code Online (Sandbox Code Playgroud)

发现有任何匹配的载体后,你可以找到的第一个匹配位置bsf eax,eax得到位,指数位掩码,这也是在16字节向量的字节索引。

或者,你可以检查所有字节匹配(例如,像你在memcmp / STRCMP做)用pcmpeqb/ pmovmskb/cmp eax, 0xffff检查所有位设置,而不是检查至少1位集。

  • @Liqs:`pmovmskb` 在所有 x86 CPU 上都很便宜。仅 1 uop(对于 Intel 上的端口 0),以及大约 3 个周期的延迟。请参阅 https://agner.org/optimize/ 或 https://www.uops.info/table.html?search=pmovms&cb_lat=on&cb_tp=on&cb_uops=on&cb_ports=on&cb_HSW=on&cb_SKX=on&cb_ICL=on&cb_ZEN%2B=on&cb_ZEN2=on&cb_measurements=开&cb_base=开&cb_sse=开。如果此基准测试比您的 movq/movq/or 方式慢,您可能会遇到其他性能问题。也许[JCC勘误表](/sf/ask/4271125421/#61016915) (4认同)
  • @Liqs:它执行的“指令”比您的答案甚至问题中的代码多,这是不合理的。您确定每次都测量相同的输入数据,并仅对您的进程的“perf stat -e task-clock,cycles:u,instructions:u”用户空间指令进行事件计数吗? (2认同)