SSE/AVX寄存器的非零字节索引

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...上面的示例应该导致以下任一情况:

  • 如果我们假设索引从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)并检查那里的非零索引.但这将导致循环.

zx4*_*485 5

如果您希望结果数组被“压缩”,您的问题不清楚。我所说的“压缩”是指结果应该是连续的。因此,例如对于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)

只是为了完整起见:本答案未涵盖第二种方法,即连续方法。