了解MIPS中的递归

时间:2014-02-25 22:05:48

标签: recursion mips

我正在审查过去的任务,并试图遵循递归函数背后的逻辑。它只是将输入传递给“fact”,确定是否> = 1,并再次将其传递给循环。在循环中,我变得困惑。我知道在调用函数时通常明智的做法是使用sw保存数据并在完成后用lw加载它。但是,循环调用fact(再次调用循环)直到输入< 1.正如您在下面的代码中所看到的,它会不断地将$ ra和输入保存在同一位置。请注意,在实际完成递归之前不会使用lw代码。

这怎么不覆盖旧数据?旧数据仅仅被推迟了吗?如果是这样,当递归多次使用时,如何只弹出两个项目?这段代码中$ v0的目的是什么?

fact: slti $t0, $a0, 1 # test for n < 1, n is user input
      beq $t0, $zero, L1 # if n >= 1, go to L1
      li $v0, 1 # return 1
      jr $ra # return to instruction after jal

L1:   addi $sp, $sp, -8 # adjust stack for 2 items
      sw $ra, 4($sp) # save the return address
      sw $a0, 0($sp) # save the argument n
      addi $a0, $a0, -1 # n >= 1; argument gets (n – 1)
      jal fact # call fact with (n – 1)
      lw $a0, 0($sp) # return from jal: restore argument n
      lw $ra, 4($sp) # restore the return address
      addi $sp, $sp, 8 # adjust stack pointer to pop 2 items
      mul $v0, $a0, $v0 # return n * fact (n – 1)
      jr $ra # return to the caller

1 个答案:

答案 0 :(得分:0)

这是堆栈操作的典型示例。

每次执行该函数时,它都会增加堆栈并将$ra$a0存储在新分配的位置。

您可以通过注意$ra$a0相对于$sp堆栈指针)进行分配来看到这一点。

每次函数执行时,通过从8减去$sp或者为两个单词减去足够的空间来扩展堆栈。同样,当函数退出堆栈时,将8添加到$sp即可缩小。


这样想:

假设我们要计算5!。

每次拨打fact时的筹码都会存储$a0$ra。在对fact进行5次调用后,堆栈将如下所示:

$a0: 5
$ra: back to main
----
$a0: 4
$ra: back to fact
---- 
$a0: 3
$ra: back to fact
----
$a0: 2
$ra: back to fact
----
$a0: 1
$ra: back to fact
----

一旦基本案例执行($a0 = 1),堆栈就会开始缩小。 $a0 = 1堆栈在1中返回$v0,当我们加载$a0时,我们得到2,因为我们已经缩小了堆栈。因此,我们将2乘以1,然后我们返回该值。在下一个堆栈帧中重复相同的过程,我们在2中返回$v0并将其乘以我们从堆栈加载的3并返回6$v0

希望从这里你可以看到:

addi $a0 $zero 5
jal fact

会在120中返回$v0