13

我编写了一个库,在其中使用 CMake 来验证 MMX、SSE、SSE2、SSE4、AVX、AVX2 和 AVX-512 的标头是否存在。除此之外,我检查指令是否存在,如果存在,我添加必要的编译器标志,-msse2 -mavx -mfma 等。

这一切都很好,但我想部署一个二进制文件,它适用于多代处理器。

问题:是否可以告诉编译器 (GCC),每当它使用 SIMD 优化函数时,它必须为体系结构列表生成代码?当然还要引入高层分支

我的想法类似于编译器如何为函数生成代码,其中输入指针是 4 或 8 字节对齐的。为了防止这种情况,我使用__builtin_assume_aligned宏。

什么是最佳实践?多个二进制文件?命名?

4

2 回答 2

12

只要您不关心可移植性,就可以。

最新版本的 GCC 通过使用target_clones函数属性使这比我所知道的任何其他编译器都更容易。只需添加属性和要为其创建版本的目标列表,GCC 将自动创建不同的变体,以及在运行时自动选择版本的调度函数。

如果你想要更多的可移植性,你可以使用目标属性,clang 和 icc 也支持,但你必须自己编写调度函数(这并不难),并多次发出函数(通常使用宏,或重复包含标题)。

AFAIK,如果您希望您的代码与 MSVC 一起使用,您将需要具有不同选项的多个编译器调用。

于 2017-06-11T01:06:41.420 回答
6

如果你只是在谈论让编译器生成 SSE/AVX 等指令,并且你有“通用”代码(即你没有使用内在函数显式矢量化,或者有很多编译器会发现和auto-vectorise)那么我应该警告您,编译您的整个代码库的 AVX、AVX2 或 AVX512 可能会比为 SSE 版本编译慢得多。

当检测到使用寄存器上半部分的 AVX 操作码时,CPU 会启动电路的上半部分(否则会断电)。这会消耗更多功率,产生更多热量并降低芯片的基本时钟速度,通常会降低 10-20%,具体取决于高功率和低功率操作码的组合,因此您可能会立即损失 15% 的性能,然后在您开始看到任何收益之前,要进行大量矢量化处理以弥补这种性能缺陷。

请参阅此线程中的更长解释和参考。

但是然后我动态检查 CPU 功能,一些函数切换到使用 AVX 内部函数实现的代码路径。

MSVC 允许这样做(它会产生警告,但您可以使它们静音),但相同的技术在 GCC 4.9 下很难发挥作用,因为只有在使用适当的代码生成标志时编译器才会考虑声明内在函数。[更新:@nemequ 在下面解释了如何在 gcc 下使用属性来装饰函数来使这项工作]根据 GCC 的版本,您可能必须编译具有不同标志的文件才能获得可行的系统。

哦,您还必须注意 AVX-SSE 转换(当您离开 AVX 代码部分以返回 SSE 代码时调用 VZEROUPPER) - 可以完成,但我发现理解 CPU 影响比我最初的战斗更大设想。

于 2017-06-17T07:07:10.467 回答