c++ - 使用 `__builtin_expect` 会影响程序语义吗?

标签 c++ gcc clang

GCC(还有 Clang),为人工辅助分支预测提供这个 __builtin_expect,如解释的那样 here .非正式地,人们用以下方式解释其语义:“编译器只是无条件地处理指示的分支,如果条件结果与指示的不同,就会发生代价高昂的回滚”。

但是如果我有一段代码如下:

if (__builtin_expect(p != 0, 1)) // line 1
  p->access_object();            // line 2

如果我按字面意思对待上面的非正式解释,编译器可以只执行第 2 行,而无需等待第 1 行中的条件计算,因此如果指针恰好为 null,则会导致未定义的行为(空指针取消引用) .

我的问题是,如果我使用 __builtin_expect 是否仍能保证我的防御检查有效?如果是这样,如果我像上面那样在防御性检查中使用 __builtin_expect,我会得到任何运行时好处吗?

(注意:我像这样使用 __builtin_expect 的目标是在 p 为非空的情况下获得最大性能,但代价是速度变慢(甚至数量级)p 为 null 的情况;即使后一种情况经常出现。)

最佳答案

不,builtin_expect 不会影响无竞争程序的语义。

特别是,编译器不得发出会执行 if block 主体的代码,如果该代码具有无法撤消的副作用。除了性能之外,代码必须“好像”未使用 builtin_expect

对于您的具体示例:

if (__builtin_expect(p != 0, 1)) // line 1
  p->access_object();            // line 2

p 如果为 null,则不能取消引用。那么在这种情况下 builtin_expect 的意义何在?它最多可以告诉编译器“p 可能不为空,因此可能会调用 access_object()”。如果 access_object() 的定义是 inline,编译器可能会尝试内联它,而如果你说“p 可能是 null, "编译器可能决定最好不要在此调用站点内联 access_object() 的代码,因为它不太可能被使用。

事实上,这会导致在实践中不直观地使用 builtin_expect:您可以用它来表示“这段代码是慢速路径”,而不管它的“可能性”有多大。作为一个简单的例子,服务器程序可能会这样做:

if (__builtin_expect(is_allowed(user, request), 1))
    process(request);
else
    reject(request);

即使我们发现 50% 的请求是非法的并且将被拒绝,我们仍可能决定将“快乐路径”标记为可能已采用,因为我们不关心放慢拒绝速度。

关于c++ - 使用 `__builtin_expect` 会影响程序语义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43184283/

相关文章:

c++ - 编译时 bool 值 C++ 未知的 constexpr 函数参数

c++ - 特定模板类型的功能特化

c - 在 Windows PowerShell 中为 GCC 设置别名

c++ - nullptr 可以转换为 uintptr_t 吗?不同的编译器不同意

c++ - C/C++ 中的 BST super 节点生成

c++ - 在键入 "exit"后,如何让我的程序打印用户键入的所有数据

c++ - Clang sizeof ("literal") 优化

c - 如何在 Windows 7 上使用 GCC 和 NVIDIA Toolkit 编译和链接 OpenCL?

arm - AVR/ARM 的 Clang 编译?

c++ - 使用 std::atomic c++11 功能的 Qt 5.1 Beta 错误