编译器会优化转义内部循环吗?

时间:2021-05-11 05:27:25

The code I have looks like this (all uses of done shown):

我的代码是这样的(所显示的所有用法):

bool done = false;
for(int i = 0; i < big; i++)
{
  ...
  for(int j = 0; j < wow; j++)
  {
    ...
    if(foo(i,j))
    {
       done = true;
       break;
    }
    ...
  }
  if(done) break;
  ...
}

will any compilers convert it to this:

是否有编译器将其转换为:

for(int i = 0; i < big; i++)
{
  ...
  for(int j = 0; j < wow; j++)
  {
    ...
    if(foo(i,j))
      goto __done; // same as a labeled break if we had it
    ...
  }
  ...
}
__done:;

Note: While I'm mostly interested in if the if(done)break; gets bypassed and removed as dead code, I'm also interested in if it and done gets removed altogether.

注意:我最感兴趣的是if(done)是否中断;作为死代码被绕过并删除,我还对它和done是否被全部删除感兴趣。

4 个解决方案

#1


14  

Obviously this depends on the compiler. The best thing to do when you're unsure is to view the compiler's assembly output (all popular compilers have a switch for this). Even if you aren't familiar with assembly, you can at least compare the debug version with the optimized version.

显然这取决于编译器。当您不确定的时候,最好的做法是查看编译器的汇编输出(所有流行的编译器都有这个选项)。即使您不熟悉汇编,您至少可以将调试版本与优化版本进行比较。

That being said, this is one of the few situations where goto is NOT a bad idea. Feel free to use it to break out of inner loops.

话虽如此,这是为数不多的不是个坏主意的情况之一。*地使用它来打破内在的循环。

Edit

编辑

Just tried the following in VS2010 and it does indeed optimize the outer conditional:

在VS2010中尝试了以下方法,它确实优化了外部条件:

bool done = false;
for(int i = 0; i < 10; i++)
{
    for(int j = 0; j < 10; j++)
    {
        if(i == 7 && j == 3)
        {
            done = true;
            break;
        }
    }
    if(done) break;
}
return 0;

#2


7  

GNU compiler does just that, starting with optimization level -O1 (I am using gcc 4.5.1 on x86_64)

GNU编译器就是这样做的,从优化级别-O1开始(我在x86_64上使用gcc 4.5.1)

call    _Z3fooii  // al = foo(i,j)
testb   %al, %al
jne .L14
...

where .L14 is the label placed exactly where you placed __done:

其中。l14是标签放置的地方,就在你放置的地方:

A better question might be: which modern compiler does not perform this optimization?

一个更好的问题可能是:哪个现代编译器不执行这种优化?

#3


4  

I'm not trying to be snarky, but...does it matter? In general, I think it's best to let compilers to their job, and that job is to produce the "best" (note that "best" may vary depending on your needs) compiled code given your source code. Any performance considerations in your code should be identified with a profiler and good working knowledge of algorithmic complexity.

我并不是想说得那么尖刻,但是……这有关系吗?一般来说,我认为最好是让编译器执行它们的工作,而这个工作就是生成“最佳”(注意,“最佳”可能根据您的需要有所不同)编译的代码。在您的代码中,任何性能方面的考虑都应该通过一个分析器和良好的算法复杂度来确定。

If you're just curious, then disregard this comment. But if your intention is to somehow optimize your code, then I think there are much better avenues.

如果你只是好奇,那么不要理会这个评论。但是,如果您的目的是以某种方式优化您的代码,那么我认为还有更好的方法。

#4


1  

I've tried GCC 4.2.1 with the following:

我已经尝试了GCC 4.2.1:

// Prevent optimizing out calls to foo and loop unrolling:
extern int big, wow;
bool foo(int,int);

void
bar()
{
    int done = false;
    for(int i = 0; i < big; i++)
    {
        for(int j = 0; j < wow; j++)
        {
            if(foo(i,j))
            {
                done = true;
                break;
            }
        }
        if(done)
            break;
    }
}

...and it falls through straight to postamble with -O3:

