SIMD - как сложить значения из 2ух вектором одного типа
Подскажите пожалуйста, как можно сложить значения из вектором одного и тоже типа, но сами значения, которых занимает разное кол-во байт в этих векторах.
Вот для примера:
int main()
{
//--------------------------------------------------------------
int my_int_sequence[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
__m128i my_int_sequence_m128i_1 = _mm_loadu_si128((__m128i*) & my_int_sequence[0]);
__m128i my_int_sequence_m128i_2 = _mm_loadu_si128((__m128i*) & my_int_sequence[4]);
__m128i my_int_sequence_m128i_3 = _mm_loadu_si128((__m128i*) & my_int_sequence[8]);
__m128i my_int_sequence_m128i_4 = _mm_loadu_si128((__m128i*) & my_int_sequence[12]);
//--------------------------------------------------------------
//-----------------------------------------------------------------------
char my_char_mask[16] = { 1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,1 };
__m128i my_char_mask_my_m128i = _mm_loadu_si128((__m128i*) &my_char_mask[0]);
//-----------------------------------------------------------------------
}
То есть я имею массив значений int в массиве my_int_sequence - и так как все 16 значений int не поместятся в один вектор __m128i, я загружаю эти значения по 4 значения в 4-е вектора __m128i.
Так же я имею массив из 16 байт, который так же загрузил в вектор my_char_mask_my_m128i.
И вот теперь хочу каждому 4 байтовому значению векторов my_int_sequence_m128i_x - прибавить, как бы соответствующее однобайтовое значение из вектора my_char_mask_my_m128i.
Проблема очевидно в том, что мне нужно сложить, как бы разные размерности. Возможно ли такое ?
Возможно мне нужно каждый байт вектора my_char_mask_my_m128i - как то трансформировать в 4 байта ?
Ответы (1 шт):
Я смотрю, вы уже частично нашли ответ: Что делает эта SIMD инструкция?.
Только я бы всё таки рекомендовал использовать тут _mm_cvtepi8_epi32, так как тут складываются знаковые int со знаковыми char.
Принцип прост: расширняем char до int, складываем их, сдвигаем маску на 4 байта вправо. И так 4 раза.
#include <stdio.h>
#include <x86intrin.h>
void show_sequence(const char* pstrMsg, int* pSeq);
void show_mask(const char* pstrMsg, char* pMask);
int main()
{
int my_int_sequence[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
char my_char_mask[16] = { 1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,1 };
show_sequence("Source sequence", my_int_sequence);
show_mask( "Characters mask", my_char_mask);
__m128i my_int_sequence_m128i_1 = _mm_loadu_si128((__m128i*)&my_int_sequence[0]);
__m128i my_int_sequence_m128i_2 = _mm_loadu_si128((__m128i*)&my_int_sequence[4]);
__m128i my_int_sequence_m128i_3 = _mm_loadu_si128((__m128i*)&my_int_sequence[8]);
__m128i my_int_sequence_m128i_4 = _mm_loadu_si128((__m128i*)&my_int_sequence[12]);
__m128i my_char_mask_my_m128i = _mm_loadu_si128((__m128i*)my_char_mask);
my_int_sequence_m128i_1 = _mm_add_epi32(my_int_sequence_m128i_1, _mm_cvtepi8_epi32(my_char_mask_my_m128i));
my_char_mask_my_m128i = _mm_bsrli_si128(my_char_mask_my_m128i, 4);
my_int_sequence_m128i_2 = _mm_add_epi32(my_int_sequence_m128i_2, _mm_cvtepi8_epi32(my_char_mask_my_m128i));
my_char_mask_my_m128i = _mm_bsrli_si128(my_char_mask_my_m128i, 4);
my_int_sequence_m128i_3 = _mm_add_epi32(my_int_sequence_m128i_3, _mm_cvtepi8_epi32(my_char_mask_my_m128i));
my_char_mask_my_m128i = _mm_bsrli_si128(my_char_mask_my_m128i, 4);
my_int_sequence_m128i_4 = _mm_add_epi32(my_int_sequence_m128i_4, _mm_cvtepi8_epi32(my_char_mask_my_m128i));
_mm_store_si128((__m128i*)&my_int_sequence[0], my_int_sequence_m128i_1);
_mm_store_si128((__m128i*)&my_int_sequence[4], my_int_sequence_m128i_2);
_mm_store_si128((__m128i*)&my_int_sequence[8], my_int_sequence_m128i_3);
_mm_store_si128((__m128i*)&my_int_sequence[12], my_int_sequence_m128i_4);
show_sequence("Result sequence", my_int_sequence);
return 0;
}
void show_sequence(const char* pstrMsg, int* pSeq)
{
printf("%s: {", pstrMsg);
for (char i=0; i<15; ++i)
printf("%2d, ", pSeq[i]);
printf("%2d}\n", pSeq[15]);
}
void show_mask(const char* pstrMsg, char* pMask)
{
printf("%s: {", pstrMsg);
for (char i=0; i<15; ++i)
printf("%2d, ", (int)pMask[i]);
printf("%2d}\n", (int)pMask[15]);
}
Source sequence: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
Characters mask: { 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1}
Result sequence: { 1, 1, 3, 4, 4, 6, 6, 8, 9, 10, 10, 12, 12, 14, 14, 16}