Прежде всего, _mm512_reduce_add_epi64
не соответствует одной инструкции AVX512, но генерирует последовательность тасовок и дополнений.
Чтобы уменьшить значения 64 epu8
до 8 epi64
значений, обычно одноиспользует инструкцию vpsadbw
(SAD = сумма абсолютных разностей) против нулевого вектора, который затем может быть уменьшен еще больше:
long reduce_add_epu8(__m512i a)
{
return _mm512_reduce_add_epi64(_mm512_sad_epu8(a, _mm512_setzero_si512()));
}
Попробуйте выполнить на Годболте: https://godbolt.org/z/1rMiPH. К сожалению, ни GCC, ни Clang не способны оптимизировать функцию, если она используется с _mm512_set1_epi16(1)
.
Для epi8
вместо epu8
, вам нужно сначала добавить 128 к каждому элементу(или xor с 0x80
), затем уменьшите его с помощью vpsadbw
и в конце вычтите 64*128
(или 8*128
на каждом промежуточном 64-битном результате).[Обратите внимание, что это было неправильно в предыдущей версии этого ответа]
Для epi16
Я предлагаю взглянуть на то, какие инструкции _mm512_reduce_add_epi32
и _mm512_reduce_add_epi64
генерируют и откуда выводят, что делать.
В целом, как предположил @Mysticial, от вашего контекста зависит, каков наилучший подход к сокращению.Например, если у вас очень большой массив int64
и вы хотите получить сумму как int64
, вам нужно просто сложить их вместе по пакетам и только в самом конце уменьшить один пакет до одного int64
.