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

标签 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:

它是正确的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/

相关文章:

C++ 赋值给隐式转换的左值

c++ - 将 DLL 放在其他目录中

c++ - 我是否有在C++中使用std::condition_variable将线程置于死锁的风险?

c++ - 使用指针用 sse 添加两个 4 vector

c++ - 如何使用SSE2实现8bit madd

c++ - 使用继承信号解决 Q_PROPERTY NOTIFY

c - 为什么 gets() 不起作用?

c - 使用数组汇总调查结果

C:用 double 除以 double 输出 lnf

c++ - 帮助 GCC 进行自动矢量化