На вашей векторной диаграмме самый верхний элемент слева или справа? Расположены ли XX
в старшем или младшем байте результата pmaddubsw
?
Чтобы получить результаты в младшем байте слова из входных данных в старшем байте каждого слова:
Используйте _mm_mulhi_epu16
, чтобы эффективно выполнять (v1 << 8) * (v2 << 8) >> 16
, получая результат в байте, противоположном входным словам. Поскольку вы говорите, что произведение строго меньше 256, вы получите 8-битный результат в младшем байте каждого 16-битного слова.
(Если ваши входы подписаны, используйте _mm_mulhi_epi16
, но тогда отрицательный результат будет расширен до 16 бит.)
Чтобы получить результаты в старшем байте слова из входных данных в младшем байте
Вам нужно изменить способ загрузки / создания одного из входов, чтобы вместо
MSB LSB | MSB LSB
v1_lo (00, 04, 00, 0e, 00, 04, 00, 04, 00, 0a, 00, 0f, 00, 05, 00, 01)
element# 15 14 13 12 ... 0
у вас есть это: (оба используют нотацию Intel, где левый элемент является наибольшим числом, поэтому вектор сдвигается как _mm_slli_epi128
смещение байтов влево на диаграмме).
MSB LSB | MSB LSB
v1_hi (04, 00, 0e, 00, 04, 00, 04, 00, 0a, 00, 0f, 00, 05, 00, 01, 00)
element# 15 14 13 12 ... 0
Если v2
все еще имеет ненулевые байты в верхней половине каждого элемента слова, просто _mm_mullo_epi16(v1_hi, v2)
, и вы получите (v1 * v2) << 8
бесплатно.
Если вы уже распаковываете байты с нулями для получения v1 и v2, распакуйте другой способ . Если вы использовали pmovzx
(_mm_cvtepu8_epi16
), то переключитесь на _mm_unpacklo_epi8(_mm_setzero_si128(), packed_v1 )
.
Если вы загружали эти векторы из памяти в этой форме, уже заполненной нулями, используйте смещение нагрузки без выравнивания на 1 байт, чтобы нули оказались в противоположном месте.
Если вы действительно хотите начать с входных байтов, которые не распакованы с нулями, я не думаю, что вы можете избежать этого. Или, если вы маскируете вместо распаковки (чтобы сохранить пропускную способность shuffle-port, используя вместо этого _mm_and_si128
), вам, вероятно, понадобится смещение куда-нибудь. Вы можете сдвинуть вместо маскирования в одну сторону, однако, используя v1_hi = _mm_slli_epi16(v, 8)
: сдвиг влево на 8 с гранулярностью слова выбьет оставивший младший байт обнуленным.