clang-cl 和 arch:avx2 是否存在兼容性问题?

Are there compatibility issues with clang-cl and arch:avx2?

我正在使用 Windows 10,Visual Studio 2019,平台:x64 并在单个文件中包含以下测试脚本 Visual Studio 解决方案:

#include <iostream>
#include <intrin.h>
using namespace std;

int main() {
    unsigned __int64 mask = 0x0fffffffffffffff; //1152921504606846975;
    unsigned long index;

    _BitScanReverse64(&index, mask);
    if (index != 59) {
        cout << "Fails!" << endl;
        return EXIT_FAILURE;
    }
    else {
        cout << "Success!" << endl;
        return EXIT_SUCCESS;
    }
}

在我的 属性 解决方案中,我将 'Enable Enhanced Instruction Set' 设置为 'Advanced Vector Extenstions 2 (/arch:AVX2)'。 使用 msvc 编译时(将 'Platform Toolset' 设置为 'Visual Studio 2019 (v142)')代码 returns EXIT_SUCCESS,但使用 clang-cl 编译时(将 'Platform Toolset' 设置为 'LLVM (clang-cl)') 我得到 EXIT_FAILURE。调试clang-cl时运行,index的值为4,而应为59。这表明clang-cl正在读取与MSVC相反方向的位。

当我将 'Enable Enhanced Instruction Set' 设置为 'Not Set' 时,情况并非如此。在这种情况下,MSVC 和 clang-cl return EXIT_SUCCESS.

所有 dll 都已加载并显示在调试输出中 window 在所有情况下都来自 C:\Windows\System32###.dll。

有人理解这种行为吗?如果有任何见解,我将不胜感激。

编辑:我之前没有提到:我用 IntelCore i7-3930K CPU @3.20GHz 编译了这个。

得到 4 而不是 59 听起来像是将 _BitScanReverse64 实现为 63 - lzcnt 的 clang。实际 bsr 在 AMD 上很慢,所以是的,编译器想要编译不同指令固有的 BSR 是有原因的。

但是你 运行 计算机上的可执行文件实际上并不支持 BMI,因此 lzcnt 解码为 rep bsr = bsr,给出前导零计数而不是最高设置位的位索引。

AFAIK,所有具有 AVX2 的 CPU 也具有 BMI。如果你的 CPU 没有那个,你不应该期望你的可执行文件在你的 CPU 上正确地使用 /arch:AVX2 到 运行 构建。在这种情况下,失败模式不是非法指令,它是 lzcnt 运行ning as bsr.

MSVC 通常不会优化内部函数,显然包括这种情况,所以它直接使用 bsr


更新:i7-3930K 是 SandyBridge-E。它没有 AVX2,所以这解释了你的结果。

当您告诉它在非 AVX2 计算机上构建 AVX2 可执行文件时,clang-cl 不会出错。其用例是在一台机器上编译以在不同机器上创建 运行 的可执行文件。

它也不会为您的可执行文件添加 CPUID 检查代码。如果你想要那个,你自己写吧。这是C++,它不牵你的手


目标CPU 选项

MSVC 风格 /arch 选项比普通 GCC/clang 风格更受限制。没有像SSE4.1那样针对不同级别的SSE;它直接跳转到 AVX。

此外,/arch:AVX2 显然意味着 BMI1/2,即使它们是具有不同 CPUID 特征位的不同指令集。例如,在内核代码中,您可能需要整数 BMI 指令,而不是接触 XMM/YMM 寄存器的 SIMD 指令。

clang -O3 -mavx2 而不是 也会启用 -mbmi。您通常会希望这样做,但如果您未能同时启用 BMI,则 clang 将一直使用 bsr。 (对于英特尔 CPUs 实际上比 63-lzcnt 更好)。我认为 MSVC 的 /arch:AVX2 类似于 -march=haswell,如果它也启用 FMA 指令的话。

并且 MSVC 中没有任何内容支持在您构建它们的计算机上将二进制文件优化为 运行。这是有道理的,它是为软件开发的闭源二进制分发模型设计的。

但是 GCC 和 clang 有 -march=native 来启用您的计算机支持的所有指令集。同样重要的是,设置适合您计算机的 tuning 选项。例如不用担心编写在 AMD CPU 或较旧的 Intel 上会很慢的代码,只需编写对 您的 CPU.[= 有益的 asm 31=]

TL:DR: CPU clang-cl 中的选择选项非常粗糙,将非 SIMD 扩展与某种级别的 AVX 混为一谈。这就是为什么 /arch:AVX2 启用整数 BMI 扩展,而 clang -mavx2 不会。