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