【发布时间】:2017-08-28 07:10:51
【问题描述】:
GCC(以及 Clang),提供此 __builtin_expect 用于人工辅助分支预测,如 here 所述。非正式地,人们用以下方式解释它的语义:“编译器只是无条件地处理指定的分支,如果条件与指定的不同,就会发生代价高昂的回滚”。
但如果我有一段代码如下:
if (__builtin_expect(p != 0, 1)) // line 1
p->access_object(); // line 2
如果我按字面意思处理上面的非正式解释,编译器可以直接执行第 2 行,而无需等待第 1 行中条件的计算,因此如果指针碰巧为空,则会导致未定义的行为(空指针取消引用) .
我的问题是,如果我使用__builtin_expect,我还能得到保证,我的防御检查有效吗?如果是这样,如果我在上述防御检查中使用__builtin_expect,是否可以获得任何运行时优势?
(注意:我像这样使用__builtin_expect 的目标是在p 为非空的情况下获得最大性能,但代价是减慢(即使是数量级)@ 987654329@ 为空;即使后一种情况经常出现。)
【问题讨论】:
-
IMO 这是一个糟糕的非正式描述,afaik 它只是针对您告诉它的任何分支进行优化。而这种信念似乎得到了answers to a related question 的支持
-
@Borgleader:所以这表示无论如何都要先执行检查。唯一的问题是执行是否可以在检查后立即继续,或者在检查后一段时间。我做对了吗?
-
我会说编译器不会“无条件地处理指定的分支”。它开始无条件地处理它,但如果选择了错误的分支,它会丢弃任何结果。这种丢弃发生在非常低的水平上。在检查条件之前,这些无条件计算的结果甚至不会出现在实际 RAM 中。此外,据我所知,即使没有
__builtin_expect,在检查条件之前总是会选择其中一个分支,但它会由分支预测器而不是您选择。