汇编代码 (1) 普通递归 不优化 fun: ... cmpl $0,8(%ebp) #n-0 jne .L2 #不等于0?跳.L2 movl $0,-4(%ebp) #临时变量,用于保存计算结果(返回值) jmp .L1 .L2: movl 8(%ebp),%eax #取n decl %eax #n-1 movl %eax,(%esp) #n-1值压栈,传给fun的参数 call fun #递归调用fun addl 8(%ebp),%eax #求n+fun(n-1) movl %eax,-4(%ebp) #保存 .L1: movl -4(%ebp),%eax #取fun的返回值 leave #恢复栈针 ret #函数返回
优化后 fun: ... xorl %eax,%eax #寄存器eax清零 movl %ebx,-4(%ebp) #保存ebx的值(惯例:eax,edx,ecx由调用者保存,而其它的有被调函数保存) movl 8(%ebp),%ebx #取n testl %ebx,%ebx #测试n (n&n) jne .L2 #非0? 跳.L2 .L1: movl -4(%ebp),%ebx #恢复ebx的值 leave ret .L2: leal -1(%ebx),%edx #n-1的值存到edx movl %edx,(%esp) #n-1的值压栈(fun的参数) call fun #递归调用fun leal (%eax,%ebx),%eax #计算n+fun(n-1)的值,作为fun的返回值 jmp .L1
(2) 尾递归 不优化 fun: ... cmpl $0,12(%ebp) #n-0 jne .L2 #不等于0?跳.L2 movl 8(%ebp),%eax #取sum movl %eax,-4(%ebp) #保存sum到临时变量 jmp .L1 .L2: movl 12(%ebp),%eax #取n decl %eax #n-1 movl %eax,4(%esp) #n-1值压栈(fun的第二个参数) movl 12(%ebp),%eax #取sum addl 8(%ebp),%eax #求sum+n movl %eax,(%esp) #sum+n值压栈(fun的第一个参数) call fun #递归调用fun .L1: movl -4(%ebp),%eax #取出保存在临时变量里的sum值,作为返回值 leave ret
优化后 (已消除递归调用) fun: ... movl 8(%ebp),%eax #取sum (第一个参数) movl 12(%ebp),%edx #取n (第二个参数) .L1: testl %edx,%edx #测试n是否为0 je .L2 #0? 跳.L2 addl %edx,%eax #sum+=n decl %edx #n-- jmp .L1 #跳.L1,循环 .L2: leave ret
|