Для уменьшения-добавления просто делайте тасования и добавления в линию (vmovshdup
/ vaddps
/ vpermilps imm8
/ vaddps
), как в Самый быстрый способ сделать горизонтальную векторную сумму с плавающей точкой на x86 для получения горизонтальной суммы в каждой 128-битной полосе, а затем vpermps
для перетаскивания нужных элементов в низ.Или vcompressps
с постоянной маской, чтобы сделать то же самое, необязательно с назначением памяти.
После упаковки в один вектор у вас есть обычное SIMD 128-битное добавление.
Если ваши массивы на самом деле больше 16, вместо vpermps
вы можете vpermt2ps
взять каждый 4-й элемент из каждого из двух векторов-источников, настроив вас на выполнение +=
часть с x[]
256-битными векторами.(Или снова объединить с другим тасованием в 512-битные векторы, но это, вероятно, станет узким местом для пропускной способности тасования в SKX).
В SKX vpermt2ps
- это всего лишь один моп, с пропускной способностью 1c / задержкой 3c,так что это очень эффективно для того, насколько это мощно.На KNL он имеет пропускную способность 2c, хуже, чем vpermps
, но, возможно, все же стоит.(KNL не имеет AVX512VL, но для добавления к x[]
с 256-битными векторами вы (или компилятор) можете использовать AVX1 vaddps ymm
, если хотите.)
См. https://agner.org/optimize/для таблиц инструкций.
Для нагрузки:
Это делается внутри цикла или многократно?(т. е. можете ли вы сохранить вектор управления тасованием в регистре? Если это так, вы можете
- сделать 128-> 512 трансляций с
VBROADCASTF32X4
(один моп дляпорт загрузки). - выполните перемешивание на линии с
vpermilps zmm,zmm,zmm
для широковещательной передачи различного элемента в каждой 128-битной полосе. (Должен быть отделен от широковещательной загрузки, посколькуисточник памяти vpermilps
может иметь источник m512
или m32bcst
(инструкции обычно имеют гранулярность широковещательной передачи памяти = размер элемента, к сожалению, в некоторых случаях, таких как этот, когда это совсем не полезно. И vpermilps
принимает операнд памяти как операнд памяти, а не исходные данные.)
Это немного лучше, чем vpermps zmm,zmm,zmm
, потому что у перемешивания есть задержка в 1 цикл вместо 3 (вкл.Skylake-avx512).
Даже вне цикла загрузка вектора с произвольным управлением все еще может быть лучшим выбором.