1

我正在使用 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;
    }
}

在我的属性解决方案中,我将“启用增强指令集”设置为“高级矢量扩展 2 (/arch:AVX2)”。使用 msvc 编译时(将“平台工具集”设置为“Visual Studio 2019 (v142)”),代码返回 EXIT_SUCCESS,但是使用 clang-cl 编译时(将“平台工具集”设置为“LLVM (clang-cl)”)我得到了EXIT_FAILURE。在调试 clang-cl 运行时,index 的值是 4,而它应该是 59。这表明 clang-cl 正在读取与 MSVC 方向相反的位。

当我将“启用增强指令集”设置为“未设置”时,情况并非如此。在这种情况下,MSVC 和 clang-cl 都返回 EXIT_SUCCESS。

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

有人理解这种行为吗?我会很感激这里的任何见解。

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

4

1 回答 1

4

得到 4 而不是 59 听起来像是 clang 实现_BitScanReverse6463 - lzcnt. AMD 的实际bsr速度很慢,所以是的,编译器想要编译不同指令固有的 BSR 是有原因的。

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

AFAIK,所有具有 AVX2 的 CPU 也具有 BMI。如果你的 CPU 没有,你不应该期望你的可执行文件/arch:AVX2在你的 CPU 上正确运行。在这种情况下,故障模式不是非法指令,它lzcntbsr.

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


更新:i7-3930K是 SandyBridge-E。它没有 AVX2,因此可以解释您的结果。

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

它也不会为您将 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. (这实际上比英特尔 CPU 更好63-lzcnt)。我认为 MSVC 的 /arch:AVX2 类似于-march=haswell,如果它还启用 FMA 指令。

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

但是 GCC 和 clang 必须-march=native启用您的计算机支持的所有指令集。同样重要的是,设置适合您计算机的调整选项。例如,不要担心在 AMD CPU 或较旧的 Intel 上编写代码会很慢,只需编写对您的CPU 有好处的 asm 即可。

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

于 2020-06-21T02:11:27.293 回答