assembly - RISCV函数使用寄存器
问题描述
使用 RISCV 的这段代码的返回值是多少,
考虑 c 的形式是 int fun(int n)
fun:
addi s0, zero, 0
addi s1, zero, 1
add t0, zero, a0
loop:
beq s0, t0, exit
add s1, s1, s1
addi s0, s0, 1
jal zero, loop
exit:
add a0, zero, s1
jalr zero, 0(ra)
解决方案
有时,在分析汇编时,直接了解 C 中发生的事情可能会有所帮助,然后简化:
int fun(int n) {
int s0 = 0;
int s1 = 1;
int t0 = n; // n is in a0
loop:
if (s0 == t0) {
goto loop_exit;
}
s1 = s1 + s1;
s0 = s0 + 1;
goto loop;
loop_exit:
return s1; // Returns in a0
}
我们可以看到t0
不需要复制到,我们可以n
直接使用。此外,这个goto
结构看起来很像一个while
循环,在开始时对循环进行条件检查。
int fun(int n) {
int s0 = 0;
int s1 = 1;
while (s0 != n) {
s1 += s1;
s0 += 1;
}
return s1;
}
我们现在可以看到s1
它将从 1 开始,然后翻倍n
。我们可以重写给出描述性的名称,并用while
a代替for
:
int fun(int n) {
int value = 1;
for (int counter = 0; counter != n; counter += 1) {
value += value;
}
return value;
}
由于编译器的优点,这三组代码实际上生成了相同的程序集(在那个特定的编译器上,在我写这篇文章的时候)。
当n
小于 的精度时int
,此函数表现为左移 1n
位。
在这种非边缘情况下,fun
等价于:
int fun(int n) {
return 1 << n;
}
如果n
至少是 的精度int
,那么您会遇到有符号整数溢出,这会导致实现定义的行为。
推荐阅读
- java - 从对象列表中获取最大值
- angular - 角度测试 - 表单输入 type="number" 应该只接受数字
- python - 尝试通过 key 从 request.form 获取值时出现 exceptions.badrequestkeyerror(key)
- php - Laravel 6 - 控制器中的更新功能运行但模型未传递给控制器
- asp.net - ASP.NET 突然想要一个斜杠
- mongodb - 如何在猫鼬中检查日期是否小于今天的日期?
- eclipse - Log4J2 - 从 Eclipse 运行时不发生日志记录
- kubernetes - 如何将 n 个不同的配置分配给 n 个 pod
- javascript - 使用 msnodesqlv8 nodejs 连接到数据库
- java - 服务器端请求伪造漏洞