如果 SSE/AVX 寄存器的值使其所有字节都为 0 或 1,是否有任何方法可以有效地获取所有非零元素的索引?
例如,如果 xmm 值为 | r0=0 | r1=1 | r2=0 | r3=1 | r4=0 | r5=1 | r6=0 |...| r14=0 | r15=1 | 结果应该类似于 (1, 3, 5, ... , 15)。结果应放在另一个 _m128i 变量或 char[16] 数组中。
如果有帮助,我们可以假设寄存器的值是所有字节都是 0 或某个常量非零值(不一定是 1)。
我很想知道是否有针对该指令的指令,或者最好是 C/C++ 内在指令。在任何 SSE 或 AVX 指令集中。
编辑 1:
它是正确的observed by @zx485那个最初的问题还不够清楚。我一直在寻找任何“连续”的解决方案。
上面的示例 0 1 0 1 0 1 0 1...
应导致以下任一结果:
- 如果我们假设索引从 1 开始,那么
0
将是一个终止字节,结果可能是
002 004 006 008 010 012 014 016 000 000 000 000 000 000 000 000
- 如果我们假设负字节是终止字节,结果可能是
001 003 005 007 009 011 013 015 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
- 任何以连续字节形式给出的东西,我们可以将其解释为原始值中非零元素的索引
编辑 2:
确实如此 @harold和 @Peter Cordes在对原始帖子的评论中建议,一种可能的解决方案是首先创建一个掩码(例如使用 pmovmskb
)并检查那里的非零索引。但这会导致循环。
最佳答案
如果您希望结果数组被“压缩”,您关于方面的问题不清楚。我所说的“压缩”的意思是,结果应该是连续的。因此,例如对于 0 1 0 1 0 1 0 1...
,有两种可能性:
非连续的:
XMM0: 000 001 000 003 000 005 000 007 000 009 000 011 000 013 000 015
连续的:
XMM0: 001 003 005 007 009 011 013 015 000 000 000 000 000 000 000 000
连续方法的一个问题是:如何确定它是索引 0
还是终止值?
我为第一种非连续方法提供了一个简单的解决方案,它应该非常快:
.data
ddqZeroToFifteen db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
ddqTestValue: db 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1
.code
movdqa xmm0, xmmword ptr [ddqTestValue]
pxor xmm1, xmm1 ; zero XMM1
pcmpeqb xmm0, xmm1 ; set to -1 for all matching
pandn xmm0, xmmword ptr [ddqZeroToFifteen] ; invert and apply indices
只是为了完整起见:第二种方法,即连续方法,未包含在此答案中。
关于c++ - SSE/AVX 寄存器的非零字节索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35681201/