Как добиться 8-битного madd с помощью SSE2

Чтение из официального внутреннего справочника Intel C ++,

SSE 2 имеет следующую команду

__m128i _mm_madd_epi16(__m128i a, __m128i b)

Умножает 8-значные 16-разрядные целые числа из a на 8-значные 16-разрядные целые числа из b.
Добавляет результаты 32-разрядного целого числа со знаком попарно и упаковывает 32-разрядное целое число со знаком 4
Результаты.

в то время как SSE 3 имеет

__m128i _mm_maddubs_epi16 (__m128i a, __m128i b)

Умножение байтов со знаком и без знака, добавление пары горизонтальных слов со знаком, упаковка
насыщенные подписанные слова.

Так как я работаю с 8-битными пикселями, и я должен использовать только SSE 2 (цель — старая архитектура), мне нужно 8 бит Мэдд инструкция.
Как мне поступить с этим?

2

Решение

Надеюсь, что это работает — у меня нет компилятора здесь. Но даже если я что-то упустил, вы должны получить общее представление.

РЕДАКТИРОВАТЬ: Спасибо @Peter Cordes за указание, что _mm_setzero_si128 лучше использовать напрямую.

inline __m128i _mm_madd_epi8_SSE2(const __m128i & a, const __m128i & b)
{
// a = 0x00 0x01 0xFE 0x04 ...
// b = 0x00 0x02 0x80 0x84 ...

// To extend signed 8-bit value, MSB has to be set to 0xFF
__m128i sign_mask_a  = _mm_cmplt_epi8(a, _mm_setzero_si128());
__m128i sign_mask_b  = _mm_cmplt_epi8(b, _mm_setzero_si128());

// sign_mask_a = 0x00 0x00 0xFF 0x00 ...
// sign_mask_b = 0x00 0x00 0xFF 0xFF ...

// Unpack positives with 0x00, negatives with 0xFF
__m128i a_epi16_l    = _mm_unpacklo_epi8(a, sign_mask_a);
__m128i a_epi16_h    = _mm_unpackhi_epi8(a, sign_mask_a);
__m128i b_epi16_l    = _mm_unpacklo_epi8(b, sign_mask_b);
__m128i b_epi16_h    = _mm_unpackhi_epi8(b, sign_mask_b);

// Here - valid 16-bit signed integers corresponding to the 8-bit input
// a_epi16_l = 0x00 0x00 0x01 0x00 0xFE 0xFF 0x04 0x00 ...

// Get the a[i] * b[i] + a[i+1] * b[i+1] for both low and high parts
__m128i madd_epi32_l = _mm_madd_epi16(a_epi16_l, b_epi16_l);
__m128i madd_epi32_h = _mm_madd_epi16(a_epi16_h, b_epi16_h);

// Now go back from 32-bit values to 16-bit values & signed saturate
return _mm_packs_epi16(madd_epi32_l, madd_epi32_h);
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]