您不需要这样做,通常最好使用-march=haswell 与-march=core2 或其他东西构建整个文件,这样您就可以设置调整选项以及目标指令集。
但是单独的编译单元使得内联小函数变得更加困难,所以如果你小心不要真正导致 SSE-AVX transition penalties 在没有 vzeroupper 的情况下混合 VEX/非 VEX,或者将 VEX 编码的指令放入在不支持 AVX 的 CPU 上运行的代码路径中。
IDK 编译器在内联时对目标属性的尊重程度如何,但链接时优化也可以内联来自使用不同选项编译的编译单元的代码,并且不会导致问题的 AFAIK。
GNU C function attributes, yes。这适用于 gcc 和 clang,但显然不适用于 ICC,即使它不拒绝属性语法。
显然它不适用于 MSVC,无论如何它都有不同的命令行选项。使用 MSVC,您可以编译使用 AVX 内部函数而不使用 /arch:AVX 的文件,但不要这样做;它将仅将 VEX 编码用于旧版 SSE 根本无法编码的指令,例如 _mm_permutevar_ps (vpermilps),从而导致转换惩罚。
GNU C 方式:
#include <immintrin.h>
__m128 addps_sse(__m128 x, __m128 y) {
return x+y; // GNU C alternative to _mm_add_ps.
}
__attribute((target("avx"))) // <<<<<<<<<<< This line
__m128 addps_avx(__m128 x, __m128 y) {
return x+y;
}
Compiled (on the Godbolt compiler explorer) 与 gcc 和 clang -O3 -march=nehalem 使 SSE4.2 可用(以及 Nehalem 的调子),但不启用 AVX。
addps_sse:
addps xmm0, xmm1
ret
addps_avx:
vaddps xmm0, xmm0, xmm1
ret
当然,gcc 和 clang 都发出相同的 asm。 ICC 对两个版本都使用addps(非 VEX)。我没有检查 ICC 是否允许在启用 AVX 的函数中使用 _mm256 内在函数,但 gcc 应该。