首页 > 解决方案 > 为 GCC 复制 clang 的 __builtin_assume

问题描述

最近发现void __builtin_assume(bool)了for clang,它可以向编译器提供有关程序状态的额外信息。这可以产生巨大的差异,例如

#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,我很好奇是否存在等效的内置函数。__builtin_assume不幸的是,我在GCC 文档中找不到。也许存在一个内置但它只是有一个不同的名字?

如果不存在等效的内置函数,是否有办法在没有 的情况下产生相同的结果__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起作用。

标签: c++gcccompilationclangbuilt-in

解决方案


我使用__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;
}

推荐阅读