为多个SIMD架构生成代码

时间:2017-06-10 23:35:12

标签: gcc simd avx sse4

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

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

问题:是否可以告诉编译器(GCC)每当使用SIMD优化函数时,它必须为架构列表生成代码?当然还有高级别的分支机构

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

什么是最佳做法?多个二进制文件?命名

2 个答案:

答案 0 :(得分:10)

只要您不关心可移植性,是的。

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

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

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

答案 1 :(得分:5)

如果您正在谈论只是让编译器生成SSE / AVX等指令,并且您有“通用”代码(即您没有使用内在函数明确地进行矢量化,或者批次 更慢 对于SSE版本。

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

this thread中查看我较长的解释和参考资料。

另一方面,如果你使用内在函数明确地进行矢量化,并且你确定你有足够大的AVX爆发以使它值得,我已经成功编写了代码,我告诉MSVC为SSE2编译(默认为x64)然后我动态检查CPU功能,一些功能切换到使用AVX内在函数实现的代码路径。

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

哦,你也必须注意AVX-SSE转换(当你离开AVX部分代码返回SSE代码时调用VZEROUPPER) - 它可以完成但我发现了解CPU的影响是一场更大的战斗比我原先设想的那样。