GNU编译器优化

3

我不太了解编译器,但知道它们非常复杂,并且足够智能化来优化您的代码。以这段代码为例:

 string foo = "bar";
 for(int i = 0; i < foo.length(); i++){
     //some code that does not modify the length of foo
 }

GNU编译器会不会聪明到意识到在这个循环中foo的长度不会改变,从而用正确的值替换foo.length()调用?或者foo.length()会在每次i比较时被调用?
4个回答

7

既然Mysticial和Kerrek都建议查看生成的汇编代码,那么这里有一个例子:

#include <string>
using namespace std;

int does_clang_love_me(string foo) {
    int j = 0;
    for (int i = 0; i < foo.length(); i++) {
        j++;
    }
    return j;
}

我把上面的代码保存在test.cpp文件中,然后像这样编译它:

$ clang++ -o test.o -Os -c test.cpp

`-Os`开关告诉clang尝试优化生成最小的代码。GCC也有相应的开关可供使用。为了查看汇编代码,我使用otool命令来检查生成的目标文件,因为我现在正使用mac系统。其他平台也有类似的工具。
$ otool -tv test.o

test.o:
(__TEXT,__text) section
__Z16does_clang_love_meSs:
0000000000000000    pushq   %rbp
0000000000000001    movq    %rsp,%rbp
0000000000000004    movq    (%rdi),%rax
0000000000000007    movq    0xe8(%rax),%rcx
000000000000000b    xorl    %eax,%eax
000000000000000d    testq   %rcx,%rcx
0000000000000010    je  0x0000001e
0000000000000012    cmpq    $0x01,%rcx
0000000000000016    movl    $0x00000001,%eax
000000000000001b    cmoval  %ecx,%eax
000000000000001e    popq    %rbp
000000000000001f    ret

就像Mysticial所说的一样,这只是一个变量访问。

6
唯一确定的方法是尝试并查看汇编代码。
我猜如果对length()的调用被内联,那么循环不变式代码移动将提升length()的内部内容,并将其替换为单个变量。
作为第二个想法,这可能甚至是无意义的。字符串的大小可能只是string类中的一个简单字段 - 位于堆栈上。因此,仅内联对length()的调用就已经具有减少调用到简单变量访问的效果。 编辑: 在后一种情况下,甚至不需要考虑foo的长度是否在循环内修改。获取字符串的长度已经只是一个变量访问。

2

编译器必须保证程序的行为“好像”在每个循环中都调用了length()。只有在可以证明没有副作用且结果确实是常量时,它才能将调用提升出循环。

在实际示例中会发生什么需要逐案分析。如果您好奇,只需查看汇编代码即可。

强制提升的典型方法是手动执行:

for (unsigned int i = 0, end = s.length(); i != end; ++i)

也许您也可以考虑现代的for (char & c : s)作为另一种选择。


1
当然,当你手动执行这个操作时,你需要确保循环内部的操作不会改变s的长度。 - Greg Hewgill
@GregHewgill:好吧,不那么严格地说,我会说你负责确保循环体代码是正确的。无论这意味着什么。通常它将涉及确保解除引用和访问是正确的。 - Kerrek SB

0
说实话,我不确定gcc会如何优化这段代码。但是将冗余代码移出循环被称为“部分冗余消除”。将foo.length()移出循环,也就是所谓的循环不变式代码移动,是部分冗余消除的一种形式。请参考《龙书》第9.5节(我也在阅读这一章),详细阐述了如何使用数据流分析解决这些问题。这里有一张来自斯坦福大学的幻灯片:http://suif.stanford.edu/~courses/cs243/lectures/l5.pdf。希望这些能够帮到你。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接