Как правило, никто не снимает маскировку с исключений FP, в противном случае вам понадобятся перестановки, например, для дублирования одного из элементов, чтобы верхний элемент делил то же самое деление, что и один из других элементов. Или есть другая известная безопасная вещь.
Возможно, вам удастся избежать только перетасовки делителя, если вы можете предположить, что в этом элементе дивиденд не равен NaN.
С AVX512 вы можете подавитьисключения для элемента, использующего маскирование нуля, но до этого момента такой функции не было. Также AVX512 позволяет вам переопределить режим округления + Подавить все исключения (SAE) без маскировки, чтобы вы могли сделать ближайший, даже явный, для получения SAE. Но это подавляет исключения для всех элементов.
Серьезно, не включайте исключения FP. Компиляторы едва ли / не знают, как оптимизировать безопасным способом, если количество исключений является видимым побочным эффектом. например, GCC -ftrapping-math
включен по умолчанию, но он не работает.
Я бы не подумал, что LLVM лучше;строгий FP по умолчанию, вероятно, все еще выполняет оптимизацию, которая могла бы дать один SIGFPE, где источник поднял бы 2 или 4. Может быть, даже оптимизации, которые поднимают 0, когда источник поднял бы 1, или наоборот, как GCC, сломанный и почти бесполезный по умолчанию. 1013 *
Включение исключений FP может быть полезно для отладки, однако, если вы ожидаете, что никогда не будет каких-либо исключений определенного типа. Но вы, вероятно, можете справиться со случайными ложными срабатываниями из инструкции SIMD, проигнорировав те с этим адресом источника.
Если есть компромисс между производительностью и корректностью исключений, большинство пользователей библиотекискорее, это максимизирует производительность.
Даже очистка, а затем проверка липких маскированных флагов FP с fenv
выполняется редко и требует использования контролируемых обстоятельств. У меня не было бы никаких ожиданий для вызова библиотечной функции, особенно если бы она не использовала SIMD.
Избегайте субнормалей в элементе мусора
Вы можетеполучить замедления от субнормалей (также известных как денормали), если в MXCSR не установлены FTZ и DAZ. (т. е. обычный случай, если вы не скомпилировали (эквивалент Rust) -ffast-math
.)
Создание NaN или + -Inf не требует дополнительного времени для типичного оборудования x86 с SSE/ AVX инструкции. (Интересный факт: NaN тоже медленный, с наследием математики x87 даже на современных HW). Так что можно _mm_or_ps
с результатом cmpps
создать NAN в некоторых элементах вектора, например, перед математической операцией. Или _mm_and_ps
, чтобы создать несколько нулей в делителе перед делением.
Но будьте осторожны с тем, какой мусор находится в вашем заполнении, потому что это может привести к ложным субнормалам. 0.0
и NaN (все), как правило, всегда безопасны.
Обычно избегайте горизонтальных вещей с SIMD. SIMD vec! = Геометрия vec.
Использование только 3 из 4 элементов вектора SIMD обычно является плохой идеей , поскольку обычно это означает, что вы используете один вектор SIMD для храненияодин вектор геометрии, вместо трех векторов с 4 x
координатами, 4 y
координатами и 4 z
координатами.
Перестановки / горизонтальные вещи в основном стоят дополнительных инструкций (за исключением широковещательных загрузок скаляраэто уже было в памяти), но вам часто нужно много тасовок, если вы используете SIMD таким образом. Есть случаи, когда вы не можете векторизовать множество вещей, но вы можете получить ускорение с помощью SIMD.
Если вы просто используете этот частичный вектор для оставшихся элементов операции нечетного размера, тогда здорово , один частичный вектор намного лучше, чем 3 скалярных итерации. Но большинство людей, спрашивающих об использовании только 3 из 4 векторных элементов, спрашивают, потому что они используют SIMD неправильно, например, добавление геометрического вектора в качестве вектора SIMD все еще дешево, но точечный продукт нуждается в тасованиях. См. https://deplinenoise.wordpress.com/2015/03/06/slides-simd-at-insomniac-games-gdc-2015/ для некоторых хороших вещей о том, как правильно использовать SIMD (SoA против AoS и т. Д.). Если вы уже знаете об этом и просто используете 3-элементные векторы для случая нечетного угла, а не для большей части работы, то это нормально.
Заполнение кратным ширине вектора обычно отлично подходит для нечетногоразмеры, но другой вариант для некоторых алгоритмов - это конечный вектор без выравнивания, который заканчивается в конце ваших данных. Хранилище с частичным перекрытием - это хорошо, если только это не алгоритм на месте, и вам не нужно беспокоиться о том, чтобы не выполнить элемент дважды. (Или о стойках пересылки магазина даже для идемпотентных операций, таких как маскирование и зажим AND).
Получение нулей бесплатно
Если у вас осталось только 2 float
элементов,movsd
load будет загружать + нулевое расширение в регистр XMM. Вы могли бы также заставить компилятор сделать это вместо movaps
.
В противном случае, если перемешать 3 скаляра, insertps
может обнулять элементы. Или вы могли знать нулевые старшие части регистров xmm из movss
загрузок из памяти. Таким образом, использование 0.0
в качестве части инициализатора вектора из скаляра (например, C ++ _mm_set_ps()
) может быть бесплатным для компилятора.
С AVX вы можете рассмотреть возможность использованиязамаскированная нагрузка, если вы беспокоитесь о том, что заполнение вызывает ненормальноеhttps://www.felixcloutier.com/x86/vmaskmov. Но это несколько медленнее, чем vmovaps
. А замаскированные магазины намного дороже на AMD, даже на Ryzen.