Не хватает AVX-512 для масок?
В руководстве Intel по встроенным функциям перечислены некоторые встроенные функции для инструкций маски AVX-512 K*, но некоторые из них отсутствуют:
- KSHIFT {L / R}
- KADD
- KTEST
В руководстве разработчика Intel утверждается, что встроенные функции не нужны, поскольку они автоматически генерируются компилятором. Как это сделать, хотя? Если это означает, что типы __mmask* могут рассматриваться как обычные целые числа, это имело бы большой смысл, но тестирование mask << 4
кажется, заставляет компилятор переместить маску в обычный регистр, сдвинуть ее, а затем вернуться к маске. Это было проверено с использованием последних GCC Годболта и ICC с -O2 -mavx512bw
,
Также интересно отметить, что встроенные имеют дело только с __mmask16
и не другие типы. Я не много тестировал, но похоже, что ICC не против принять неверный тип, но GCC, кажется, пытается и убедиться, что в маске есть только 16 бит, если вы используете встроенные функции.
Не смотрю ли я на правильные внутренние особенности вышеприведенных инструкций, а также на другие варианты типа __mmask*, или есть другой способ добиться того же, не прибегая к встроенной сборке?
1 ответ
Документация Intel, гласящая, что "нет необходимости, поскольку они автоматически генерируются компилятором", на самом деле верна. И все же, это неудовлетворительно.
Но чтобы понять, почему это так, нужно взглянуть на историю AVX512. Хотя ни одна из этих сведений не является официальной, это явно подразумевается на основе доказательств.
Причина, по которой состояние масок вошло в тот беспорядок, которым они сейчас являются, возможно, в том, что AVX512 "раскатывался" в несколько этапов без достаточного планирования на следующую фазу.
Фаза 1: Рыцарский десант
В Knights Landing добавлены 512-битные регистры, которые имеют только 32-битную и 64-битную детализацию данных. Поэтому регистры маски никогда не должны быть шире, чем 16 бит.
Когда Intel разрабатывает этот первый набор встроенных компонентов AVX512, они пошли дальше и добавили встроенные компоненты практически для всего, включая регистры маски. Вот почему существующие маски имеют только 16 бит. И они охватывают только инструкции, которые существуют в Knights Landing. (хотя я не могу объяснить, почему KSHIFT
пропал, отсутствует)
На Приземлении Рыцарей операции маски были быстрыми (2 цикла). Но перемещение данных между регистрами маски и общими регистрами было очень медленным (5 циклов). Таким образом, имело значение, где выполнялись операции с маской, и имело смысл дать пользователю более точный контроль перемещения вперед-назад между регистрами маски и георадарами.
Фаза 2: Скайлэйк Перли
Skylake Purley расширяет AVX512 для покрытия байтовых дорожек. И это увеличило ширину регистров маски до полных 64 бит. Этот второй раунд также добавил KADD
а также KTEST
которого не было в высадке рыцарей.
Эти новые инструкции маски (KADD
, KTEST
и 64-битные расширения существующих) - это те, в которых отсутствуют их внутренние аналоги.
Хотя мы не знаем точно, почему они отсутствуют, есть веские доказательства в поддержку этого:
Компилятор / Синтаксис:
В Knights Landing одни и те же свойства маски использовались как для 8-битных, так и для 16-битных масок. Не было никакого способа отличить их. Расширение их до 32-битных и 64-битных ухудшило ситуацию. Другими словами, Intel не спроектировала встроенную маску правильно с самого начала. И они решили отбросить их полностью, а не починить.
Несоответствия производительности:
Инструкции по маске пересечения битов на Скайлейке Перли медленные. Хотя все побитовые инструкции являются одноцикловыми, KADD
, KSHIFT
, KUNPACK
и т.д... все 4 цикла. Но перемещение между маской и георадаром - всего 2 цикла.
Из-за этого часто быстрее перемещать их в георадары, чтобы делать их и перемещать обратно. Но программист вряд ли узнает об этом. Поэтому вместо того, чтобы предоставить пользователю полный контроль над регистрами маски, Intel решила, что компилятор примет это решение.
То, что компилятор принимает это решение, означает, что компилятор должен иметь такую логику. Компилятор Intel в настоящее время делает так, как он будет генерировать kadd
и семья в определенных (редких) случаях. Но GCC нет. В GCC все, кроме самых тривиальных операций с маской, будут перенесены в георадары и вместо этого будут выполняться там.
Последние мысли:
До выпуска Skylake Purley у меня лично было написано много кода AVX512, который включает много кода маски AVX512. Они были написаны с определенными предположениями о производительности (задержка одного цикла), которые оказались ложными на Скайлейке Перли.
Из моего собственного тестирования на Skylake X, некоторые из моих собственных кодов масок, которые основывались на операциях пересечения битов, оказались медленнее, чем сгенерированные компилятором версии, которые переместили их в GPR и обратно. Причина, конечно, в том, что KADD
а также KSHIFT
было 4 цикла вместо 1.
Конечно, я предпочитаю, чтобы Intel предоставила встроенные функции, чтобы дать нам контроль, который я хочу. Но здесь очень легко ошибиться (с точки зрения производительности), если вы не знаете, что делаете.