使用寄存器的 RISCV 函数

RISCV function using registers

这段代码使用 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 替换为 for:

int fun(int n) {
    int value = 1;

    for (int counter = 0; counter != n; counter += 1) {
        value += value;
    }

    return value;
}

感谢编译器的美,这三组代码actually generate同一个程序集(在那个特定的编译器上,在我写这篇文章的时候)。


n小于int的精度时,此函数表现为将1左移n位。

在这种非边缘情况下,fun 等同于:

int fun(int n) {
    return 1 << n;
}

如果 n 至少是 int 的精度,那么您会遇到有符号整数溢出,这会导致实现定义的行为。