c - 最佳 SSE 无符号 8 位比较

标签 c x86 sse simd sse4

我正在尝试找到使用 SSE(最高 SSE 4.2)执行 8 位无符号比较的最多方法。

我正在处理的最常见情况是比较 > 0U,例如

_mm_cmpgt_epu8(v, _mm_setzero_si128())                // #1

(当然也可以认为是对非零的简单测试。)

但我也对更一般的情况感兴趣,例如

_mm_cmpgt_epu8(v1, v2)                                // #2

第一种情况可以用 2 条指令实现,使用各种不同的方法,例如与 0 比较,然后反转结果。第二种情况通常需要 3 条指令,例如从两个操作数中减去 128 并执行带符号的比较。 (有关各种 3 指令解决方案,请参阅 this question。)

理想情况下,我正在寻找针对#1 的单指令解决方案和针对#2 的双指令解决方案。如果这些都不可能,那么我也很想知道在现代英特尔 CPU(Sandy Bridge、Ivy Bridge、Haswell)上,各种可能的 2 条或 3 条指令实现中哪一种最有效。


到目前为止案例 #2 的最佳实现:

    1. 与无符号最大值比较并反转结果:

#define _mm_cmpgt_epu8(v0, v1) \ _mm_andnot_si128(_mm_cmpeq_epi8(_mm_max_epu8(v0, v1), v1), \ _mm_set1_epi8(-1))

两条算术指令 + 一条按位 = 1.33 吞吐量。

    1. 反转两个参数的符号位(== 减去 128)并使用带符号的比较:

#define _mm_cmpgt_epu8(v0, v1) \ _mm_cmpgt_epi8(_mm_xor_si128(v0, _mm_set1_epi8(-128)), \ _mm_xor_si128(v1, _mm_set1_epi8(-128)))

一个算术指令 + 两个按位 = 1.16 吞吐量。


案例 #1 的最佳实现,源自上述案例 #2 的实现:

  • 1.

#define _mm_cmpgtz_epu8(v0) \ _mm_andnot_si128(_mm_cmpeq_epi8(v0, _mm_set1_epi8(0)), \ _mm_set1_epi8(-1))

一条算术指令 + 一条按位 = 0.83 吞吐量。

  • 2.

#define _mm_cmpgtz_epu8(v0) \ _mm_cmpgt_epi8(_mm_xor_si128(v0, _mm_set1_epi8(-128)), \ _mm_set1_epi8(-128)))

一条算术指令 + 一条按位 = 0.83 吞吐量。

最佳答案

有一个例子来自 Simd Library :

    const __m128i K_INV_ZERO = SIMD_MM_SET1_EPI8(0xFF);//_mm_set1_epi8(-1);

    SIMD_INLINE __m128i NotEqual8u(__m128i a, __m128i b)
    {
        return _mm_andnot_si128(_mm_cmpeq_epi8(a, b), K_INV_ZERO);
    }

    SIMD_INLINE __m128i Greater8u(__m128i a, __m128i b)
    {
        return _mm_andnot_si128(_mm_cmpeq_epi8(_mm_min_epu8(a, b), a), K_INV_ZERO);
    }

    SIMD_INLINE __m128i GreaterOrEqual8u(__m128i a, __m128i b)
    {
        return _mm_cmpeq_epi8(_mm_max_epu8(a, b), a);
    }

    SIMD_INLINE __m128i Lesser8u(__m128i a, __m128i b)
    {
        return _mm_andnot_si128(_mm_cmpeq_epi8(_mm_max_epu8(a, b), a), K_INV_ZERO);
    }

    SIMD_INLINE __m128i LesserOrEqual8u(__m128i a, __m128i b)
    {
        return _mm_cmpeq_epi8(_mm_min_epu8(a, b), a);
    }

关于c - 最佳 SSE 无符号 8 位比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33824300/

相关文章:

c - 如何使用 WinPCap 获取以太网标签

将 char* 转换为 char &

gcc - assembly 中的位测试 (BT)

arm - ARM NEON 的 SSE _mm_movemask_epi8 等效方法

c - char 数组声明形式之间的区别

c - 尽管RAW套接字和HDRINCL,IP源地址仍然由系统填充

c++ - double 型上的 SSE vector 运算

c - SSE:使用_mm_add_epi32看不到加速

gcc - 当需要额外的堆栈对齐时,gcc 奇怪的堆栈操作是怎么回事?

c++ - float 学执行时间