RISC-V汇编递归函数栈:如何用非保留寄存器替换n为n-1?
解决RISC-V递归函数累加逻辑错误的问题
你的递归函数目标是实现 a0 = (n-1) + factorial(n-1) 的累加逻辑,但当前代码在递归返回后用了入栈前的原始n进行计算,导致结果不符合预期:输入7得到0x0000001c而非预期的0x00000015,输入5预期1+2+3+4=10(0x0000000a)也出错。
问题根源
看else分支的执行流程:
- 你先把
a0减1得到n-1,然后调用递归 - 但入栈的是减1之前的原始n(
function开头的sw a0, 4(sp)) - 递归返回后,从栈里取出的
t1是原始n,所以add a0, t1, a0实际执行的是原始n + factorial(n-1),和需求的(n-1) + factorial(n-1)相差1。
两种可行修改方案
方案1:累加前将原始n减1
直接在取出t1后,把它调整为n-1再进行累加:
else: addi a0, a0, -1 # n = n − 1 jal function # 递归调用 lw t1, 4(sp) # 取出原始n lw ra, 0(sp) addi sp, sp, 8 addi t1, t1, -1 # 将原始n转为n-1 add a0, t1, a0 # 执行a0 = (n-1) + factorial(n-1) jr ra
方案2:入栈时直接存储n-1
提前计算n-1并存入栈,避免后续二次计算:
function: addi sp, sp, -8 # 分配栈空间 sw ra, 0(sp) # 先存返回地址 addi t0, zero, 1 # 临时变量=1 bgt a0, t0, else # n>1则跳转到else addi a0, zero, 1 # n<=1时返回1 addi sp, sp, 8 # 回收栈空间 jr ra # 返回 else: addi t1, a0, -1 # 计算n-1并存入t1 sw t1, 4(sp) # 将n-1存入栈(替换原来的原始n) addi a0, a0, -1 # a0改为n-1用于递归调用 jal function # 递归调用 lw t1, 4(sp) # 直接取出预存的n-1 lw ra, 0(sp) addi sp, sp, 8 add a0, t1, a0 # 执行累加 jr ra # 返回
关于你之前尝试的问题
你提到用其他寄存器存储n-1却出错,大概率是存储时机不对:如果在递归调用之后才去计算n-1,此时原始n已经被递归调用覆盖;或者用了临时寄存器(如t0-t6),这类寄存器在递归函数中可能被修改,导致数值丢失。正确的做法是在递归调用前就把n-1存入栈(或保存到s0-s11这类被调用者保存寄存器),确保递归返回后数值还在。
验证结果
修改后:
- 输入5时,计算
1+2+3+4=10,对应0x0000000a,符合预期 - 输入7时,计算
1+2+3+4+5+6=21,对应0x00000015,结果正确
内容的提问来源于stack exchange,提问作者RDL
相关产品推荐
相关产品推荐

