Есть ли способ автоматически заменить avx512 на avx2?

Следуя совету Линуса Торвальдса (и кроссплатформенной производительности), я не хочу использовать avx512. Есть ли флаг, который я могу указать компилятору (как gcc, так и msvc), чтобы все инструкции avx512 разбивались на пары инструкций avx2, если библиотека, которую я использую, пытается использовать axv512 либо из встроенных функций, либо из оптимизации компилятора?


person Ebony Ayers    schedule 20.03.2021    source источник
comment
Линус предлагает не использовать AVX-512 даже на процессорах, в которых он есть? Я знаю, что он сказал, что AVX-512 — мощный вирус для разработчиков ЦП (что имеет некоторый смысл; добавление хороших функций маскирования к 256-битным векторам было бы хорошо и позволило бы большему количеству ЦП иметь это раньше). Избегать 512-битных векторов также имеет смысл, но на процессоре, который уже потратил транзисторы/компромиссы, чтобы иметь их, зачем вообще избегать AVX-512? Иногда он может сохранять инструкции для 256-битных векторов. Можете ли вы дать ссылку на то, что вы имеете в виду? Возможно, Линус сказал AVX-512 в целом, когда на самом деле он просто имел в виду полноразмерные 512-битные векторы.   -  person Peter Cordes    schedule 20.03.2021


Ответы (1)


Нет, скомпилируйте свой код, чтобы не использовать AVX-512, в первую очередь, сообщив компилятору, что это невозможно; вам нужно только что-то сделать с кодом, использующим встроенные функции, для которых требуется AVX-512.


Однако, если вы компилируете для ЦП, поддерживающего AVX-512, часто стоит использовать его, особенно с 256-битными векторами, чтобы избежать турбо-частота и другие штрафы, связанные с 512-битными векторами. Настройка GCC по умолчанию уже -mprefer-vector-width=256 для таких процессоров, как -march=skylake-avx512.

Если вы хотите создать двоичный файл, который может работать на процессорах без AVX-512, тогда да, очевидно, вам нужно убедиться, что он никогда не будет выполняться, и инструкции, которые без него будут давать сбой. например gcc -O3 -march=znver2 или -march=skylake или что-то еще. Ни один из этих вариантов целевой арки не включает AVX-512. Или -march=native, если вы компилируете для любого процессора, который у вас есть.

Но если у вас есть ЦП, поддерживающий AVX-512, и вы не хотите его использовать, вы можете использовать что-то вроде -march=native -mno-avx512f (все остальные расширения AVX-512 зависят от Foundation AVX-512F, поэтому отключение, которое также предотвращает даже AVX-512VL для 128 и 256-битных векторов.)

(Частичное преимущество -march=native и последующего отключения состоит в том, чтобы также установить параметры настройки. Если вам нужен двоичный файл, который хорошо работает как на Skylake, так и на Zen2, я не уверен, что порекомендовать; вероятно, -march=skylake или -march=znver2 оба подходят; есть по умолчанию tune=generic, но он слишком заботится о действительно старых процессорах, которые даже не поддерживают AVX2, например Sandybridge: Почему gcc не разрешает _mm256_loadu_pd как одиночный vmovupd?)


Внутренности

Даже со встроенными функциями GCC будет выдавать только инструкции, поддерживаемые целевыми параметрами, поэтому -mno-avx512f может позволить вам быть уверенным, что вы ничего не пропустили. Вы получите ошибки времени компиляции, а не инструкции EVEX, проскальзывающие сквозь трещины.

(MSVC отличается и разработан на основе однодвоичной модели, в которой использование новых наборов инструкций выполняется в функциях, которые вы вызываете только в том случае, если ЦП поддерживает это, поэтому это не помешает вам использовать AVX-512. AFAIK, MSVC по-прежнему у него даже нет возможности автовекторизации с помощью AVX-512, только /arch:AVX2.Но в любом случае, MSVC не будет выдавать инструкции AVX-512 самостоятельно, если вы не скажете ему об этом, если вы не используете какие-либо опция вроде /arch:AVX512, если такая вещь существует; AFAIK, к сожалению, у нее нет /arch:native. С MSVC вы должны быть уверены, что уловили все случаи использования встроенных функций, хотя компиляция с помощью GCC может помочь убедиться, что ваша кодовая база не делает этого .)

Если вы все еще хотите скомпилировать код, использующий _mm512_add_epi32 или _mm256_ternlog_epi32 или что-то еще, вам понадобится версия immintrin.h, которая определяет __m512i как структуру/класс с двумя членами __m256i и эмулирует все встроенные функции. Некоторые встроенные функции AVX512 недешевы для эмуляции, особенно маскированные операции, и вся концепция сравнения с маской для получения целого числа вместо вектора. Так что, вероятно, не стоит пытаться сделать это полностью прозрачным; вместо этого просто заставьте GCC запретить вам использовать какие-либо инструкции AVX-512, пока вы делаете версии только для AVX2 любого встроенного кода, у которого еще нет версий AVX2.

В прошлый раз, когда это произошло, кодирование на недостаточном оборудовании, я смог найти avxintrin-emu.h, который позволяет разрабатывать для AVX, компилируя только для SSE4. Но я не нашел аналога для AVX-512. (Обычно вы должны скомпилировать двоичный файл AVX-512 и протестировать его на эмуляторе, таком как SDE, который эмулирует во время выполнения, а не во время компиляции.)

Библиотека-оболочка VectorClass от Agner Fog (https://www.agner.org/optimize/#vectorclass) поддерживает основные операции, такие как + - * /, а также перемешивание и смешивание, а также имеет версии 512-битных векторов, эмулируемых парой векторов AVX2. (И типы VCL неявно преобразуются в __m256i или __m512i и т. д., поэтому для операций, для которых у него нет собственных функций, вы можете использовать встроенные функции Intel. __m256_ternlog_epi32 только с инструкциями AVX2.)


Это не помешает libc использовать написанные от руки инструкции AVX-512 в таких функциях, как strcmp или log/exp, поскольку динамическая диспетчеризация ЦП происходит во время выполнения, и вы не можете запретить ЦП сообщать о том, что он поддерживает AVX- 512. (За исключением виртуальной машины или указания ядру не включать AVX-512 при загрузке, если в Linux есть такая возможность.)

person Peter Cordes    schedule 20.03.2021