比较两个__m128i值的总订单

时间:2019-05-28 11:39:39

标签: c++ x86 x86-64 simd intrinsics

我需要一种方法来比较C ++中类型为__m128i的任何值之间的总顺序。顺序的类型无关紧要,只要它在类型__m128i的所有值之间建立总顺序即可。因此,该比较可能不及128位整数之间的比较,或完全可以提供总顺序的其他东西。

我尝试使用__m128i运算符,但是没有返回<,而是似乎比较了bool(即SIMD)的矢量分量:

__m128i

另一种可能性是使用#include <emmintrin.h> inline bool isLessThan(__m128i a, __m128i b) noexcept { // error: cannot convert '__vector(2) long int' to 'bool' in return return a < b; } / memcmp或类似的方法,但这很可能不是最佳选择。针对至少具有SSE4.2和AVX2的现代Intel x86-64 CPU,我是否可以使用任何内在函数/指令进行此类比较?怎么做?

PS:已经问过类似的问题来检查相等性,而不是顺序:

1 个答案:

答案 0 :(得分:5)

你在这里。

inline bool isLessThan( __m128i a, __m128i b )
{
    /* Compare 8-bit lanes for ( a < b ), store the bits in the low 16 bits of the
       scalar value: */
    const int less = _mm_movemask_epi8( _mm_cmplt_epi8( a, b ) );

    /* Compare 8-bit lanes for ( a > b ), store the bits in the low 16 bits of the
       scalar value: */
    const int greater = _mm_movemask_epi8( _mm_cmpgt_epi8( a, b ) );

    /* It's counter-intuitive, but this scalar comparison does the right thing.
       Essentially, integer comparison searches for the most significant bit that
       differs... */
    return less > greater;
}

顺序不理想’coz pcmpgtb将这些字节视为带符号整数,但是您说这对用例并不重要。


更新:这里的版本稍慢,排序顺序为uint128_t

// True if a < b, for unsigned 128 bit integers
inline bool cmplt_u128( __m128i a, __m128i b )
{
    // Flip the sign bits in both arguments.
    // Transforms 0 into -128 = minimum for signed bytes,
    // 0xFF into +127 = maximum for signed bytes
    const __m128i signBits = _mm_set1_epi8( (char)0x80 );
    a = _mm_xor_si128( a, signBits );
    b = _mm_xor_si128( b, signBits );

    // Now the signed byte comparisons will give the correct order
    const int less = _mm_movemask_epi8( _mm_cmplt_epi8( a, b ) );
    const int greater = _mm_movemask_epi8( _mm_cmpgt_epi8( a, b ) );
    return less > greater;
}

我们通过将无符号输入范围移位到有符号(通过翻转高位=减去128)来建立无符号比较。