【问题标题】:How would you write feature agnostic code for both AVX2 and AVX512?您将如何为 AVX2 和 AVX512 编写与功能无关的代码?
【发布时间】:2020-10-07 19:53:16
【问题描述】:

这样做的一种方法是创建函数指针,根据选择所需功能集的预处理器指令有条件地指向不同的函数。

#if defined(__AVX512__)
    void (*func_ptr)() = _mm512_func;
#else
    void (*func_ptr)() = _mm256_func;
#endif

int main()
{
    func_ptr();
    return 0;
}

有没有更好的方法来做到这一点?谢谢。

【问题讨论】:

  • 如果您仅在编译时检测 AVX512,则不需要函数指针。只是#define func _mm512_func。 (并且只定义实际调用的版本)。或者更简单地说,根本不要为同一个函数定义不同的名称,只需选择要编译的定义即可。
  • @PeterCordes 我认为在 C++ 社区中函数指针优于宏。但这做同样的工作。这是最好的方法吗?还有其他想法吗?
  • ... 或只是 #ifdef 围绕同一功能的可能实现。
  • @NanashiNoGombe - 你仍然有你建议的函数指针方法的宏,所以即使“函数指针在宏上”是某种规则,这不会摆脱宏。

标签: c++ c-preprocessor intrinsics avx2 avx512


【解决方案1】:

如果您仅在编译时检测 AVX512,则不需要函数指针。

最简单的方法:根本不要为同一个函数定义不同的名称,只需在您有多个版本的.cpp 文件中选择要编译的定义即可。这使编译时分派与定义函数的文件保持隔离,对您的其余代码不可见。

#ifdef __AVX512F__
void func(float *__restrict a, float *__restrict b) {
 ...  // AVX512 version here
}
#elif defined(__AVX2__) && defined(__FMA__)
void func(float *__restrict a, float *__restrict b) {          // same name
 ...  // AVX2 version here
}
#else
...       // SSE2 or scalar fallback
#endif

虽然对于测试,您可能确实希望能够构建它的所有版本并相互测试+基准测试,因此您可以考虑使用#define func _mm512_func,或者在该文件中使用一些预处理器技巧。也许另一个答案对此会有更好的想法。


我认为在 C++ 社区中,函数指针优于宏。但这做同样的工作

也许如果功能点是void (*static const func_ptr)(),那么您可以指望它被内联/优化掉。如果你不需要它,你真的不想为调度增加额外的开销(例如,对于 runtime CPU 检测,在运行 cpuid 的 init 函数中设置函数指针)

【讨论】:

  • 您能否详细说明选择性编译定义的含义?谢谢。
  • @NanashiNoGombe:添加了一个示例。
  • 是否有任何开销与定义一个完整的函数(如您所展示的)而不是 #define func _mm512_func 相关?
  • 另外,把这些函数做成inline不是更好吗?再次感谢!
  • @NanashiNoGombe:如果它很小,那么是的,您希望能够内联。通过将所有内容放在标题中并定义inline,或者通过链接时优化进行编译。 LTO 通常是一个好主意,所以我假设你会这样做。
猜你喜欢
  • 1970-01-01
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
相关资源
最近更新 更多