我正在尝试在 MIPS/QtSpim 中编写以下序列:
a_n = a_n-1 + 2a_n-2
其中 a_0 = a_1 = 1
代码应提示用户输入 n 的值并显示 结果在控制台中。我需要对嵌套使用递归 过程链接以实现代码。
我试过下面的代码,但是如果我输入 n 大于 2,我会一直遇到错误:
.data
a0: .word 1
a1: .word 1
n: .word 0
an: .word 0
.text
.globl main
main:
# Prompt user to enter the value of n
li $v0, 4
la $a0, prompt
syscall
# Read the value of n from the user
li $v0, 5
syscall
move $s0, $v0
# Call the sequence function
move $a0, $s0
jal sequence
# Display the result
li $v0, 1
lw $a0, an
syscall
# Exit program
li $v0, 10
syscall
sequence:
addi $sp, $sp, -4
sw $ra, 0($sp)
beq $a0, 0, a0_case
beq $a0, 1, a1_case
addi $a0, $a0, -1
jal sequence
lw $t0, an
addi $a0, $a0, -1
jal sequence
lw $t1, an
add $v0, $t0, $t1
sll $t1, $t1, 1
add $t0, $t0, $t1
sw $t0, an
j end
a0_case:
li $v0, 1
sw $v0, an
j end
a1_case:
li $v0, 1
sw $v0, an
end:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
.data
prompt: .asciiz "Enter the value of n: "
.text
该代码不遵循调用约定。您是想使用标准调用约定还是自己编写?
在任何情况下,寄存器都会混淆,递归调用会破坏属于递归调用者的值。不用说,CPU 寄存器一次只能保存一个值,因此,如果/当重新用于保存不同的变量时,那么前一个变量的值就会丢失。
$a0
不是离开任何给定递归调用的参数 aN
的安全位置,因为每个递归调用都会修改该寄存器。在第一次递归调用之后需要该参数以便进行第二次此类调用,但它已被第一次递归调用删除。
$t0
也不是临时数据的安全位置,因为它在第二次递归调用后无法存活,因为从广义上讲,该函数还会修改 $t0
:
jal sequence
lw $t0, an # t0, assigned here, will be wiped out by the next jal
# if the recursion is deep enough
addi $a0, $a0, -1
jal sequence
lw $t1, an
add $v0, $t0, $t1 # but this code expects it to have a meaningful value
# e.g. as per the above assignment!
# but it doesn't since the recursive call
# also used $t0 for its own purposes.
使用全局变量 an: .word 0
来存储递归函数的返回值也容易出错。返回值应该只在$v0
单独返回。从广义上讲,全局变量不是线程安全的,不可重入的,也不是递归友好的,所以根据调用约定使用 CPU 寄存器和调用堆栈而不是全局变量。
以下代码序列将 $v0
和 an
设置为不同的值。我没有看到 $v0
在任何地方被使用,所以 add
指令没有意义。
lw $t1, an
add $v0, $t0, $t1
sll $t1, $t1, 1
add $t0, $t0, $t1
sw $t0, an
j end