C++编译器可以优化"for"循环中的"if"语句吗?

25 c++ compiler-construction optimization

考虑一个像这样的例子:

if (flag)
  for (condition)
    do_something();
else
  for (condition)
    do_something_else();
Run Code Online (Sandbox Code Playgroud)

如果flagfor循环内没有改变,这应该在语义上等同于:

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是一个全局变量,并且你在循环中调用函数它可能不会执行优化 - 它可能无法确定这些函数是否修改了全局.

这也可能受到您所做的那种优化的影响 - 优化尺寸将有利于非提升版本,而优化速度可能会有利于提升版本.

通常,这不是您应该担心的事情,除非分析告诉您该函数是一个热点,并且您发现通过遍历编译器输出的程序集实际生成的代码效率低于高效代码.像这样的微优化你应该总是留给编译器,除非你绝对必须这样做.

  • 谢谢你的回答.在您的维基百科链接中,我找到了"loop unswitching"的页面,这似乎是这种优化的更精确的术语. (5认同)
  • OP 引用的“循环取消切换”链接:https://en.wikipedia.org/wiki/Loop_unswitching (2认同)

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是全局的,则不会进行此优化.

  • 你能试试下面我用过的片段吗?在你的代码片段中,编译器只是删除了第二个分支,因为它永远不会执行.(诀窍是从extern volatile初始化`doesnt_change`,因此编译器无法确定它将具有哪个值) (3认同)
  • +1:用于执行测试并显示生成的代码. (2认同)