Преобразование упакованных 64-разрядных чисел в упакованные 8-разрядные целые числа со знаком насыщения с использованием AVX512 - PullRequest
0 голосов
/ 30 января 2020

Я ищу решение для насыщения упакованных 64-разрядных целых чисел в 8-разрядные целые числа. Посмотрел на _mm256_cvtepi64_epi8, но вместо насыщения он усекает, что приводит к нежелательному выводу.

Моя программа выглядит следующим образом:

int main()
{
    __m256i a, b, c;
    __m128i d;

    a = _mm256_set1_epi64x(127);
    b = _mm256_set1_epi64x(1);
    c = _mm256_add_epi64x(a, b);
    d = _mm256_cvtepi64_epi8(c);
}

Я ожидаю, что вывод (d) будет содержать четыре 127 (насыщенный), однако программа выдает четыре элемента -128 (усечено от 128).

1 Ответ

5 голосов
/ 30 января 2020

_mm256_cvtepi64_epi8 - это AVX512. (В частности, AVX512VL; 512-битная версия AVX512F). Вы отметили это, но ваш (оригинальный) заголовок только сказал AVX.

В любом случае, ваши варианты включают в себя выполнение насыщенного сложения в первую очередь с _mm256_adds_epi8, так что вы можете иметь в 8 раз больше элементов на вектор.

(И, как обсуждалось в комментариях, для умножения 8x8 => 8-битного насыщения, вы можете просто захотеть, чтобы распаковка на линии переместилась на _mm256_mullo_epi16, и упаковать пары результатов обратно в линию _mm256_packs_epi16 (vpacksswb). Несмотря на то, что распаковка в пределах дорожки с расширением знака неудобна, поэтому вы можете рассмотреть vpmovsx. В любом случае, вам определенно не нужно расширять более 16-битных элементов; int16_t может содержать полное произведение двух int8_t без переполнения.)


Или, чтобы сделать это так, как вы просили, AVX512 имеет подписанные и неподписанные версии насыщенных инструкций преобразования с понижением, наряду с найденной версией усечения. VPMOVQB, VPMOVSQB и VPMOVUSQB все задокументированы вместе.

__m128i _mm256_cvtsepi64_epi8(__m256i a); делает насыщение со знаком. Он доступен в версии с источником __m512i и в версии, которая хранится непосредственно в памяти (опционально как хранилище в маске).

(версия магазина не более эффективна на основных процессорах, но она позволяла KNL / KNM (в котором отсутствует AVX512BW) для узких хранилищ с байтовой маской.)


Не расширяйте ваши данные до 64-битных элементов, если в этом нет необходимости. Это 1/8-ая часть работы на вектор по сравнению с 8-битными элементами, и умножение 32x32 => 32-битных и 64x64 => 64-битных SIMD требует 2 моп на инструкцию на Intel, начиная с Haswell.


Другой вариант - упаковать 2 вектора -> 1 вектор той же ширины, что и 2 входа, но они работают только с инструкциями по пакетированию внутри линии. например, _mm256_packs_epi16, как указано выше. Они доступны только для крыс размером 10: 1 ios, а не от 64 или 32 до 8 за один шаг. (Так что это еще одна причина избегать слишком большого расширения).

Но если вы посмотрите на общее количество перемешиваний, чтобы получить N байтов выходных данных, оно будет немного впереди. например, для 4 входных векторов вам нужно 2 + 1 тасования вместо 4, чтобы сузить от 32 до 8 бит. (И, возможно, 4-й случайный случай, если вам нужно исправить внутреннюю линию, если вы не смогли передать им инструкции с чередованием данных нечетным / четным в 128-битных каналах). Вы должны взглянуть на общую картину того, сколько перемешиваний (или, возможно, других инструкций, таких как AND или AVX512 байтовое маскирование) требуется для распаковки и перепаковки.

2: 1 имеет преимущество ведя к более широким магазинам, если вы даже сохраняете результаты. Если нет, то это еще большее преимущество по сравнению с новыми инструкциями AVX512 1-> 1, где вам понадобятся тасования, чтобы объединить их в 256-битный вектор.

...