SIMD: более общая функция перемешивания - PullRequest
0 голосов
/ 28 октября 2019

Я думаю, что функция SIMD shuffle не настоящая shuffle для int32_t, если левая и правая части будут перетасованы отдельно.

Я хочу, чтобы настоящая функция тасования была следующей:

Предполагается, что мы получили __m256i и хотим перетасовать 8 int32_t.

__m256i to_shuffle = _mm256_set_epi32(17, 18, 20, 21, 25, 26, 29, 31);

const int imm8 = 0b10101100;

__m256i shuffled _mm256_shuffle(to_shuffle, imm8);

Я надеюсь, что shuffled = {17, 20, 25, 26, -, -, -, -}, где - представляет не релевантное значение, и они могутбудь что угодно. Поэтому я надеюсь, что int в позиции с установленным битом с 1 будет помещен в shuffled.

(В нашем случае: 17, 20, 25, 26 сидят в позициях с1 в imm8).


Предлагает ли Intel такую ​​функцию? Как можно эффективно реализовать такую ​​функцию?


РЕДАКТИРОВАТЬ: - могли быбыть проигнорированнымТребуется только int с установленным битом 1.

1 Ответ

1 голос
/ 29 октября 2019

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

Как можно эффективно реализовать такую ​​функцию?

В этом случае с AVX2 vpermd (_mm256_permutevar8x32_epi32). Ему нужен управляющий вектор, а не немедленный, для хранения 8 селекторов для 8 выходных элементов. Таким образом, вам придется загрузить константу и использовать ее в качестве операнда управления.

Поскольку вы заботитесь только о нижней половине выходного вектора, ваша векторная константа может составлять только __m128i, экономя пространство. vmovdqa xmm, [mem] распространяется на ноль в соответствующий вектор YMM. Вероятно, неудобно писать это в C с внутренними признаками, но _mm256_castsi128_si256 должно работать. Или даже _mm256_broadcastsi128_si256, потому что широковещательная нагрузка будет такой же дешевой. Тем не менее, некоторые компиляторы могут преобразовать его в фактическую 32-байтовую константу в памяти, выполняя постоянное распространение. Если вы знаете ассемблер, вывод компилятора часто разочаровывает.

Если вы хотите использовать в своем источнике фактическое целочисленное растровое изображение, вы, возможно, могли бы использовать шаблоны C ++ для преобразования этого во время компиляции в правильную векторную константу. Библиотека векторных классов Агнера Фога (теперь Apache-licensed, ранее GPL) имеет некоторые связанные вещи, такие как превращение целочисленных констант в одну смесь или последовательность команд смешивания в зависимости от константы и того, какая целевая ISA поддерживается,используя шаблоны C ++. Но его шаблон shuffle принимает список индексов, а не растровое изображение.

Но я думаю, вы пытаетесь спросить, почему / как x86 shuffle разработаны так, как они есть.


Является ли такая функция, предлагаемая Intel,?

Да, в аппаратном обеспечении с AVX512F (плюс AVX512VL для использования на 256-битных векторах).

Вы ищете vpcompressd, векторно-элементный эквивалент BMI2 pext. (Но он принимает управляющий операнд как значение регистра маски, а не как непосредственную константу.) Свойство имеет вид
__m256i _mm256_maskz_compress_epi32( __mmask8 c, __m256i a);
Он также доступен в версии, которая сливается с основанием существующего вектора вместо обнуленияверхние элементы.


в качестве немедленного тасования, №

Все тасования x86 используют управляющий операнд с индексами в источнике, а не растровое изображение каких элементов сохранить. (За исключением vpcompressd/q и vpexpandd/q). Или они используют неявный элемент управления, такой как, например, _mm256_unpacklo_epi32, который чередует 32-битные элементы с 2-х входов (внутренняя в нижней и верхней половинах).

Если вы собираетесь предоставить перемешивание сОперанд управления вообще, обычно наиболее полезно, если какой-либо элемент может оказаться в любой позиции. Таким образом, выходные данные не должны быть в том же порядке, что и входные. Ваше сжатие в случайном порядке не обладает этим свойством.

