Суммирование 8-битных целых чисел в __mm512 со встроенными AVX - PullRequest
0 голосов
/ 22 марта 2019

AVX512 предоставляет нам встроенные элементы для суммирования всех ячеек в векторе __mm512.Однако некоторые их аналоги отсутствуют: пока нет _mm512_reduce_add_epi8.

_mm512_reduce_add_ps     //horizontal sum of 16 floats
_mm512_reduce_add_pd     //horizontal sum of 8 doubles
_mm512_reduce_add_epi32  //horizontal sum of 16 32-bit integers
_mm512_reduce_add_epi64  //horizontal sum of 8 64-bit integers

В основном мне нужно реализовать MAGIC в следующем фрагменте.

__m512i all_ones = _mm512_set1_epi16(1);
short sum_of_ones = MAGIC(all_ones);
/* now sum_of_ones contains 32, the sum of 32 ones. */

Наиболее очевидный способ - использовать _mm512_storeu_epi8 и суммировать элементы массива вместе, но это будет медленно, плюс это может сделать недействительным кеш.Я полагаю, что существует более быстрый подход.

Бонусные баллы за реализацию _mm512_reduce_add_epi16.

1 Ответ

4 голосов
/ 22 марта 2019

Прежде всего, _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.

...