void __builtin_assume(bool)
,它可以向编译器提供有关程序状态的附加信息。这可以产生巨大的差异,例如:
#include <cstddef>
// compiles to about 80 instructions at -O3
unsigned sum(unsigned data[], size_t count) {
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return sum;
}
// compiles to about 10 instructions at -O3
unsigned sum_small(unsigned data[], size_t count) {
__builtin_assume(count <= 4);
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return sum;
}
我现在被迫使用 GCC,我很好奇是否存在等效的内置函数。不幸的是我在GCC文档
中找不到
__builtin_assume
。也许存在一个内置函数,但它只是有一个不同的名称?
如果不存在等效的内置函数,是否有办法在没有 __builtin_assume
的情况下产生相同的结果,例如在条件不成立时故意调用未定义的行为?理想情况下,我想要一个始终可以安全调用的宏,例如:
#if ... // detect clang
#define MY_ASSUME(condition) __builtin_assume(condition)
#elif ... // detect GCC
#define MY_ASSUME(condition) __gcc_builtin_assume_equivalent(condition)
#else
#define MY_ASSUME(condition)
#endif
无论解决方案是什么,它也应该适用于 constexpr
函数。
if
中以实质上编写断言。该条件可以是任何不变量
false
,因此在您的情况下,您可以设置相反的条件。示例:
// Basically `assert(count <= 4);`
if ( !(count <= 4) ) {
__builtin_unreachable();
}
编辑:为了响应评论,您可以将其转换为断言宏,如下所示:
// Line break for readability
#define my_assert( condition ) \
{ if(!(condition)) __builtin_unreachable(); }
根据问题中的代码,您将像这样使用它:
unsigned sum_small(unsigned data[], size_t count) {
my_assert(count <= 4); // <--- Changed here
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return sum;
}
if
检查与
abort
的结合定义明确,并为优化器提供了足够的思考空间:
#include <cstddef>
#include <cstdlib>
// compiles to about 10 instructions at -O3
unsigned sum_small(unsigned data[], size_t count) {
if (count > 4)
std::abort();
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return sum;
}
不需要的时候不需要召唤鼻魔。
属性实现这一点。这就像 clang 的
__builtin_assume
一样:例如:
// define an ASSUME(...) function-style macro so we only need to detect compilers
// in one place
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(assume) >= 202207L
#define ASSUME(...) [[assume(__VA_ARGS__)]]
#endif
#endif
#ifndef ASSUME
#if defined(__clang__)
#define ASSUME(...) __builtin_assume(__VA_ARGS__)
#elif defined(__GNUC__)
#define ASSUME(...) ((__VA_ARGS__) ? void() : __builtin_unreachable())
#elif defined(_MSC_VER)
#define ASSUME(...) __assume(__VA_ARGS__)
#elif __cpp_lib_unreachable >= 202202L
#include <utility>
#define ASSUME(...) ((__VA_ARGS__) ? void() : ::std::unreachable())
#else
#define ASSUME(...)
#endif
#endif
unsigned sum_small(unsigned data[], size_t count) {
ASSUME(count <= 4);
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return sum;
}
所有编译器可能需要一些时间才能实现这一点。截至撰写本文时,仅 GCC 13 支持此功能。