编译器内置函数与位运算

最后更新: 2022-03-03 23:02:53 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

GCC 和 Clang 为其前端能够直接识别的运算提供内置函数形式。位计数组内置函数可以根据所选目标和优化上下文,降低为目标指令、库调用序列或经过优化的表达式。源代码应选择能够明确表达其可移植性和零输入契约的接口。

GNU 风格的位运算内置函数 #

GCC 和 Clang 针对 unsigned int、unsigned long 和 unsigned long long 支持以下函数族:

操作unsigned intunsigned longunsigned long long
设置位数量__builtin_popcount__builtin_popcountl__builtin_popcountll
前导零位数量__builtin_clz`__builtin32_t{16}) == 4);

如果必须支持库功能边界,请在包含 `<bit>` 后检查 `__cpp_lib_bitops`;C++20 为该功能规定的值是 `201907L`。对于编译器特定代码,只有在使用前完成保护后,才能使用 `__has_builtin` 检查内置函数是否可用:

```cpp
#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
// Use std::popcount, std::countl_zero, and std::countr_zero.
#elif defined(__has_builtin)
#  if __has_builtin(__builtin_popcount)
#    define PROJECT_HAS_BUILTIN_POPCOUNT 1
#  endif
#endif

GCC 和 Clang 都记录了这些特定的内置函数,因此,明确支持二者的项目也可以集中处理编译器家族检查,并为其他编译器保留可移植的回退实现。不要假设 __has_builtin 一定存在,也不要使用它来选择一个零输入前提未由公共 API 强制执行的内置函数。

代码生成与常量求值 #

对于性能关键的目标,应检查生成的代码,因为内置函数的写法并不保证生成一条指令。硬件支持、目标特性、操作数宽度、周围的控制流以及优化级别共同决定降低结果。符合标准的实现可以为标准 <bit> 函数向优化器提供等价的语义信息,同时保留可移植性;当操作数和库实现允许时,这些函数还可以用于常量求值。对于 C++20 之前的库,或经过测量确认的目标差异,可以使用内置函数回退;但该回退应置于一个按宽度处理并带有已文档化前提条件的统一包装器之后。

评论

在 GitHub 上阅读或评论(发表评论需要登录)