…它通过-O3直接到postamble:

  33:   e8 fc ff ff ff          call   34 <bar()+0x34> ; call to foo*
  38:   84 c0                   test   %al,%al
  3a:   74 e5                   je     21 <bar()+0x21> ; next loop iteration
  3c:   83 c4 10                add    $0x10,%esp
  3f:   5b                      pop    %ebx
  40:   5e                      pop    %esi
  41:   5d                      pop    %ebp
  42:   c3                      ret

*** This is from an unlinked object file, call 34 is actually call to foo.

***这是来自一个未链接的对象文件,调用34实际上是对foo的调用。

#1


14  

Obviously this depends on the compiler. The best thing to do when you're unsure is to view the compiler's assembly output (all popular compilers have a switch for this). Even if you aren't familiar with assembly, you can at least compare the debug version with the optimized version.

显然这取决于编译器。当您不确定的时候,最好的做法是查看编译器的汇编输出(所有流行的编译器都有这个选项)。即使您不熟悉汇编,您至少可以将调试版本与优化版本进行比较。

That being said, this is one of the few situations where goto is NOT a bad idea. Feel free to use it to break out of inner loops.

话虽如此,这是为数不多的不是个坏主意的情况之一。*地使用它来打破内在的循环。

Edit

编辑

Just tried the following in VS2010 and it does indeed optimize the outer conditional:

在VS2010中尝试了以下方法,它确实优化了外部条件:

bool done = false;
for(int i = 0; i < 10; i++)
{
    for(int j = 0; j < 10; j++)
    {
        if(i == 7 && j == 3)
        {
            done = true;
            break;
        }
    }
    if(done) break;
}
return 0;

#2


7  

GNU compiler does just that, starting with optimization level -O1 (I am using gcc 4.5.1 on x86_64)

GNU编译器就是这样做的,从优化级别-O1开始(我在x86_64上使用gcc 4.5.1)

call    _Z3fooii  // al = foo(i,j)
testb   %al, %al
jne .L14
...

where .L14 is the label placed exactly where you placed __done:

其中。l14是标签放置的地方,就在你放置的地方:

A better question might be: which modern compiler does not perform this optimization?

一个更好的问题可能是:哪个现代编译器不执行这种优化?

#3


4  

I'm not trying to be snarky, but...does it matter? In general, I think it's best to let compilers to their job, and that job is to produce the "best" (note that "best" may vary depending on your needs) compiled code given your source code. Any performance considerations in your code should be identified with a profiler and good working knowledge of algorithmic complexity.

我并不是想说得那么尖刻,但是……这有关系吗?一般来说,我认为最好是让编译器执行它们的工作,而这个工作就是生成“最佳”(注意,“最佳”可能根据您的需要有所不同)编译的代码。在您的代码中,任何性能方面的考虑都应该通过一个分析器和良好的算法复杂度来确定。

If you're just curious, then disregard this comment. But if your intention is to somehow optimize your code, then I think there are much better avenues.

如果你只是好奇,那么不要理会这个评论。但是,如果您的目的是以某种方式优化您的代码,那么我认为还有更好的方法。

#4


1  

I've tried GCC 4.2.1 with the following:

我已经尝试了GCC 4.2.1:

// Prevent optimizing out calls to foo and loop unrolling:
extern int big, wow;
bool foo(int,int);

void
bar()
{
    int done = false;
    for(int i = 0; i < big; i++)
    {
        for(int j = 0; j < wow; j++)
        {
            if(foo(i,j))
            {
                done = true;
                break;
            }
        }
        if(done)
            break;
    }
}

...and it falls through straight to postamble with -O3:

…它通过-O3直接到postamble:

  33:   e8 fc ff ff ff          call   34 <bar()+0x34> ; call to foo*
  38:   84 c0                   test   %al,%al
  3a:   74 e5                   je     21 <bar()+0x21> ; next loop iteration
  3c:   83 c4 10                add    $0x10,%esp
  3f:   5b                      pop    %ebx
  40:   5e                      pop    %esi
  41:   5d                      pop    %ebp
  42:   c3                      ret

*** This is from an unlinked object file, call 34 is actually call to foo.

***这是来自一个未链接的对象文件,调用34实际上是对foo的调用。