25 c++ compiler-construction optimization
考虑一个像这样的例子:
if (flag)
for (condition)
do_something();
else
for (condition)
do_something_else();
Run Code Online (Sandbox Code Playgroud)
如果flag在for循环内没有改变,这应该在语义上等同于:
for (condition)
if (flag)
do_something();
else
do_something_else();
Run Code Online (Sandbox Code Playgroud)
仅在第一种情况下,代码可能会更长(例如,如果使用了几个for循环或者是否do_something()是与大多数相同的代码块do_something_else()),而在第二种情况下,标记会被多次检查.
我很好奇当前的C++编译器(最重要的是,g ++)是否能够优化第二个例子来摆脱for循环内的重复测试.如果是这样,在什么条件下这可能?
Mic*_*ael 19
是的,如果确定标志没有改变且无法通过do_something或do_something_else更改,则可以将其拉出循环.我听说这个称为循环提升,但维基百科有一个名为"循环不变代码运动" 的条目.
如果flags是局部变量,则编译器应该能够执行此优化,因为它保证不会对生成的代码的行为产生影响.
如果flags是一个全局变量,并且你在循环中调用函数它可能不会执行优化 - 它可能无法确定这些函数是否修改了全局.
这也可能受到您所做的那种优化的影响 - 优化尺寸将有利于非提升版本,而优化速度可能会有利于提升版本.
通常,这不是您应该担心的事情,除非分析告诉您该函数是一个热点,并且您发现通过遍历编译器输出的程序集实际生成的代码效率低于高效代码.像这样的微优化你应该总是留给编译器,除非你绝对必须这样做.
Unc*_*ens 17
试过GCC和-O3:
void foo();
void bar();
int main()
{
bool doesnt_change = true;
for (int i = 0; i != 3; ++i) {
if (doesnt_change) {
foo();
}
else {
bar();
}
}
}
Run Code Online (Sandbox Code Playgroud)
主要结果:
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call ___main
call __Z3foov
call __Z3foov
call __Z3foov
xorl %eax, %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
因此它确实优化了选择(并展开较小的循环).
如果doesnt_change是全局的,则不会进行此优化.