将 SSE2 和 AVX 内部函数与不同的编译器混合
Posted
技术标签:
【中文标题】将 SSE2 和 AVX 内部函数与不同的编译器混合【英文标题】:Mixing SSE2 and AVX intrinsics with different compilers 【发布时间】:2018-03-12 00:05:54 【问题描述】:是否可以在同一个编译单元中混合使用 VEX 和非 VEX 编码的 SIMD 内部函数?我想这样做是为了将代码发布到不同的编译器作为单个文件模块。
【问题讨论】:
您是否使用#ifdef
s 分隔代码?如果是这样,可能是的。但是,将所有代码放在一个源中会触发所有版本的重新编译,即使您只是修改了一个替代方案。
我会发现让一个文件依赖于晦涩的预处理器魔法比简单地让一堆文件彼此相邻并让构建系统担心选择正确的文件更令人困惑和简单对于它正在使用的 build 工具。
“VEX 编码的 SIMD 内在函数”:没有这样的东西。内在函数是高级构造,可能会使用 VEX 转换为 asm
@spectras 我不会为我的项目使用构建系统,也不想强加给使用我的代码的每个人。
【参考方案1】:
您不需要这样做,通常最好使用-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 应该。
【讨论】:
所以答案是“不可能在所有编译器上”。该死! @user3368561:此答案仅适用于 gcc/clang。 IDK 如何在 ICC 或 MSVC 上做到这一点,但我不使用那些编译器(除了随便在 Godbolt 上检查他们的代码生成),所以也许他们有办法。我绝对不说这在其他编译器上是不可能的。 我根据您的回答进行了自己的研究,使用 MSVC 更改发出的指令的唯一方法是通过命令行标志,因此无法按照我的问题要求在单个编译单元中执行此操作。以上是关于将 SSE2 和 AVX 内部函数与不同的编译器混合的主要内容,如果未能解决你的问题,请参考以下文章
用于灰度到 ARGB 转换的 C++ SSE2 或 AVX2 内在函数
如何在 Visual Studio 2017 15.5 中禁用 AVX?