将以下高级代码翻译成 MIPS 汇编代码

Translating the following high level code into MIPS Assembly code

我已经把这个C程序翻译成了MIPS汇编代码。 所以,在这里我想知道:

  1. 我是不是做错了什么?
  2. 如果我的汇编代码是正确的,我可以通过减少 指令数。我在这里使用了14条指令

这是我转换这个 C 程序的方法 这是我的 MIPS 汇编代码

#s0 = res

main:
    addi $a0 , [=10=] , 27
    addi $a1 , [=10=] , 3
    jal division            # call function 
    add $s0 , $v0 , [=10=]      # res = returned value



division:
    addi $t0 , [=10=] , 0       # $t0 = 0
    addi $s0 , [=10=] , 0       # $s0 = val and val = 0
    add $s1 , [=10=] , $a0      # $s1 = i   and i = 27
    
loop:
    slt $t1 , $s1 , $t0      # checking if i>0
    bne $t1 , [=10=] , break     # if $t1 = 0 then break
    addi $s0 , $s0 , 1       # else val = val + 1
    sub $s1 , $s1 , $a1      # i = i - y
    add $v0 , $s0 , [=10=]       # put return value in $v0
    j loop

break:
     jr $ra                  # return to caller

这是高级 C 程序

int main(){

    int res;
    res = division (27, 3);

}

 int division(int x, int y)
{
    int i;
    int val = 0;
    for (i = x; i>0; i = i-y){
        val = val + 1;
    }

    return val;
}

错误:

关系被错误地否定了。您已将其翻译为

for ( i = x; i >= 0; i -= y )

所以,它会比你想要的多循环一次(当整数除法是精确的时候)。您知道循环条件测试需要对 if-goto-label 样式的程序集取反:

if ( ! (i > 0) ) goto break;

然而 ! (i > 0)i <= 0 你有 i < 0.

你没有在main结束的时候正确终止程序,所以会不小心掉到divide子程序中。解决方案是向 main.

添加一个退出系统调用

建议:

寄存器使用过多,使用较少的寄存器也会减少所需的指令数。此外,使用 $s 寄存器而不保留其原始值违反了调用约定。但是,最好的解决方案是简单地避免在该函数中使用它们——直接使用 $a0$a1 而不是将它们复制到其他地方。

(可以在 main 中使用 s 寄存器而不保留它们的原始值,b/c main 位于调用链的顶部——它有没有调用者——相比之下,我们可能会将 division 视为可以从任何调用者调用的通用函数,因此应遵循调用约定。)

我们不仅要尽量减少指令,还要尽量减少循环中的指令数。您正在通过将 $s0 复制到 $v0 来完成“return val”的工作,但每次都在循环中,而只需要一次,因此最好留到循环之后.更好的是,首先简单地使用 $v0 作为计数器 (val)。

slt 指令有一个等效的 slti 指令,在与常数进行比较时非常方便。使用 slti,无需将常量 0 加载到 $t0 寄存器。如果您确实需要在寄存器中使用常量 0,那么总有 [=33=] 寄存器。

MIPS指令集有与零比较的关系分支指令,因此您可以直接在寄存器<= 0(或< 0)上分支而无需slt/slti.