Recursion 理解MIPS中的递归
我在复习以前的作业,并试图遵循递归函数背后的逻辑。它只是将输入传递给“事实”,确定>=1,然后再次传递给循环。这是在循环中,我变得困惑。我理解调用函数时,通常明智的做法是使用sw保存数据,并在完成后使用lw加载数据。但是,循环调用fact(再次调用循环),直到输入<1。正如您在下面的代码中所看到的,它不断地将$ra和输入保存在同一位置。请注意,在实际完成递归之前,不会使用lw代码 这如何不覆盖旧数据?旧数据仅仅是被推后的吗?如果是这样的话,当递归被多次使用时,仅仅弹出两项就足够了吗?此代码中$v0的用途是什么Recursion 理解MIPS中的递归,recursion,mips,Recursion,Mips,我在复习以前的作业,并试图遵循递归函数背后的逻辑。它只是将输入传递给“事实”,确定>=1,然后再次传递给循环。这是在循环中,我变得困惑。我理解调用函数时,通常明智的做法是使用sw保存数据,并在完成后使用lw加载数据。但是,循环调用fact(再次调用循环),直到输入=1;参数获取(n–1) 日航实况#呼叫实况(n-1) lw$a0,0($sp)#从日航返回:恢复参数n lw$ra,4($sp)#恢复返回地址 addi$sp$sp,8#将堆栈指针调整到pop 2项 mul$v0,$a0,$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
事实:slti$t0,$a0,1#测试n<1,n是用户输入
beq$t0,$zero,L1#如果n>=1,则转到L1
李$v0,1#返回1
jr$ra#日航后返回指令
L1:addi$sp$sp,-8#调整两个项目的堆栈
sw$ra,4($sp)#保存回信地址
sw$a0,0($sp)#保存参数n
addi$a0,$a0,-1#n>=1;参数获取(n–1)
日航实况#呼叫实况(n-1)
lw$a0,0($sp)#从日航返回:恢复参数n
lw$ra,4($sp)#恢复返回地址
addi$sp$sp,8#将堆栈指针调整到pop 2项
mul$v0,$a0,$v0#返回n*事实(n-1)
jr$ra#返回给来电者
这是堆栈操作的经典示例
每次函数执行时,它都会增加堆栈并将$ra
和$a0
存储在新分配的位置
您可以看到,$ra
和$a0
是相对于$sp
(堆栈指针)分配的
每次函数执行时,堆栈都会通过从$sp
中减去8
或为两个单词留出足够的空间来展开。类似地,当函数退出时,通过将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堆栈在$v0
中返回1
,当我们加载$a0
时,我们得到2
,因为我们已经收缩了堆栈。所以我们将2
乘以1
,然后返回该值。在下一个堆栈帧中重复相同的过程,我们取$v0
中返回的2
,并将其乘以从堆栈中加载的3
,然后在$v0
中返回6
希望您能从这里看到:
addi $a0 $zero 5
jal fact
将在
$v0
中返回120
,这是我最初看到的情况,但在调用lw或addi$sp,$sp,8之前使用jal fact。这不会导致堆栈上的内容被覆盖吗?不会。jal
只是一个跳转,它也会将当前PC放入$ra
。如果函数要执行8次,它将首先扩展8次,然后收缩8次。好的,那么mul$v0,$a0,$v0呢?因为这是在jal和lws之后,这不意味着我们只是将n乘以1吗?$a0
的值在mul
语句之前重新加载。$v0
的值是由调用事实
决定的。您能给我一个如何工作的示例吗?例如,假设我们通过的数字是5。一步一步会发生什么?