计算 128 位 avx 向量中唯一值的数量,或检测所有元素是否相等?

count number of unique values in a 128bit avx vector, or detecting if all elements are equal?

我正在优化我的代码库中的热路径,并且我已转向矢量化。请记住,我对所有这些 SIMD 东西还是很陌生。这是我要解决的问题,使用非 SIMD

实现
inline int count_unique(int c1, int c2, int c3, int c4)
{
    return 4 - (c2 == c1)
             - ((c3 == c1) || (c3 == c2))
             - ((c4 == c1) || (c4 == c2) || (c4 == c3));
}

-O3编译后的汇编输出:

count_unique:
        xor     eax, eax
        cmp     esi, edi
        mov     r8d, edx
        setne   al
        add     eax, 3
        cmp     edi, edx
        sete    dl
        cmp     esi, r8d
        sete    r9b
        or      edx, r9d
        movzx   edx, dl
        sub     eax, edx
        cmp     edi, ecx
        sete    dl
        cmp     r8d, ecx
        sete    dil
        or      edx, edi
        cmp     esi, ecx
        sete    cl
        or      edx, ecx
        movzx   edx, dl
        sub     eax, edx
        ret

将 c1,c2,c3,c4 存储为 16 字节整数向量时,如何完成这样的操作?

好的,我已经“简化”了问题,因为当我使用唯一计数时,唯一的情况是它是否为 1,但这与检查所有元素是否相同相同,可以是通过将输入与自身进行比较来完成,但使用 _mm_alignr_epi8 函数移动了一个元素(4 个字节)。

inline int is_same_val(__m128i v1) {
    __m128i v2 = _mm_alignr_epi8(v1, v1, 4);
    __m128i vcmp = _mm_cmpeq_epi32(v1, v2);
    return ((uint16_t)_mm_movemask_epi8(vcmp) == 0xffff);
}

对于您的简化问题(测试所有 4 条车道是否相等),我会稍微不同地做,方法如下。这样只需要3条指令就可以完成测试。

// True when the input vector has the same value in all 32-bit lanes
inline bool isSameValue( __m128i v )
{
    // Rotate vector by 4 bytes
    __m128i v2 = _mm_shuffle_epi32( v, _MM_SHUFFLE( 0, 3, 2, 1 ) );
    // The XOR outputs zero for equal bits, 1 for different bits
    __m128i xx = _mm_xor_si128( v, v2 );
    // Use PTEST instruction from SSE 4.1 set to test the complete vector for all zeros
    return (bool)_mm_testz_si128( xx, xx );
}