【问题标题】:Extract non-zero values from _m128i register with SSE使用 SSE 从 _m128i 寄存器中提取非零值
【发布时间】:2013-03-23 22:36:08
【问题描述】:

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

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

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

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

是否可以将它们洗牌,或者是否有一个好的内在提取和存储?

【问题讨论】:

  • 我们可以假设 SSE 4 吗?
  • 是的,我们可以,但我更喜欢 SSSE3。
  • 非零值的顺序是否需要保留?
  • 是的,保持非零值的顺序很重要。

标签: c performance sse simd


【解决方案1】:

根据 anjruu 的回答,这里有一个未经任何测试的 SSSE3 版本:

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

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

【讨论】:

    【解决方案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 中。

    【讨论】:

    • 哇,我不知道这个命令,使用 sh_mask 的技巧真的很酷。非常感谢。
    猜你喜欢
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多