问题描述
最近,我发现了void __builtin_assume(bool)
for clang,它可以向编译器提供有关程序状态的其他信息。这可以产生很大的变化,例如for example:
#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,我很好奇是否存在等效的内置函数。不幸的是,我在the GCC documentation中找不到__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
函数中起作用。
解决方法
我使用了__builtin_unreachable()
,它表示控制流到达此处是“未定义行为”。您可以将其包装在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;
}
不需要时,不需要召唤鼻恶魔。