Какова самая быстрая обратная функция _mm_movemask_ps ()? - PullRequest
3 голосов
/ 16 июня 2019

В Как выполнить инверсию _mm256_movemask_epi8 (VPMOVMSKB)? , OP запрашивает инверсию _mm256_movemask_epi8, но для SSE _mm_movemask_ps() существует более простая версия?Это лучшее, что я могу придумать, что не так уж и плохо.

__m128 movemask_inverse(int x) {
    __m128 m = _mm_setr_ps(x & 1, x & 2, x & 4, x & 8);
    return _mm_cmpneq_ps(m, _mm_setzero_ps());
}

1 Ответ

3 голосов
/ 17 июня 2019

Эффективность вашей маски обратного хода сильно зависит от компилятора.С gcc требуется около 21 инструкций .

Но с clang -std=c99 -O3 -m64 -Wall -march=nehalem код векторизуется хорошо, и результаты на самом деле не так уж плохи:

movemask_inverse_original:              # @movemask_inverse_original
        movd    xmm0, edi
        pshufd  xmm0, xmm0, 0           # xmm0 = xmm0[0,0,0,0]
        pand    xmm0, xmmword ptr [rip + .LCPI0_0]
        cvtdq2ps        xmm1, xmm0
        xorps   xmm0, xmm0
        cmpneqps        xmm0, xmm1
        ret

Тем не менеевам не нужно целое число cvtdq2ps для преобразования с плавающей запятой.Более эффективно вычислять маску в целочисленной области и приводить (без преобразования) результаты для последующего плавания.В ответе Питера Кордеса: есть ли обратная инструкция к инструкции movemask в intel avx2? , обсуждаются многие идеи по делу AVX2.Большинство из этих идей могут быть использованы в той или иной форме и для случая SSE.Решение LUT и решение ALU подходят для вашего случая.

Решение ALU с собственными характеристиками:

__m128 movemask_inverse_alternative(int x) {
    __m128i msk8421 = _mm_set_epi32(8, 4, 2, 1);
    __m128i x_bc = _mm_set1_epi32(x);
    __m128i t = _mm_and_si128(x_bc, msk8421);
    return _mm_castsi128_ps(_mm_cmpeq_epi32(x_bc, t));
}

Генерируемая сборка с gcc -std=c99 -O3 -m64 -Wall -march=nehalem:

movemask_inverse_alternative:
        movdqa  xmm1, XMMWORD PTR .LC0[rip]  % load constant 8, 4, 2, 1
        movd    xmm2, edi                    % move x from gpr register to xmm register
        pshufd  xmm0, xmm2, 0                % broadcast element 0 to element 3, 2, 1, 0
        pand    xmm1, xmm0                   % and with 8, 4, 2, 1
        pcmpeqd xmm0, xmm1                   % compare with 8, 4, 2, 1
        ret

movdqa, вероятно, выводится из цикла после включения функции.

...