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

Bap*_*cht 51 gcc sse clang avx avx512

我正在尝试优化一些矩阵计算,我想知道是否有可能在编译时检测SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI [1]是否由编译器?理想情况下,对于GCC和Clang,但我只能管理其中一个.

我不确定它是否可能,也许我将使用自己的宏,但我更愿意检测它并要求用户选择它.


[1] "KCVI"代表骑士角矢量指令优化.像FFTW这样的库检测/利用这些较新的指令优化.

Pau*_*l R 82

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

__SSE__
__SSE2__
__SSE3__
__AVX__
__AVX2__
Run Code Online (Sandbox Code Playgroud)

等等,根据你传递的命令行开关.您可以使用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
Run Code Online (Sandbox Code Playgroud)

要么:

$ 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
Run Code Online (Sandbox Code Playgroud)

或者只是检查预定义的宏以获取特定平台上的默认构建:

$ 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
Run Code Online (Sandbox Code Playgroud)

最近的英特尔处理器支持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
Run Code Online (Sandbox Code Playgroud)

这是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
Run Code Online (Sandbox Code Playgroud)

英特尔公布了其他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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,SSE 宏不适用于 Visual C++。您必须改用 _M_IX86_FP:https://msdn.microsoft.com/en-us/library/b0084kay.aspx (2认同)
  • @Rémi:是的,恐怕是典型的 - 如果您被迫支持 MSVC,最简单的方法就是在您的项目或 makefile 中定义 SSE 宏。 (2认同)
  • 我认为最后一个需要`-march = native` ...另外值得注意的是:GCC定义了各个AVX512子集(例如`__AVX512F__`和`__AVX512BW__`). (2认同)