【问题标题】:Tail call optimization for void return typed functionvoid 返回类型函数的尾调用优化
【发布时间】:2013-06-12 17:56:18
【问题描述】:

尾调用优化是否适用于对返回 void 的函数的递归调用?例如我有一个函数,void fun()

void fun()
{
    ...
    ...
    ...
    fun();
}

这里编译器不会知道,调用 fun() 是最后一条语句。那么尾调用优化是否只针对返回一些值的函数?

【问题讨论】:

  • 取决于编译器。你用的是哪一个?
  • @RogerLipscombe GCC。但是无论我使用哪个编译器,编译器如何知道它是最后一条语句?没有像函数返回某个值的情况那样显式返回,比如返回 int..
  • 我想知道,返回类型会有什么不同?我的猜测是尾部优化将在这种情况下起作用
  • 编译器可以推断它是最后一个语句,因为它紧跟在右大括号之后。
  • @shar 如果没有显式返回,递归什么时候结束?

标签: optimization recursion


【解决方案1】:

答案是可以,但编译器没有义务这样做。是否这样做在很大程度上取决于函数、编译器和选择的优化级别。如果您担心特定函数的这一点,请查看特定编译器在特定优化级别生成的程序集。

更具体地说,GCC(至少是使用 LLVM 作为后端的 Apple 版本)将为至少一些在优化级别 -O1 或更高级别返回 void 的函数生成尾调用优化代码。

一些测试代码:

/* Fills an array with a single value, recursively with side effects */
void fillarray(int val, int* curr, int* end)
{
  if (curr==end) return;

  *curr = val;
  fillarray(val,curr+1,end);
}

使用最少的优化 (-O1),编译为汇编 (gcc -O1 -S test.c) 会产生一个很好的尾调用优化函数:

_fillarray:
        pushq       %rbp
        movq        %rsp, %rbp   # set up the stack

        cmpq        %rdx, %rsi   # early exit if beg == end
        je  LBB1_2
LBB1_1:
        movl        %edi, (%rsi) # *curr = val
        addq        $4, %rsi     # curr++

        cmpq        %rsi, %rdx   # TAIL CALL optimization is here
        jne LBB1_1               # if curr != end, go to LBB1_1
LBB1_2:
        popq        %rbp         # restore the stack and exit
        ret

(注意:我已经删除了一些不必要的标签和对齐语句,它们会混淆程序集的结构)。

此外,当优化关闭时 (-O0),生成的代码是递归的(不是尾调用优化的)。

【讨论】:

    猜你喜欢
    • 2015-03-24
    • 1970-01-01
    • 2021-07-20
    • 2019-10-08
    • 2019-02-05
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    • 2020-01-18
    相关资源
    最近更新 更多