我正在尝试使用simd(AVX2或更早版本)查找字符的第一个实例,此处为“'”。我想使用_mm256_cmpeq_epi8,但是接着需要快速找到__m256i中是否有任何结果字节被设置为0xFF的方法。计划是使用_mm256_movemask_epi8将结果从字节转换为位,然后使用ffs获取匹配索引。使用_mm_movemask_epi8一次移出一部分是否更好?还有其他建议吗?
_mm256_cmpeq_epi8
-> _mm256_movemask_epi8
。据我所知,这至少是在Intel CPU上实现此操作的最佳方法。PMOVMSKB r32, ymm
与XMM 16字节版本的速度相同,因此拆分256b向量的两个通道并单独移动掩码,然后重新组合整数结果将导致巨大的性能损失。(来源: Agner Fog's instruction table. 请参阅x86标记wiki中的其他性能链接。)_mm256_movemask_epi8
的非零结果之后再执行ffs
,使循环内的代码尽可能高效。ffs
的结果上进行分支,给你一些测试输入是否为非零的测试,然后BSF,然后加1,然后比较和分支。与仅测试movemask结果相比,这显然是可怕的。)std::countr_zero
。它可以编译为单个tzcnt
,而不是ffs
的偏移1。由于您已经检查了掩码是否为非零,希望可以优化为单个(rep
)bsf
指令,如果不确定所有运行代码的CPU都支持tzcnt
。如果您可以假设目标CPU支持BMI1,通常可以对AVX2代码进行启用,以便您可以可靠地获得高效的tzcnt
。)另请参阅:
strchr-avx2.S
(Woboq.org具有用于文件名/符号的有用搜索的漂亮源代码浏览器)。 memchr-avx2.S
glibc的memchr使用PMAXUB而不是POR。我不确定这是否出于某些神秘微架构原因而有用,但它在大多数CPU上运行时使用的端口更少。也许这是期望的,以避免与其他资源发生冲突?我不知道,似乎很奇怪,因为它与PCMPEQB竞争。
PMOVMSKB r,v
被列为2-3c延迟。在Haswell上, VMOVMSKPS/D r32, ymm
为2c延迟,但xmm版本为3c延迟!这很令人惊讶。你在哪里看到256b版本更慢?你确定ymm版本在Skylake上不是更快吗? - Peter Cordes_mm256_movemask_epi8
仍然是你能做的最好的选择。 你用两个单独的半部分所能做的任何事情都不可能像只使用一个VPMOVMSKB r32, ymm那样好。在上半车道上使用128b movmsk需要先将其提取到寄存器的低128b中,使用3个周期的延迟车道交叉洗牌,例如VEXTRACTF128。 - Peter Cordesffs
)敏感。分支预测的推测执行意味着每个条件分支指令都是单独的依赖链。即,控制依赖关系不是数据依赖关系。JCC上标志输入的较短延迟不会影响吞吐量,只有在检测到分支错误预测之前的延迟才能被检测到。 - Peter Cordes
strchr
(或者如果你知道长度则为memchr
),并且可能已经存在 SIMD 优化的实现可用。另外,请注意对于尚未缓存的字符串,你的函数很可能会受到内存带宽的限制。 - Paul R'\0'
(实际上是strlen
),你也许可以进行修改。 - Paul R