SSE - сравнить и поставить мое значение?

Я на этой странице встроенного руководства Intel.

Мой sse опыт довольно хрупкий.


Хорошо, у меня есть массив — действительно длинный — целых чисел с именем «источник».

Пример :

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

int source[] = {4,5,9,8}
int mask[] = {4,4,4,4}
int replacer[] = {3,3,3,3} 

Таким образом, окончательный исходный код должен выглядеть как {3,5,9,8}.

Я хотел бы добиться этого с помощью SSE ‹ 4.

Ближайшая инструкция, которая мне попалась, это _mm_cmpeq_epi32:

FOR j := 0 to 3 
i := j*32 dst[i+31:i] := ( a[i+31:i] == b[i+31:i] ) ? 0xFFFFFFFF : 0 
ENDFOR

Теперь я хотел бы заменить исходный массив моим значением или ничего не делать иначе:

FOR j := 0 to 3 
i := j*32 dst[i+31:i] := ( a[i+31:i] == b[i+31:i] ) ? my_mask_value_here : source_value_untouched
ENDFOR

Есть ли отдаленное достижение того, что я пытаюсь? Не могу понять даже при объединении разных инструкций..

Спасибо


person Jdarc    schedule 21.07.2015    source источник


Ответы (1)


Получив свою маску с помощью PCMPEQ, если у вас sse 4.1, то вы можете использовать специально предназначенную для этой цели инструкцию PBLENDVB. В противном случае вы можете использовать PAND, PANDN и POR для эмуляции. Также можно использовать MASKMOVDQU.

Вот исходный код, демонстрирующий 3 способа:

#include <stdio.h>
#include <x86intrin.h>

int main()
{
    int source[] = {4,5,9,8};
    int mask[] = {4,4,4,4};
    int replacer[] = {3,3,3,3};

    __m128i bitmask = _mm_cmpeq_epi32(*(__m128i*)source, *(__m128i*)mask);

    // manual version
    __m128i result = _mm_and_si128(*(__m128i*)replacer, bitmask);
    __m128i tmp = _mm_andnot_si128(bitmask, *(__m128i*)source);
    result = _mm_or_si128(result, tmp);
    printf("%d %d %d %d\n", *(int*)&result, *((int*)&result + 1), *((int*)&result + 2), *((int*)&result + 3));

    // maskmovdqu version
    result = *(__m128i*)source;
    _mm_maskmoveu_si128(*(__m128i*)replacer, bitmask, (char*)&result);
    printf("%d %d %d %d\n", *(int*)&result, *((int*)&result + 1), *((int*)&result + 2), *((int*)&result + 3));

    // sse 4.1 version
    result = _mm_blendv_epi8(*(__m128i*)source, *(__m128i*)replacer, bitmask);
    printf("%d %d %d %d\n", *(int*)&result, *((int*)&result + 1), *((int*)&result + 2), *((int*)&result + 3));
}
person Jester    schedule 21.07.2015
comment
Нет, maskmovq работает только для mmx, но его друг, maskmovdqu работает с sse, но пишет только в память. Хотя может быть полезно. - person Jester; 21.07.2015
comment
Сама страница, на которую вы ссылаетесь, показывает, что она работает только с mmx. _mm_maskmoveu_si128 является встроенным для maskmovdqu, но, как вы можете видеть, он принимает операнд памяти. - person Jester; 21.07.2015
comment
№ void _m_maskmovq (__m64 a, __m64 маска, char* mem_addr) #include xmmintrin.h Инструкция: maskmovq mm, mm CPUID Флаги: SSE - person Jdarc; 21.07.2015
comment
__m64 - это mmx, а не sse, даже если инструкция является частью набора sse. - person Jester; 21.07.2015
comment
ааа ок! Мой плохой тогда Шут - person Jdarc; 21.07.2015