如何在 RISC-V 中实现阶乘函数

How to implement factorial function in RISC-V

    C-code  :

int factorial(int n) 
{
if (n<1) return 1;
 else return n * factorial (n-1);
}

我已经尝试实现它,但没有成功。所以这是我的尝试:

     goto:

 factorial:
 int factorial(int n) {
 if (n<1) goto Lthen;

 Lelse:
 tmp=factorial(n-1);
 return n*tmp;
 goto Lend;

 Lthen: return 1;
 Lend;
 }



 RISC V:
.factorial
 addi sp, sp,  -16
 sw ra, (sp)
 sw s0, 4(sp) //n
 sw s1, 8(sp) //tmp
 mv s0, a0               //a--->s0
 addi t1, zero,1 
 blt s0, t1, Lthen

   .Lelse
   mv t0, s0          // copy of n to t0
   addi s0, s0, -1   // n-1
   mv a0, s0;        // n-1--->a0
   jal factorial // factorial(a0)
   mv s1, a0         // s1=factorial(a0) //tmp
   mul a0,t0,s1        //  n*tmp ----> a0 
   ret
   j LEND



Lthen: li a0,1
ret
LEND jr ra, 0 

谁能告诉我这样可以吗,因为我不知道如何测试它。 我不确定例如 return 1 / 或任何其他 value/expression,我们可以把它放在 a0 中然后说 ret..

感谢您的宝贵时间!

您应该使用 $s0 作为保留值,而不是 $t0

在递归调用之前从 $s0 复制后,您应该从 $a0 减一。

乘法将介于 $a0 return 值和 $s0 保留值之间。

$s0 有效但 $t0 无效(以保留原始 $a0 输入)的原因是您正在(正确)努力保存 s 注册。

但是,您没有恢复函数尾声中保存的值,也没有削减堆栈,也没有重新加载 $ra...

这是我 RV32I assembly programmer's quick reference 的 RISC-V 递归阶乘函数:(欢迎评论!)

.text  # recursive implementation of factorial
.globl __start
fact:       # arg: n in a0, returns n! in a1
    addi  sp, sp, -8    # reserve our stack area
    sw ra, 0(sp)    # save the return address
    li t0, 2
    blt a0, t0, ret_one # 0! and 1! == 1
    sw a0, 4(sp)    # save our n
    addi a0, a0, -1
    jal fact        # call fact (n-1)
                    # a1 <- fact(n-1)
    lw t0, 4(sp)    # t0 <- n
    mul a1, t0, a1  # a1 <- n * fact(n-1)
    j done
ret_one:
    li a1, 1
done:
    lw ra, 0(sp)    # restore return address from stack
    addi sp, sp, 8  # free our stack frame
    jr ra           # and return

__start:
    li a0, 5        # compute 5!
    jal fact
    li a0, 1        # print it
    ecall
    li a0, 17
    ecall       # and exit

为了测试它,我最喜欢的轻量级 RISC-V 模拟器是 Venus and Jupiter