Это 2-х линейные haddps
инструкции в низком и верхнем 128-битных каналах. Большинство инструкций AVX на самом деле не расширяют операцию до 256-битной, они выполняют 2 отдельные операции внутри линии . Это делает AVX трудным в использовании, особенно без AVX2 для перестановок с пересечением полос с зернистостью менее 128 бит!
Но это экономит транзисторы против, например, создание vpshufb
одного 32-байтового тасования вместо 2-х 16-байтовых тасов. AVX2 даже не обеспечивает, что: Где VPERMB в AVX2? (приходится ждать AVX512VBMI).
(связано: лучший способ перестановки по линиям AVX? Кроме того, AVX512 добавляет множество гибких перестановок, пересекающих полосы, но версии инструкций SSE / AVX AXV512, такие как vhaddps zmm
, все еще находятся в полоса. См. также Дают ли 128-битные операции перекрестной полосы в AVX512 лучшую производительность? )
Для цепочки AVX2 vpack*
обычно требуется vpermq
, чтобы выполнить исправление при пересечении полосы движения в конце, если только вы не собираетесь снова распаковывать линию. Таким образом, в большинстве случаев 2-кратные тасовки в полосе хуже, чем полная операция с 256-битной шириной, но это не то, что мы получаем от AVX. Часто все еще требуется ускорение перехода на 256-битную вектор со 128, даже если для исправления поведения на линии требуются дополнительные тасовки, но это часто означает, что это не 2-кратное ускорение, даже если нет узких мест в памяти.
vpalignr
, вероятно, является наиболее вопиющим примером того, что 2x 128-битные версии одного и того же шаффла сами по себе не являются полезным строительным блоком; Я не могу вспомнить, видел ли я когда-нибудь сценарий использования двух отдельных оконных байтовых данных. О, на самом деле да, если вы кормите его с помощью vperm2i128
Как эффективно объединить два вектора с помощью AVX2? (версия VPALIGNR с пересечением полосы движения) , но обычно невыровненные нагрузки лучше подходят для процессоров, поддерживающих AVX2.
Варианты использования для (v)haddps
очень ограничены
Может быть, Intel планировала превратить haddps
в инструкцию с одним занятием в какой-то момент после введения ее в SSE3, но этого не произошло.
Варианты использования включают в себя вещи типа транспонирования и добавления , в которых вам все равно придется перетасовывать оба входа для вертикального addps
. например Наиболее эффективный способ получения __m256 горизонтальных сумм из 8 исходных __m256 векторов включает vhaddps
. (Плюс AVX1 vperm2f128
для исправления поведения на линии.)
Многие люди ошибочно полагают, что это хорошо для горизонтальных сумм одного вектора, но и 128, и 256-битные (v)haddps
декодируют до 2x случайных чисел, чтобы подготовить входные векторы для вертикального (v)addps
упа. Для горизонтальной суммы вам понадобится только 1 случайный шаг на добавление. ( Самый быстрый способ сделать горизонтальную векторную сумму с плавающей запятой на x86 )
Сначала сужение до 128-битного (с vextractf128
/ vaddps
) обычно является лучшим первым шагом, если вы не хотите, чтобы результат транслировался на каждый элемент, и вы не находитесь на процессоре AMD (где 256-битный вектор операции расшифровываются как минимум до 2 моп или более для перестановок, пересекающих полосу движения). (v)haddps xmm
или целое число vphaddd
полезно для горизонтальных сумм, если вы оптимизируете размер кода, а не скорость, например мой ответ с машинным кодом x86 на вопрос по коду для гольфа "Вычислите среднее значение двух чисел".
Неразрушающие операнды назначения AVX также устраняют некоторые преимущества наличия многопользовательской инструкции. Без AVX иногда вы не можете избежать movaps
для копирования регистра перед его уничтожением, поэтому выпечка 2x shuffle + add to 1 фактически спасла мопс от необходимости делать это вручную с movaps
+ shufps
.