推测条件执行 C/C++

Speculative conditional execution C/C++

于是和同事讨论了评估执行的顺序。 考虑这个条件:

if (a > b && ref++) { do something }

我们都同意,按照 C 标准,顺序是从左到右。然而, 分歧在于,尽管有求值顺序,但某些其数据最终将被求值的指令可能会被推测性地执行,然后尽管惰性求值仍保持此状态。

例如,ref 在评估 a > b 之前递增,评估仍然从左到右进行,即 a > ba > b 的实际 jump greater than 指令rev > 0 按从左到右的顺序执行,并在 !true 时在第一个实例中放弃。现在这违背了惰性评估的整个概念,但是如果 ref 是一个指令流,也许是一个内联函数怎么办。开始推测性地执行一些指令会更有意义。问题是:这些指令是否已提交,即使是中途。

想法?

运算符&&(以及运算符||)在某种意义上是特殊的,因为它们保证从左到右为"short-cut-evaluation"。这意味着对于像 expr1 && expr2 这样的条件,expr1 将始终首先被评估,并且 - 甚至更多 - 如果 expr1 已经被评估为 expr2 则根本不会被评估错误的。这不是优化,这是语言保证的。

因此,在 if (a > b && ref++) 中,当且仅当 a > b 的计算结果为 [=20] 时,表达式 ref++ 才会被计算(包括它递增 ref 的副作用) =].

a > b && ref++ 不可能,因为 && 运算符 短路

想想那个案例:

f = fopen("foo.txt");
if ((f != NULL) && fread(buffer,10,1,f)) { ...

执行第二部分如果 f==NULL 会是一个 bug 因为第一部分可以防止它。

相反,没有什么能阻止编译器在这里为所欲为:

a > b & ref++

& 是算术 所以这两个条件总是被执行。因此,即使第一个条件为假,ref 也会递增。

C 编译器被允许执行 "as-if" 规则,这意味着只要程序的 意图 得到尊重,它们就可以做任何他们喜欢的事情。

考虑 (a > b && ref++)。这里的意图是如果 a > b1ref 只增加 ,并且 必须 是观察到的行为。这是因为 && 的右手参数仅在左手参数为 1 时才被评估。然而,生成的汇编代码可能使得 CPU 可以推测性地递增 ref 分支预测 ),并在适当时通过管道转储收回该递增。