考虑以下 C 程序:
void bar();
void baz();
void foo( int a ) {
if ( a ) {
bar();
}
else {
baz();
}
}
在我的基于 x86-64 的计算机上,GCC 生成的具有 -O1 优化级别的指令给出:
0: sub $0x8,%rsp
4: test %edi,%edi
6: je 14 <foo+0x14>
8: mov $0x0,%eax
d: callq 12 <foo+0x12> # relocation to bar
12: jmp 1e <foo+0x1e>
14: mov $0x0,%eax
19: callq 1e <foo+0x1e> # relocation to baz
1e: add $0x8,%rsp
22: retq
而添加 -freorder-blocks 优化参数(包含在 -O2 中)会将代码变为:
0: sub $0x8,%rsp
4: test %edi,%edi
6: jne 17 <foo+0x17>
8: mov $0x0,%eax
d: callq 12 <foo+0x12> # relocation to baz
12: add $0x8,%rsp
16: retq
17: mov $0x0,%eax
1c: callq 21 <foo+0x21> # relocation to bar
21: add $0x8,%rsp
25: retq
主要是从跳跃等于到跳跃不等于的变化。我知道直到 Pentium 4,处理器不考虑条件前向分支上的静态分支预测(似乎静态预测在其他英特尔处理器上变得随机),因此我想这种优化正在处理这个问题。
假设并参考jne优化版本,这意味着else块实际上被认为比程序流中的if块更有可能执行。
但这究竟是什么意思?由于编译器没有对foo函数中的a值进行假设,因此这种概率仅依赖于程序员的著作(实际上,他们可以使用而不是和反转函数调用)。if ( !a )
if ( a )
这是否意味着将if条件块视为例外情况(而不是正常的执行流程)应该被视为一种好习惯?
那是:
if ( !cond ) {
// exceptional code
}
else {
// normal continuation
}
代替:
if ( cond ) {
// normal continuation
}
else {
// exceptional code
}
(当然,人们可能更喜欢在相关块内使用 return 语句来限制缩进大小)。