assembly 带栈递归函数

bvk5enib  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(106)

我如何使用一个非保留的寄存器是(n-1)indead的n,而我做的递归(行26)?我已经尝试存储在不同的寄存器,但结果是错误的,任何想法?

main:
addi a0, zero, 7       # a1 = 7
jal function
j L

function:
addi sp, sp, -8 # save regs
sw a0, 4(sp)
sw ra, 0(sp)
addi t0, zero, 1 # temporary = 1
bgt a0, t0, else # if n>1, go to else
addi a0, zero, 1 # otherwise, return 1
addi sp, sp, 8 # restore sp
jr ra # return

else:
addi a0, a0, -1 # n = n − 1
jal function # recursive call
lw t1, 4(sp) # restore n into t1
lw ra, 0(sp) # restore ra
addi sp, sp, 8 # restore sp
add a0, t1, a0 # a0=(**n**)+factorial(n−1)   <---------- NEED to BE: a0=(**n-1**)+factorial(n−1)
jr ra # return

当我运行代码时,a0的结果将是0x 0000001 c而不是0x 00000015。因为它也迭代了已经传递的参数,当它应该是-1时。换句话说,如果例如我向函数传递5,结果应该是:1+2+3+4 = 10 -〉0x000000a。

syqv5f0l

syqv5f0l1#

如果在函数调用后需要的是n-1,有几个选项:
1.从递归调用后保存的内存n开始重新计算n-1-因此在使用t1之前从t1中减去1-考虑到代码已经是如何工作的,还有什么比从n再次计算n-1更简单的呢?
1.但是,您不一定需要在函数序言中存储n-只需在那里为它保留空间。
等到n-1被计算出来后再存储到堆栈槽中。当你重新加载它时,它已经被前面的参数计算中的-1调整过了。这样,每次递归调用只会减1一次。
如果在C代码中重复了n-1的表达式,哑编译器(或未处于优化模式的编译器)将重新计算n-1,如return n-1 + function(n-1)n-1在源代码中说了两次,所以在简单模式下,编译器会做两次。
然而,可以自己进行优化,如下所示:

int m = n-1;
    return m + function(m);

这样,n本身在函数之后就不再需要了,但是m,所以它的代码看起来像我的选项(2)。
你也可以把整个序言移到else:部分,这样做不会保存太多,但是这样做是自由的,所以基本情况根本不需要分配堆栈空间(只是基本情况并不真正在关键路径上并且缩短它通常会有所帮助但不如缩短递归情况那么多,取决于这个函数的平均输入值)。只是要确保在基本情况下省略等效的堆栈恢复。
我们还要注意,如果function:调用function2:而不是它自己,堆栈处理、计算和变量保存/恢复需要完全相同-换句话说,函数调用需要正确的堆栈处理,递归不会增加常规函数调用以外的开销或规则(只要系统使用调用堆栈)。

相关问题