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

时间:2013-04-02 14:57:47

标签: c performance sse simd

我必须提取__m128i寄存器的非零值。 例如,我有一个带有八个无符号短路的向量。

__m128i vector {40, 0, 22, 0, 0, 0, 0, 8}

我想用最少量的SSE指令提取40,22和8。 然后,非零值将存储在非零值的数组中。

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

是否有可能对它们进行洗牌或提取和存储是否具有良好的内在性?

2 个答案:

答案 0 :(得分:2)

如果你看at this paper,作者会描述如何使用_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中。

答案 1 :(得分:2)

根据anjruu的回答,这是一个尚未经过任何方式测试的SSSE3版本:

; xmm0 = input
pxor xmm1, xmm1
pcmpeqb xmm1, xmm0
pmovmskb eax, xmm1
shl eax, 4
pshufb xmm0, [table + eax]

table当然是不同的,但不是很难解决,只要记住索引是“反转的” - 例如索引0对应没有零,0xFFFF对应全零。< / p>