如何在 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
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