c – SSE/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,4,6,7,8,9,10,11,12,13,14,15
  ddqTestValue:                 db 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&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...