我有一个程序,大量使用内部命令_BitScanForward
/_BitScanForward64
(又名计数尾随零,TZCNT,CTZ)。我想 * 不 * 使用内部,而是使用相应的CPU指令(在Haswell和更高版本中提供)。
当使用gcc或clang(其中的内部函数称为__builtin_ctz
)时,我可以通过指定-march=haswell
或-mbmi2
作为编译器标志来实现这一点。
_BitScanForward的文档只规定了intrinsic在所有架构"x86,ARM,x64,ARM64"或"x64,ARM64"上可用,但我不只是希望它可用,我希望确保它被编译为使用CPU指令而不是intrinsic函数。
我也搜索了网络,但奇怪的是,几乎没有匹配我的问题,大多数只是解释如何使用intrinsic,例如this question和this question。
我是不是想太多了,如果CPU支持的话,MSVC将创建神奇的使用CPU指令的代码?是否需要任何标志?如何确保CPU指令在可用时被使用?
- 更新**
这是godbolt的样子。请友好一点,我的汇编阅读技能相当基本。
GCC使用tzcnt
搭配haswell/bmi2,否则会使用rep bsf
。MSVC使用bsf
,但不使用rep
。
我还发现了这个有用的答案,它指出:
- "为BSR使用冗余的rep前缀一般被定义为被忽略[...]".我想知道
bsf
是否也是如此? - 它解释了(正如我所知)
bsf
与tzcnt
不同,但是MSVC似乎不检查input == 0
这增加了以下问题:为什么bsf
适用于MSVC?
- 更新**
好的,这很简单,我实际上调用_BitScanForward
来表示MSVC。
- 更新**
所以我在这里添加了一些不必要的混淆。理想情况下,我希望使用一个固有的__tzcnt
,但MSVC中不存在,所以我求助于_BitScanForward
加上一个额外的检查来说明0
输入。
但是,MSVC支持LZCNT,我在这里遇到了类似的问题(但是在我的代码中很少使用它)。
略微更新的问题为:MSVC如何处理LZCNT(而不是TZCNT)?
- 答案:**请参见here。具体如下:在不支持
lzcnt
指令的Intel处理器上,指令字节编码作为bsr
(位扫描反向)执行。如果代码可移植性是一个问题,请考虑使用_BitScanReverse
内在函数。
- 答案:**请参见here。具体如下:在不支持
这篇文章建议如果老的CPU是一个问题,就求助于bsr
。对我来说,这意味着没有编译器标志来控制这一点,相反,他们建议手动识别__cpu
,然后调用bsr
或lzcnt
。
简而言之,MSVC不支持不同的CPU架构(x86/64/ARM以外)。
1条答案
按热度按时间p4tfgftt1#
正如我在上面发布的,MSVC似乎不支持不同的CPU体系结构(x86/64/ARM之外)。
This article says:"在不支持
lzcnt
指令的英特尔处理器上,指令字节编码作为bsr
(位扫描反向)执行。如果考虑代码可移植性,请考虑使用_BitScanReverse
内部函数。"文章建议如果老CPU是一个问题,就求助于
bsr
。对我来说,这意味着没有编译器标志来控制这一点,相反,他们建议手动识别__cpuid
,然后根据结果调用bsr
或lzcnt
。正如@defaffled所指出的,x64 intrinsics list中确实存在
_tzcnt_u32
/_tzcnt_u64
。我在查看窗格左侧的Alphabetical listing of intrinsic functions时被误导了。我想知道"intrinsic"和"intrinsic函数"之间是否有区别,即
_tzcnt_u64
是intrinsic但不是intrinsic函数。