당신과 0과 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;
}
//----------------------------------------------------------------------------
이와 같이 수집 된로드를 수행하는 것은 성능이 나쁜 방법입니다. 인접한 데이터를 사용할 수없는 경우 스칼라 코드를 사용하는 것이 좋습니다. –
네, 여기에서하는 일은 순차적으로하는 것보다 훨씬 느립니다. 따라서 메모리 액세스 패턴을 변경할 수 없다면 시간을 낭비하지 마십시오. – Mysticial
당신은 단지 4 개의 값, 또는 전체 묶음 그러나 한 번에 단지 4를 위해 이것을하고 있습니까? 알려 주시면 솔루션을 기꺼이 작성하겠습니다. 그건 제외하고, 여기에 몇 가지 점이 있습니다. 실제로 4 개의 값만있는 경우 _mm_packs_epi32, _mm_packs_epi16, _mm_movemask_epi8, 룩업 테이블을 고려해보십시오. 그러나 스칼라 버전이 더 빠를 수도 있습니다. 그럼에도 불구하고 _mm_set_epi32를 사용하면 안되므로 _mm_load_ps 또는 _mm_loadu_ps를 사용하여 4 개의 값을 모두로드해야합니다. 자, 당신이 4 튜플의 전체 무리에 대해 이것을 할 예정이라면 __m128i에서 4 개의 합계를 유지할 수 있습니다. – Apriori