(я предполагаю, что вы сразу же получили назад (селектор для 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
, которыеобрабатывать нижнюю и верхнюю половину выходного сигнала отдельно, например, нижнюю половину выходного сигнала можно выбрать из элементов первого источника, верхнюю половину выходного сигнала можно выбрать из элементов второго регистра источника.