【发布时间】:2013-09-04 19:34:29
【问题描述】:
考虑以下 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
主要是从jump equals到jump not equals的变化。我知道直到 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 语句来限制缩进大小)。
【问题讨论】:
标签: c gcc optimization assembly x86-64