使用多版本控制时的编译时 AVX 检测
Compile-time AVX detection when using multi-versioning
我为两种不同的架构编译了相当大的函数:
__attribute__ ((target ("arch=broadwell"))) void doStuff()
{
doStuffImpl()
}
__attribute__ ((target ("arch=nocona"))) void doStuff()
{
doStuffImpl();
}
__attribute__((always_inline)) void doStuffImpl()
{
(...)
}
我知道这是进行多版本控制的旧方法,但我使用的是 gcc 4.9.3。另外实际上 doStuffImpl() 不是单个函数,而是一堆带有内联的函数,其中 doStuff() 是最后一个实际函数调用,但我认为它不会改变任何东西。
函数包含一些由编译器自动矢量化的代码,但我还需要在那里添加一些手工制作的内在函数。两种不同的口味显然不同。
问题是:我如何在编译时识别哪些 SIMD 扩展可用?
我在尝试类似的东西:
#ifdef __AVX2__
AVX_intrinsics();
#elif defined __SSE4.2__
SSE_intrinsics();
#endif
但似乎定义来自 "global" -march 标志,而不是来自多版本控制覆盖的标志。
Godbolt(内在函数是垃圾,但表明了我的观点)
我可以提取这部分并执行单独的多版本函数,但这会增加调度和函数调用的成本。
有什么方法可以对函数的两个多版本变体进行编译时区分吗?
正如评论中的回答:
我建议将每个 CPU 目标移动到一个单独的翻译单元,该单元使用相应的编译器标志进行编译。公共 doStuffImpl
功能可以在每个 TU 中包含的 header 中实现。在 header 中,您可以使用 __AVX__
等预定义宏来测试可用的 ISA 扩展。 __attribute__((target))
属性不再需要,在这种情况下可以将其删除。
我为两种不同的架构编译了相当大的函数:
__attribute__ ((target ("arch=broadwell"))) void doStuff()
{
doStuffImpl()
}
__attribute__ ((target ("arch=nocona"))) void doStuff()
{
doStuffImpl();
}
__attribute__((always_inline)) void doStuffImpl()
{
(...)
}
我知道这是进行多版本控制的旧方法,但我使用的是 gcc 4.9.3。另外实际上 doStuffImpl() 不是单个函数,而是一堆带有内联的函数,其中 doStuff() 是最后一个实际函数调用,但我认为它不会改变任何东西。
函数包含一些由编译器自动矢量化的代码,但我还需要在那里添加一些手工制作的内在函数。两种不同的口味显然不同。 问题是:我如何在编译时识别哪些 SIMD 扩展可用? 我在尝试类似的东西:
#ifdef __AVX2__
AVX_intrinsics();
#elif defined __SSE4.2__
SSE_intrinsics();
#endif
但似乎定义来自 "global" -march 标志,而不是来自多版本控制覆盖的标志。
Godbolt(内在函数是垃圾,但表明了我的观点)
我可以提取这部分并执行单独的多版本函数,但这会增加调度和函数调用的成本。 有什么方法可以对函数的两个多版本变体进行编译时区分吗?
正如评论中的回答:
我建议将每个 CPU 目标移动到一个单独的翻译单元,该单元使用相应的编译器标志进行编译。公共 doStuffImpl
功能可以在每个 TU 中包含的 header 中实现。在 header 中,您可以使用 __AVX__
等预定义宏来测试可用的 ISA 扩展。 __attribute__((target))
属性不再需要,在这种情况下可以将其删除。