如何为MSVC Visual Studio指定目标CPU/架构Haswell?

问题描述 投票:0回答:2

我有一个程序,大量使用内部命令

_BitScanForward
/
_BitScanForward64
(又名计数尾随零、TZCNT、CTZ)。 我想使用内在函数,而是使用相应的CPU指令(在Haswell及更高版本上可用)。

当使用 gcc 或 clang(其中内在函数称为

__builtin_ctz
)时,我可以通过指定
-march=haswell
-mbmi2
作为编译器标志来实现此目的。

_BitScanForward的文档仅指定该内在函数在所有架构“x86,ARM,x64,ARM64”或“x64,ARM64”上可用,但我不只是希望它可用,我想确保它被编译为使用CPU指令而不是内部函数。我还检查了/Oi,但这也不能解释它。

我也搜索了网络,但奇怪的是,与我的问题匹配的很少,大多数只是解释如何使用内在函数,例如这个问题这个问题

我是否想得太多了,如果 CPU 支持的话,MSVC 会创建神奇地使用 CPU 指令的代码?是否需要任何标志?如何确保 CPU 指令在可用时得到使用?

更新

这就是 Godbolt 的样子。 请客气一点,我的汇编阅读能力非常基础。

GCC 将

tzcnt
与 haswell/bmi2 一起使用,否则诉诸
rep bsf
。 MSVC 使用
bsf
而不使用
rep

我还发现了这个有用的答案,其中指出:

  • “对 bsr 使用冗余的代表前缀通常被定义为被忽略[...]”。我想知道
    bsf
    是否也是如此?
  • 它解释了(据我所知)
    bsf
    tzcnt
    不同,但是MSVC似乎不会检查输入== 0

这增加了问题:为什么

bsf
适用于 MSVC?

更新

好吧,这很简单,我实际上为 MSVC 打电话

_BitScanForward
。嚯!

更新

所以我在这里添加了一些不必要的混乱。理想情况下,我想使用内在的

__tzcnt
,但这在 MSVC 中不存在,所以我求助于
_BitScanForward
加上额外的检查来解释
0
输入。

但是,MSVC 支持 LZCNT,我也有类似的问题(但在我的代码中使用较少)。

稍微更新的问题是:MSVC 如何处理 LZCNT(而不是 TZCNT)?

答案:参见这里。具体来说:“在不支持

lzcnt
指令的英特尔处理器上,指令字节编码作为
bsr
(位扫描反向)执行。如果考虑代码可移植性,请考虑使用
_BitScanReverse
内在函数。 ”

本文建议如果担心较旧的 CPU,请使用

bsr
。对我来说,这意味着没有编译器标志来控制这一点,相反,他们建议手动识别
__cpu
,然后调用
bsr
lzcnt

简而言之,MSVC 不支持不同的 CPU 架构(x86/64/ARM 之外)。

c++ visual-c++ x86 compiler-optimization intrinsics
2个回答
0
投票

正如我上面发布的,MSVC 似乎不支持不同的 CPU 架构(x86/64/ARM 之外)。

本文说:“在不支持

lzcnt
指令的 Intel 处理器上,指令字节编码以
bsr
(位扫描反向)执行。如果考虑代码可移植性,请考虑使用
 _BitScanReverse
是内在的。”

本文建议如果担心较旧的 CPU,请使用

bsr
。对我来说,这意味着没有编译器标志来控制这一点,相反,他们建议手动识别
__cpuid
,然后根据结果调用
bsr
lzcnt

更新

正如 @dewaffled 指出的,

x64 内在函数列表中确实有 
_tzcnt_u32
 / 
_tzcnt_u64

我通过查看窗格左侧的按字母顺序排列的内部函数列表而受到误导。我想知道“内在函数”和“内在函数”之间是否有区别,即

_tzcnt_u64
是内在函数,但不是内在函数。


0
投票

如果您能负担得起一个相当新的编译器并且可以指定 /std:c++20) - 您可以使用标准 C++ std::countl_zero / std::countl_one / std::countr_zero / std::countr_one ;详情请参考 https://en.cppreference.com/w/cpp/header/bit .

从个人经验来看:这些恰好在 3 个不同的平台和 3 个不同的编译器上发挥作用。

© www.soinside.com 2019 - 2024. All rights reserved.