Как определить доступность SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI во время компиляции?

Я пытаюсь оптимизировать некоторые матричные вычисления, и мне было интересно, можно ли было определить во время компиляции, включен ли SSE / SSE2 / AVX / AVX2 / AVX-512 / AVX-128-FMA / KCVI[1] компилятор? Идеально для GCC и Clang, но я могу справиться только с одним из них.

Я не уверен, что это возможно, и, возможно, я буду использовать свой собственный макрос, но я бы предпочел скорее обнаружить его и попросить пользователя выбрать его.


[1] "KCVI" обозначает оптимизацию векторной инструкции Knights Corner. Такие библиотеки, как FFTW, обнаруживают / используют эти новые оптимизации команд.

1 ответ

Решение

Большинство компиляторов будут автоматически определять:

__SSE__
__SSE2__
__SSE3__
__AVX__
__AVX2__

и т.д., в зависимости от того, какие параметры командной строки вы передаете. Вы можете легко проверить это с помощью gcc (или gcc-совместимых компиляторов, таких как clang), например так:

$ gcc -msse3 -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE_MATH__ 1

или же:

$ gcc -mavx2 -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __AVX__ 1
#define __AVX2__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1

или просто проверить предопределенные макросы для сборки по умолчанию на вашей конкретной платформе:

$ gcc -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __SSE2_MATH__ 1
#define __SSE2__ 1
#define __SSE3__ 1
#define __SSE_MATH__ 1
#define __SSE__ 1
#define __SSSE3__ 1

Более поздние процессоры Intel поддерживают AVX-512, который не является монолитным набором команд. Можно увидеть поддержку, доступную от GCC (версия 6.2) для двух примеров ниже.

Вот Рыцарь Приземления:

$ gcc -march=knl -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __AVX__ 1
#define __AVX2__ 1
#define __AVX512CD__ 1
#define __AVX512ER__ 1
#define __AVX512F__ 1
#define __AVX512PF__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1

Вот Skylake AVX-512:

$ gcc -march=skylake-avx512 -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __AVX__ 1
#define __AVX2__ 1
#define __AVX512BW__ 1
#define __AVX512CD__ 1
#define __AVX512DQ__ 1
#define __AVX512F__ 1
#define __AVX512VL__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1

Intel раскрыла дополнительные подмножества AVX-512 (см. Расширения ISA). GCC (версия 7) поддерживает флаги компилятора и символы препроцессора, связанные с подмножествами 4FMAPS, 4VNNIW, IFMA, VBMI и VPOPCNTDQ AVX-512:

for i in 4fmaps 4vnniw ifma vbmi vpopcntdq ; do echo "==== $i ====" ; gcc -mavx512$i -dM -E - < /dev/null | egrep "AVX512" | sort ; done
==== 4fmaps ====
#define __AVX5124FMAPS__ 1
#define __AVX512F__ 1
==== 4vnniw ====
#define __AVX5124VNNIW__ 1
#define __AVX512F__ 1
==== ifma ====
#define __AVX512F__ 1
#define __AVX512IFMA__ 1
==== vbmi ====
#define __AVX512BW__ 1
#define __AVX512F__ 1
#define __AVX512VBMI__ 1
==== vpopcntdq ====
#define __AVX512F__ 1
#define __AVX512VPOPCNTDQ__ 1

Взгляните на archspec, библиотеку, которая была создана именно для этой цели: https://github.com/archspec/archspec

Другие вопросы по тегам