我正在用 C++ 编写一个应用程序,我想使用 SIMD 的内在函数。 现在我想为不同的架构(如 SSE、AVX2 和 AVX512)编写单独的代码。 我可以在运行时检查支持哪些硬件并跳转到正确的实现。 问题是编译器需要了解它编译的架构。但我想添加不同架构的实现。 我该如何处理呢? 我可以为代码的不同部分添加编译器选项吗? 我使用带有 MSVC 编译器的 Visual Studio Code。我不想使用 SIMD 库来能够使用该库不支持的 SIMD 操作。
这有点复杂,但架构在编译时就已知。因此,您可以从包含正确的标题开始。如果您计划包含其他编译器或架构,请添加 mote
#elif
s
#if defined(_MSVC_LANG) && defined(_M_ARM64)
#include <arm64_neon.h>
#define ARCH_ARM64
#elif defined(_MSVC_LANG) && defined(_M_X64)
#include <intrin.h>
#define ARCH_X64
#else
// TODO: Add support for other architectures
#error "Unsupported architecture"
#endif
然后我们可以添加检测CPU功能并存储它们的代码,这样我们就不必在每次使用时都进行查询。
enum class isa_lvl: unsigned int
{
none = 0,
avx2 = 0x1,
avx512 = 0x2,
neon = 0x1001
};
isa_lvl g_isaLevel = isa_lvl::none;
void init_arch(void);
// TODO: call this once on startup
void init_arch(void)
{
#if defined(ARCH_ARM64)
g_isaLevel = isa_lvl::neon; // ARM64 always supports NEON
#elif defined(ARCH_X64)
int regs[4];
__cpuidex(regs, 7,0); // use cpuid instruction to interrogate the CPU
if (regs[1] & (1 << 16)) {
g_isaLevel = isa_lvl::avx512;
} else if (regs[1] & (1 << 5)) {
g_isaLevel = isa_lvl::avx2;
}
#else
// TODO: other archs
#endif
}
最后,您可以在运行时使用缓存的 ISA 信息来调度最佳代码路径:
void do_stuff()
{
switch (g_isaLevel)
{
#if defined(ARCH_X64)
case isa_lvl::avx2:
do_stuff_avx2();
break;
//...
#elif defined(ARCH_ARM64)
case isa_lvl::neon:
do_stuff_neon();
break;
#endif
default:
do_stuff_();
}
}