【发布时间】:2017-02-23 06:43:48
【问题描述】:
如标题所示,如果一个 256 位 SIMD 寄存器是:
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
如何有效地获取第一个非零元素的索引(即第一个1
的索引2
)?最直接的方法是存入内存,一一检查,但可能成本很高。有什么好主意吗?
【问题讨论】:
标签: x86 bit-manipulation simd intrinsics avx
如标题所示,如果一个 256 位 SIMD 寄存器是:
0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
如何有效地获取第一个非零元素的索引(即第一个1
的索引2
)?最直接的方法是存入内存,一一检查,但可能成本很高。有什么好主意吗?
【问题讨论】:
标签: x86 bit-manipulation simd intrinsics avx
movmskps
或pd
获得每个 dword 或 qword 1 位,而不是每个字节,如果这使您的位扫描 - > 索引计算更有效,例如如果您想要一个元素偏移量而不是字节偏移量。 )~
运算符,asm NOT 指令)以在位图中为非零元素获取 1如果只有一个可能的非零值(如 1
),则 PCMPEQB 会针对该向量的一个向量,因此您以后无需反转它。
如果是这种情况,请首先考虑将数据存储在位图中,以将缓存占用空间减少 8 倍。然后您只需 TZCNT 阵列的 64 位块。 (或者使用 SIMD 搜索第一个非零向量,然后 TZCNT 搜索它的第一个非零元素,如果您希望在第一个设置位之前有多个零 qword。就像memcmp
用于查找不匹配字节位置。)
刚刚注意到内在标签。 asm指令参考手册在每个条目的底部列出了相关的C内在函数,您可以通过asm助记符搜索Intel's intrinsics finder。 (有关链接,请参阅x86 标签 wiki)。
【讨论】:
LZCNT
而不是 TZCNT
。 Acutally asm 指令更好,无论如何都要感谢内在信息。正如您所提到的,只有一个可能的非零值,但是您知道如何在装配级别实现cache footprint
问题吗?
_mm_set_epi8
,最后一个 arg 到 _mm_setr_epi8
)进入整数掩码的 LSB。 TZCNT / BSF 首先查看低位,因此使用它们从低地址扫描到高地址(如果向量是从内存中加载的)。如果您想从另一个方向扫描,请使用 LZCNT 或 BSR(它们会给出不同的结果)。
tzcnt rax, [my_bitmap + rsi]
或其他任何东西,看看从 8*rsi 开始的 64 位中是否有任何命中(因为内存仍然是字节寻址的,除非你使用 BT/BTR/BTS 指令,但不要t 因为它们对内存操作数非常慢,请参阅agner.org/optimize)
PCMPEQ
或PMOVMSKB
,然后每64位TZCNT(即执行4条TZCNT指令)位图?如果是这样,TZCNT 会执行 4 次,这样会更快吗?为什么cache footprint
减少了 8 倍?