Я пытаюсь реализовать линейный поиск по массиву uint64, используя инструкции SSE. У меня все работает для uint16 и uint32, но я получаю ошибки компилятора для кода uint64 (linux, gcc - см. спецификации в конце).
Я пытаюсь сравнить 64-битные числа 2x2, а затем каким-то образом перевести результат в индекс для моего массива. Это хорошо работает с uint32 (кредиты идут на http://schani.wordpress.com/2010/04/30/linear-vs-binary-search/):
#include <xmmintrin.h>
#include <smmintrin.h>
typedef ham_u64_t vec2uint64 __attribute__ ((vector_size (16)));
typedef ham_u32_t vec4uint32 __attribute__ ((vector_size (16)));
typedef float vec4float __attribute__ ((vector_size (16)));
typedef ham_u16_t vec8uint16 __attribute__ ((vector_size (16)));
typedef ham_u8_t vec16uint8 __attribute__ ((vector_size (16)));
// ...
vec4uint32 v1 = _mm_loadu_si128((const __m128i *)&data[start + i + 0]);
vec4uint32 v2 = _mm_loadu_si128((const __m128i *)&data[start + i + 4]);
vec4uint32 v3 = _mm_loadu_si128((const __m128i *)&data[start + i + 8]);
vec4uint32 v4 = _mm_loadu_si128((const __m128i *)&data[start + i + 12]);
vec4uint32 cmp0 = _mm_cmpeq_epi32(key4, v1);
vec4uint32 cmp1 = _mm_cmpeq_epi32(key4, v2);
vec4uint32 cmp2 = _mm_cmpeq_epi32(key4, v3);
vec4uint32 cmp3 = _mm_cmpeq_epi32(key4, v4);
vec8uint16 pack01 = __builtin_ia32_packssdw128(cmp0, cmp1);
vec8uint16 pack23 = __builtin_ia32_packssdw128(cmp2, cmp3);
vec16uint8 pack0123 = __builtin_ia32_packsswb128(pack01, pack23);
int res = __builtin_ia32_pmovmskb128(pack0123);
if (res > 0) {
int czt = __builtin_ctz(~res + 1);
return (start + i + czt);
}
Вот что я придумал для uint64. Сравнение работает, я просто не знаю, что делать с результатами, а вызов __builtin_ia32_packssdw() не компилируется:
vec2uint64 v1 = _mm_loadu_si128((const __m128i *)&data[start + i + 0]);
vec2uint64 v2 = _mm_loadu_si128((const __m128i *)&data[start + i + 2]);
vec2uint64 cmp0 = _mm_cmpeq_epi64(key2, v1);
vec2uint64 cmp1 = _mm_cmpeq_epi64(key2, v2);
vec4uint32 pack01 = __builtin_ia32_packssdw(cmp0, cmp1); // error
vec4uint32 pack23 = _mm_set1_epi32(0);
vec16uint8 pack0123 = __builtin_ia32_packsswb128(pack01, pack23);
int res = __builtin_ia32_pmovmskb128(pack0123);
if (res > 0) {
int czt = __builtin_ctz(~res + 1);
return (start + i + czt);
}
Ошибка говорит:
error: cannot convert 'vec1uint64 {aka __vector(2) long unsigned int}'
to '__vector(2) int' for argument '1' to '__vector(4) short int
__builtin_ia32_packssdw(__vector(2) int, __vector(2) int)'
(Определения типов для vec2uint64 находятся вверху, в коде для uint32.)
Моя среда:
Linux ws4484 3.5.0-48-generic #72~precise1-Ubuntu SMP Tue Mar 11 20:09:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
Мой вопрос заключается не только в том, как я могу исправить ошибку компилятора, но если у кого-то есть лучшая идея получить индекс массива с совпадением, может быть, без всей упаковки?
Заранее спасибо!
__builtin_ia32_packssdw
, вместо более привычных_mm_packs_epi32
? Это делает работу с векторными типами намного более запутанной. - person Paul R   schedule 15.04.2014__m128i
для всех ваших векторных переменных и не беспокоиться о смешивании разных типов для 32-битных и 64-битных операций, которые, как вы видели, могут быть уродливыми. - person Paul R   schedule 15.04.2014