我如何知道gcc(更具体地说是g++)是否正在优化特定函数中的尾部递归? (因为它出现了几次:我一般不想测试gcc是否可以优化尾部递归。我想知道它是否可以优化我的尾部递归函数。)

如果您的答案是“查看生成的汇编程序”,那么我想确切地知道我在寻找什么,是否可以编写一个简单的程序来检查汇编程序以查看是否有优化。

PS。我知道这是5个月前出现的问题Which, if any, C++ compilers do tail-recursion optimization?的一部分。但是,我认为该问题的这一部分没有得到令人满意的回答。 (答案是“检查编译器是否进行了优化(我知道)的最简单方法是执行调用,否则将导致堆栈溢出–或查看程序集输出。”)

最佳答案

让我们使用the example code from the other question。编译它,但是告诉gcc不要汇编:

gcc -std=c99 -S -O2 test.c

Now let's look at the _atoi function in the resultant test.s file (gcc 4.0.1 on Mac OS 10.5):

        .text
        .align 4,0x90
_atoi:
        pushl   %ebp
        testl   %eax, %eax
        movl    %esp, %ebp
        movl    %eax, %ecx
        je      L3
        .align 4,0x90
L5:
        movzbl  (%ecx), %eax
        testb   %al, %al
        je      L3
        leal    (%edx,%edx,4), %edx
        movsbl  %al,%eax
        incl    %ecx
        leal    -48(%eax,%edx,2), %edx
        jne     L5
        .align 4,0x90
L3:
        leave
        movl    %edx, %eax
        ret

编译器已对此函数执行了尾调用优化。我们可以知道,因为该代码中没有call指令,而原始的C代码显然有一个函数调用。此外,我们可以看到jne L5指令,该指令在函数中向后跳转,表示在C代码中显然没有循环时会出现循环。如果在关闭优化的情况下进行重新编译,则会看到一行显示call _atoi的信息,并且也不会看到任何向后跳转。

是否可以自动执行此操作是另一回事。汇编代码的细节将取决于您正在编译的代码。

我想,您可以通过编程方式发现它。使函数打印出堆栈指针的当前值(在x86上注册ESP)。如果该函数在第一个调用中打印的值与递归调用中打印的值相同,则说明编译器已执行了尾部调用优化。这个想法需要修改您希望观察的功能,但这可能会影响编译器选择优化功能的方式。如果测试成功(两次都打印相同的ESP值),那么我认为可以合理地假设优化也将在没有您的仪器的情况下执行,但是如果测试失败,我们将不知道失败是否是由于仪器代码的添加。

10-07 12:22
查看更多