我想获取 256 位向量之间的 8 位垂直 SIMD 比较的结果,并将这些位打包到每个 32 位元素的最低字节中,以便查找vpshufb最低字节。这对于 AVX-512 来说并不是非常困难(&如果使用 512 位向量,则用屏蔽移动替换 ):
__m256i cmp_8_into_32(__m256i a, __m256i b) {\n return _mm256_popcnt_epi32(_mm256_cmpeq_epi8(a, b)\n & _mm256_set1_epi32(0xff0f0301 /* can be any order */));\n}\nRun Code Online (Sandbox Code Playgroud)\n这是 3 个 uops,假设完美调度,根据 uops.info\xe2\x80\x94,吞吐量为 1 还不错。可惜,vpopcntdAVX2 中没有。在那里进行此操作的最佳方法是什么?我能想到的最好的方法是屏蔽索引 7,8 和 15,16 处的位对,然后执行两个常量vpsrld和一个vpor. 所以这是 6 uops,吞吐量为 2.5 左右。不错,但我想知道是否有更好的东西。
根据 chtz 的评论(谢谢!),我意识到这实际上相当简单:
\n__m256i cmp_8_into_32_1(__m256i a, __m256i b) {\n const __m256i weights = _mm256_set1_epi32(0x08040201);\n const __m256i all_n1 = _mm256_set1_epi16(-0x1);\n\n __m256i cmp = _mm256_cmpeq_epi8(a, b);\n __m256i hsum16 = _mm256_maddubs_epi16(weights, cmp);\n\n return _mm256_madd_epi16(hsum16, all_n1);\n}\nRun Code Online (Sandbox Code Playgroud)\nPeter Cordes 的建议节省了额外的vpand. 两个乘法\xe2\x80\x93add 指令都在端口 0 或 1 上运行,因此这与原始基于 popcount 的解决方案具有相同的吞吐量,尽管延迟约为 11 而不是 5。
使用 1 乘法:
__m256i cmp_8_into_32(__m256i a, __m256i b) {
__m256i cmp = _mm256_cmpeq_epi8(a, b);
__m256i msk = _mm256_and_si256(cmp, _mm256_set1_epi32(0x08040201));
__m256i hsum = _mm256_madd_epi16(msk, _mm256_set1_epi8(1));
return _mm256_srli_epi16(hsum, 8);
}
Run Code Online (Sandbox Code Playgroud)
_mm256_mullo_epi32不使用32 位乘法 ( ),因为它很慢。
如果“通道内”不需要结果,那么可以_mm256_packs_epi16在比较后立即使用 a 来一次处理两倍的数据。如果您不需要所有可能的状态(假设我们不关心最低字节匹配),那么您可以为每条指令执行 4 倍的操作。如果查找的结果vpshufb聚集在一起,那么可能还有其他可能的优化......
| 归档时间: |
|
| 查看次数: |
407 次 |
| 最近记录: |