Инструкции SSE: байт + короткий

у меня очень длинные байтовые массивы, которые нужно добавить в целевой массив типа short (или int). Существует ли такая инструкция SSE? Или, может быть, их набор ?

2 ответов


вам нужно распаковать каждый вектор 8-битных значений в два вектора 16-битных значений, а затем добавить их.

__m128i v = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
__m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); // vl = { 7, 6, 5, 4, 3, 2, 1, 0 }
__m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); // vh = { 15, 14, 13, 12, 11, 10, 9, 8 }

здесь v является вектором 16 x 8 битных значений и vl, vh - это два распакованных вектора 8 x 16 битных значений.

обратите внимание, что я предполагаю, что 8-битные значения без знака, поэтому при распаковке до 16 бит высокий байт установлен в 0 (т. е. без расширения знака).

если вы хотите суммировать много этих векторов и получить 32-битный результат тогда полезный трюк-использовать _mm_madd_epi16 С множителем 1, например,

__m128i vsuml = _mm_set1_epi32(0);
__m128i vsumh = _mm_set1_epi32(0);
__m128i vsum;
int sum;

for (int i = 0; i < N; i += 16)
{
    __m128i v = _mm_load_si128(&x[i]);
    __m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0));
    __m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0));
    vsuml = _mm_add_epi32(vsuml, _mm_madd_epi16(vl, _mm_set1_epi16(1)));
    vsumh = _mm_add_epi32(vsumh, _mm_madd_epi16(vh, _mm_set1_epi16(1)));
}
// do horizontal sum of 4 partial sums and store in scalar int
vsum = _mm_add_epi32(vsuml, vsumh);
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8));
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4));
sum = _mm_cvtsi128_si32(vsum);

Если вам нужно подписать-расширить свои байтовые векторы вместо нулевого расширения, используйте pmovsxbw (_mm_cvtepi8_epi16). В отличие от инструкций по распаковке hi/lo, вы можете использовать pmovsx только из нижней половины/четверти/восьмой части регистра src.

вы можете pmovsx непосредственно из памяти, хотя, хотя внутренние компоненты делают это действительно неуклюжим. Поскольку пропускная способность shuffle более ограничена, чем пропускная способность нагрузки на большинстве процессоров, вероятно, предпочтительнее делать две нагрузки + pmovsx, чем делать одну нагрузку + три тасует.