SSE2内在函数 - 比较2个包含4个int32的__m128i,看看有多少是相等的

时间:2014-07-08 19:09:08

标签: count comparison sse intrinsics sse2

我第一次潜入SSE2内在函数,我不知道该怎么做。

我想将4个int32与4个其他int32进行比较并计算有多少是相等的。 所以我读了我的前4个int32,在__m128i中设置它们,为第二个设置做同样的事情,并使用_mm_cmpeq_epi32进行比较。

这应该导致__m128i包含4个int32,每个都是0xffffffff或0,具体取决于整数是否相等。

但是我不知道如何从生成的__m128i到 count 指定实际上相等的数量。

有人能指出我正确的方向吗?

代码,我将它拼凑在一起:

        int* source = blah;
        int* reference = otherblah;

        // Load the 4 source int32's (they are actually 4 int32s apart)
        __m128i first_4_int32s = _mm_set_epi32(*(source + 12), *(source + 8), *(source + 4), *(source));

        // Load the 4 source int32's (also actually 4 int32s apart)
        __m128i second_4_int32s = _mm_set_epi32(*(reference + 12), *(reference + 8), *(reference + 4), *(reference));

        // Compare the int32's
        __m128i result = _mm_cmpeq_epi32(first_4_int32s, second_4_int32s);

        // Perform magic here that counts whether 0, 1, 2, 3 or all 4 ints were equal ?!?!

1 个答案:

答案 0 :(得分:0)

您可以将比较结果与1的向量进行比较,以创建零和1的向量。然后使用水平添加操作来计算它们。这是一些可能性。

#include "stdio.h"
#include "stdint.h"
#include "intrin.h"

//----------------------------------------------------------------------------
// non-SSE method (reference for result check)
static int method0 (__m128i value)
    {
    int index, total = 0;
    uint32_t *buffer = (void *) &value;

    for (index = 0; index < 4; index++)
        total += buffer [index] == 0xFFFFFFFF;
    return total;
    }

//----------------------------------------------------------------------------
//
// horizontalAddBytes - return integer total of all 16 bytes in xmm argument
//
static int horizontalAddBytes (__m128i byteArray)
   {
   __m128i total;
   const __m128i zero = _mm_setzero_si128 ();

   total = _mm_sad_epu8 (byteArray, zero);
   return _mm_cvtsi128_si64 (_mm_add_epi32 (total, _mm_shuffle_epi32 (total, 0xAA)));
   }

//----------------------------------------------------------------------------
// requires SSE2
static int method1 (__m128i value)
    {
    return horizontalAddBytes (_mm_srli_epi32 (value, 31));
    }

//----------------------------------------------------------------------------
// requires SSE3
static int method2 (__m128i value)
    {
    __m128 count;
    const __m128 mask = _mm_set1_ps (1);
    count = _mm_and_ps (_mm_castsi128_ps (value), mask);
    count = _mm_hadd_ps (count, count);
    count = _mm_hadd_ps (count, count);
    return _mm_cvtss_si32 (count);
    }

//----------------------------------------------------------------------------
// requires SSSE3
static int method3 (__m128i value)
    {
    __m128i count;
    count = _mm_srli_epi32 (value, 31);
    count = _mm_hadd_epi32 (count, count);
    count = _mm_hadd_epi32 (count, count);
    return _mm_cvtsi128_si32 (count);
    }

//----------------------------------------------------------------------------

static void createTestData (uint32_t *data, int mask)
    {
    int index;
    for (index = 0; index < 4; index++)
        data [index * 4] = (mask & (1 << index)) != 0;
    }

//----------------------------------------------------------------------------

int main (void)
    {
    int index1, index2, expected, result1, result2, result3;
    uint32_t source [16];
    uint32_t reference [16];

    for (index1 = 0; index1 < 16; index1++)
        for (index2 = 0; index2 < 16; index2++)
            {
            __m128i first_4_int32s, second_4_int32s, result;
            createTestData (source, index1);
            createTestData (reference, index2);

            // Load the 4 source int32's (they are actually 4 int32s apart)
            first_4_int32s = _mm_set_epi32(*(source + 12), *(source + 8), *(source + 4), *(source));

            // Load the 4 source int32's (also actually 4 int32s apart)
            second_4_int32s = _mm_set_epi32(*(reference + 12), *(reference + 8), *(reference + 4), *(reference));

            // Compare the int32's
            result = _mm_cmpeq_epi32(first_4_int32s, second_4_int32s);

            expected = method0 (result);
            result1 = method1 (result);
            result2 = method2 (result);
            result3 = method3 (result);
            if (result1 != expected) printf ("method1, index %d,%d expected %d, actual %d\n", index1, index2, expected, result1);
            if (result2 != expected) printf ("method2, index %d,%d expected %d, actual %d\n", index1, index2, expected, result2);
            if (result3 != expected) printf ("method3, index %d,%d expected %d, actual %d\n", index1, index2, expected, result3);
            }

    return 0;
    }

//----------------------------------------------------------------------------