Кроме того, наличие исходного индекса для каждого элемента вывода - это то, что естественным образом требуется аппаратному обеспечению в случайном порядке. Насколько я понимаю, каждый выходной элемент питается своим собственным MUX (мультиплексором), где MUX принимает N входных элементов и один двоичный селектор, чтобы выбрать, какой из них вывести. (И, конечно, такой же ширины, как ширина элемента.) См. Где находится VPERMB в AVX2? для более подробного обсуждения построения мультиплексоров.

Наличие операнда управления в каком-то другом форматечем список селекторов потребует предварительной обработки, прежде чем он может быть передан на аппаратное перемешивание.

Для немедленного, формат представляет собой либо 2x1-битные или 4x2-битные поля, либо счетчик сдвига байтов для_mm_bslli_si128 и _mm_alignr_epi8. Или индекс + обнуление битовой маски для insertps. Там нет никаких SIMD инструкций с непосредственным шире, чем 8 бит. Предположительно, это упрощает аппаратные декодеры.

(или 1x1-бит для vextractf128 xmm, ymm, 0 or 1, что в ретроспективе было бы лучше, если бы не было немедленного. Использование с 0 всегда хуже, чем vmovdqa xmm, xmm. Хотя AVX512 использует тот же код операции для vextractf32x4 с префиксом EVEX для непосредственного 1x2-бита, так что, возможно, это имело некоторое преимущество для сложности декодера. В любом случае, нет немедленных тасовок с полями селектора шире, чем 2 бита , потому что 8x 3-бит будет 24 бита.)

Для более широких перетасовок 4x2, например, _mm256_shuffle_ps (vshufps ymm, ymm, ymm, imm8), один и тот же шаблон селектора 4x2-бит используется повторно для обеих полос. Для более широких перетасовок 2x1 на линии, таких как _mm256_shuffle_pd (vshufpd ymm, ymm, ymm, imm8), мы получаем 4x 1-битных непосредственных полей, которые все еще выбирают на линии.

Существуют тасовки, пересекающие полосыс 4x 2-битными селекторами vpermq и vpermpd. Они работают точно так же, как pshufd xmm (_mm_shuffle_epi32), но с 4x элементами qword в 256-битном регистре вместо 4x элементов dword в 128-битном регистре.


Что касается сужения / толькозабота о части вывода:

Обычному немедленному требованию потребуется 4x 3-битных селектора для каждого индекса одного из 8x 32-битных исходных элементов. Но гораздо более вероятно, что 8x 3-битные селекторы = 24 бита, потому что зачем разрабатывать команду тасования, которая может когда-либо записывать только половину ширины вывода? (Кроме vextractf128 xmm, ymm, 1).

Общая парадигма для более гранулярных тасов состоит в том, чтобы взять управляющий вектор, , а не какое-нибудь броское непосредственное кодирование.

AVX512 сделалдобавьте некоторые сужающие тасовки, такие как VPMOVDB xmm/[mem], x/y/zmm, которые усекают (или насыщают со знаком / без знака) 32-битные элементы до 8-битных. (И все другие комбинации размеров доступны).

Они интересны, потому что они доступны с памятью destination . Возможно, это вызвано тем, что некоторые процессоры (например, Xeon Phi KNL / KNM) не имеют AVX512VL, поэтому они могут только использовать инструкции AVX512 с векторами ZMM. Тем не менее, они имеют AVX1 и 2, так что вы можете сжать их в xmm reg и использовать обычное VEX-кодированное хранилище. Но он позволяет создавать узкое хранилище с байтовой маской с AVX512F, что было бы возможно только с AVX512BW, если бы у вас были упакованные данные в регистре XMM.

Существуют некоторые 2-входные тасовки, такие как shufps, которыеобрабатывать нижнюю и верхнюю половину выходного сигнала отдельно, например, нижнюю половину выходного сигнала можно выбрать из элементов первого источника, верхнюю половину выходного сигнала можно выбрать из элементов второго регистра источника.

...