Подтвердить что ты не робот

SIMD/SSE: как проверить, что все векторные элементы отличны от нуля

Мне нужно проверить, что все векторные элементы отличны от нуля. До сих пор я нашел следующее решение. Есть лучший способ сделать это? Я использую gcc 4.8.2 в Linux/x86_64, инструкции до SSE4.2.

typedef char ChrVect __attribute__((vector_size(16), aligned(16)));

inline bool testNonzero(ChrVect vect)
{
    const ChrVect vzero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    return (0 == (__int128_t)(vzero == vect));
}

Обновление: приведенный выше код скомпилирован следующим кодом ассемблера (при компиляции как не-встроенная функция):

movdqa  %xmm0, -24(%rsp)
pxor    %xmm0, %xmm0
pcmpeqb -24(%rsp), %xmm0
movdqa  %xmm0, -24(%rsp)
movq    -24(%rsp), %rax
orq -16(%rsp), %rax
sete    %al
ret
4b9b3361

Ответ 1

С прямыми встроенными функциями SSE вы можете сделать это следующим образом:

inline bool testNonzero(__m128i v)
{
    __m128i vcmp = _mm_cmpeq_epi8(v, _mm_setzero_si128());
#if __SSE4_1__  // for SSE 4.1 and later use PTEST
    return _mm_testz_si128(vcmp, vcmp);
#else           // for older SSE use PMOVMSKB
    uint32_t mask = _mm_movemask_epi8(vcmp);
    return (mask == 0);
#endif
}

Я предлагаю посмотреть, что ваш компилятор в настоящее время генерирует для вашего существующего кода, а затем сравнить его с этой версией с использованием встроенных функций и посмотреть, есть ли существенная разница.

С SSE3 (clang -O3 -msse3) для приведенной выше функции я получаю следующее:

pxor    %xmm1, %xmm1
pcmpeqb %xmm1, %xmm0
pmovmskb    %xmm0, %ecx
testl   %ecx, %ecx

Версия SSE4 (clang -O3 -msse4.1) создает:

pxor    %xmm1, %xmm1
pcmpeqb %xmm1, %xmm0
ptest   %xmm0, %xmm0

Обратите внимание, что обнуление xmm1 обычно будет выведено из любого цикла, содержащего эту функцию, поэтому приведенные выше последовательности должны быть уменьшены на одну команду при использовании внутри цикла.