如何在编译时检测 SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI 可用性?

我试图优化一些矩阵计算,我想知道是否有可能在编译时检测,如果 SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI[1]是由编译器启用?理想的海湾合作委员会和叮当,但我可以管理,只有其中之一。

我不确定这是否可行,也许我会使用我自己的宏,但我宁愿检测它,而不是要求用户选择它。


[1] “ KCVI”代表骑士角向量指令优化。像 FFTW 这样的库检测/利用这些新的指令优化。

54066 次浏览

大多数编译器会自动定义:

__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

更新的英特尔处理器支持 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

这里是天湖 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

英特尔公布了其他 AVX-512子集(见 ISA 扩展)。GCC (版本7)支持与 AVX-512的4FMAPS、4VNNIW、 IFMA、 VBMI 和 VPOPCNTDQ 子集相关的编译器标志和预处理器符号:

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

请注意,SSE 宏不能与 VisualC + + . 您必须改用 _M_IX86_FP一起工作。

看看 archspec,一个为此目的构建的 没错库: https://github.com/archspec/archspec