为 GCC 复制 clang 的 __builtin_assume

问题描述 投票:0回答:3

最近,我发现了 clang 的

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

 函数。

c++ gcc compilation clang built-in
3个回答
6
投票
我使用了

__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; }
    

1
投票
我觉得这里完全没有必要经历未定义的行为。非常简单的

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; }
不需要的时候不需要召唤鼻魔。


0
投票
自 C++23 起,可以使用

[[assume]]

 属性
实现这一点。这就像 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 支持此功能。

另请参阅:C++23 编译器支持

© www.soinside.com 2019 - 2024. All rights reserved.