Tru*_*uLa 7 c c++ sse simd avx
如果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:
@ zx485正确地观察到原始问题不够明确.我一直在寻找任何"连续"的解决方案.
0 1 0 1 0 1 0 1...上面的示例应该导致以下任一情况:
0将是终止字节,结果可能是002 004 006 008 010 012 014 016 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在对原始帖子的评论中所建议的,可能的解决方案之一是首先创建一个掩码(例如with 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
Run Code Online (Sandbox Code Playgroud)
只是为了完整起见:本答案未涵盖第二种方法,即连续方法。