使用SSE从_m128i寄存器中提取非零值

4
我需要提取一个__m128i寄存器中的非零值。例如,我有一个包含八个无符号short整数的向量。
__m128i vector {40, 0, 22, 0, 0, 0, 0, 8}

我希望用最少量的SSE指令提取40、22和8。非零值将被存储在一个非零值数组中。

{40, 22, 8, more values from different vectors ... }

是否可能对它们进行洗牌,或者有没有良好的内在机制可以提取和存储?


我们可以假设使用 SSE 4 吗? - Paul R
是的,我们可以,但我更喜欢SSSE3。 - martin s
非零值的顺序需要被保留吗? - Paul R
是的,保持非零值的顺序很重要。 - martin s
2个回答

3

如果您查看这篇论文,作者描述了如何使用_mm_cmpestrm指令实现基本所需的操作。他们算法的核心是这样的(我稍微修改了一下以满足您的需求,而不是他们的需求):

__m128i res_v = _mm_cmpestrm(
    vector, 
    8, 
    mm_setzero_si128(),
    8,
    _SIDD_UWORD_OPS|_SIDD_CMP_EQUAL_ANY|_SIDD_BIT_MASK|_SIDD_NEGATIVE_POLARITY);
int r = _mm_extract_epi32(res_v, 0);

__m128i p = _mm_shuffle_epi8(vector, sh_mask[r]);

如果按照论文所述构建查找表sh_mask,那么p应该具有非零元素(无需重新排序)后跟零元素。r中设置的位数将告诉您非零元素的数量。
_mm_cmpestrm在SSE4中,不幸的是。

哇,我不知道这个命令,而且使用 sh_mask 的技巧真的很酷。非常感谢。 - martin s

2

根据anjruu的答案,这里有一个SSSE3版本,尚未进行任何测试:

; xmm0 = input
pxor xmm1, xmm1
pcmpeqb xmm1, xmm0
pmovmskb eax, xmm1
shl eax, 4
pshufb xmm0, [table + eax]
当然有所不同,但并不难理解,只需要记住索引是“反转”的-例如,索引0对应于没有零,0xFFFF对应于所有零。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接