有谁知道 MSVC 编译器 bug/annoyance 的修复程序,其中 SIMD 扩展设置在 AVX 上获得 "stuck"?

Does anyone know of a fix for an MSVC compiler bug/annoyance where SIMD Extension settings get "stuck" on AVX?

有谁知道 MSVC 编译器 bug/annoyance SIMD 扩展设置在 AVX 上“卡住”的修复方法?

这个问题的背景是编写 SIMD CPU 调度程序,紧跟 Agner 著名的 dispatch_example2.cpp 项目。我一直在三个不同的 MSVC 项目中来回走动,并且在其中两个项目中遇到了这个问题,之后这两个项目中的一个以某种方式“自行修复”了。

问题很简单:要编译调度程序,我需要编译 4 次

/arch:AVX512 /DINSTRSET=10
/arch:AVX2 /DINSTRSET=8
/arch:AVX /DINSTRSET=7
/arch:SSE2 /D__SSE4_2__

在执行此操作时,我正在观察 INSTRSET 的值和此代码:

#if defined ( __AVX512VL__ ) && defined ( __AVX512BW__ ) && defined ( __AVX512DQ__ )
#define AVX512_FLAG 1
#else
#define AVX512_FLAG 2
#endif

#if defined ( __AVX2__ )
#define AVX2_FLAG 1
#else
#define AVX2_FLAG 2
#endif

#if defined ( __AVX__ )
#define AVX_FLAG 1
#else
#define AVX_FLAG 2
#endif

行为是这样的:对于三个 AVX 编译,一切都完全符合预期。当问题没有发生时,SSE2 编译按预期显示 (AVX512_FLAG、AVX2_FLAG、AVX_FLAG == 2),最终代码 运行 没问题。

出现问题时,对于/arch:SSE2 /D__SSE4_2__编译上面的代码显示AVX512_FLAG == 2 but AVX2_FLAG == AVX_FLAG = = 1 和 INSTRSET == 8,编译器认为 AVX2 指令已启用 - 项目编译,但在 SSE4.2 机器上崩溃。

如果我尝试 /arch:SSE2 /DINSTRSET=6 然后我得到 INSTRSET == 6 用于编译,但上面的代码仍然显示 AVX2_FLAG == 1 和 AVX_FLAG == 1 , 最终项目在 SSE4.2 机器上仍然崩溃。

即使我没有 运行 任何向量代码也会发生崩溃 - 调用调度程序的任何内容都会立即崩溃,即使所有向量代码都已短路。

仅供参考,尝试 /DINSTRSET=6 只是一种绝望的行为 - 我从来没有在不使用 /D__SSE4_2__

的情况下使用 SSE4.2。

有谁知道如何解决这个完全阻碍我进步的问题?已经尝试过“清洁解决方案”。

如果您想要一个在仅限 SSE 的计算机上运行但可以在可用时利用 AVX 的二进制文件,则需要执行以下操作。

  1. 在项目级别,如果为 Win64 构建,则设置“启用增强指令集:未设置”,如果为 Win32 构建,则设置“SSE2”。

  2. 在包含函数的 AVX 版本的 *.cpp 文件上设置“启用增强指令集:AVX”或 AVX2

  3. 确保永远不要调用这些 AVX 函数,除非 CPU 和 OS(请参阅 GetEnabledXStateFeature WinAPI)实际上都支持。

实际上,与其使用不同的设置多次编译同一个源文件,不如编译 4 个不同的源文件。它们可以包含相同的代码,C++ 有 #include 预处理器指令。如果您有一个使用这些宏调度的实现,请将该实现移动到 *.inl*.hpp 文件中,并将该文件包含到 4 个不同的 *.cpp 文件中以用于不同的 CPU。

我想通了(这很简单也很无聊)。对于增量目标文件,我正在从同一个 .cpp(带有矢量代码的 .cpp)编译 3 个 .obj 文件。当 MSVC SIMD 设置在项目级别属性中更改时,它们可能会或可能不会在 .cpp 文件属性中继承。这是项目在 AVX 上“卡住”的地方(有时,并非总是如此)。只需要检查 .cpp 文件属性并确保它们是正确的。

顺便说一句,我使用的是 VS 2019,/std:c++17,上面的上下文是 32 位版本。