将 C 转换为 MIPS

问题描述

我在将 C 转换为 MIPS 时遇到了一些麻烦。 我目前无法将此 C 代码转换为 MIPS:

int arraySum(int* array,int arraySize)
{
   int result;

   if(arraySize == 0)
      result = 0;
   else
      result = *array + arraySum(&array[1],arraySize-1);

   return result;
}

我在 MIPS 中创建的当前代码在这里

    arraySum:
         addi $sp,$sp,-4
         sw $ra,0($sp)
         
         beqz $a1,rec_done
         li $v0,0
         j rec
    rec:
        addi $a1,$a1,-1
        jal arraySum
        addi $a1,1
    rec_done:
        sll $t2,2
        add $t2,$a0,$t2
        lw $t2,0($t2)
        addu $v0,$t2,$v0

        lw $ra,0($sp)
        addiu $sp,4
        jr $ra

抱歉没有注释掉,我一般都是代码写完之后再打注释

解决方法

您正在做作业,目的不是消除或优化递归,而是以赋值所期望的递归精神翻译函数,因此您可以了解堆栈帧、返回地址、变量一个电话等。

在上面的注释中为编译器示例提供的链接已经对代码进行了如此严格的优化,以至于您应该学习的任何课程都不会保留在生成的代码中。 (我们都知道递归对数组的连续值求和是多余的,但这就是赋值。)

您的代码需要在 jal 之后做一些事情,因为在某些时候(正常工作时)它会在递归 jal 之后返回到指令。

在每个返回路径上都需要进入 $v0 — 返回地址(寄存器 $ra;有时在旧术语中称为链接)和返回值(寄存器 $v0)之间存在差异。两者都是必要的,但它们是不同的概念,所以不要使用/混淆另一个。返回地址是一个指向机器代码指令的指针,用于将处理器指令流的控制权返回给调用者;而这里的返回值只是一个整数值,如 0 或总和,用于将函数答案也称为返回值返回给调用者。

递归是一个函数调用另一个函数(结果是同一个函数)。在处理调用函数时(模高级优化),我们需要保留调用前定义和调用后使用的值。

一方面,返回地址是函数最后需要的参数值,用于返回给调用者(jr $ra)。

另一方面,让我们更仔细地看看这个表达式:

*array + arraySum(&array[1],arraySize-1)

显然,在对 + 的调用返回操作数之前,我们不能添加 (arraySum)。因此,根据您如何编码,调用后需要 array*array。 (它是递归的并不重要:任何以相同方式调用任何东西都需要类似的分析。)

根据 C 语言标准,C 编译器(实现)可以在调用 array 之前或之后自由取消引用 *array(如在 arraySum 中)。无论哪种方式,函数调用后都需要再保留一个值:如果取消引用是事先完成的,则需要保留取消引用元素的值以供函数调用后的 add 使用,或者如果取消引用被延迟,则 {{1 }} 参数本身必须保留,以便在调用后进行取消引用(以及接下来的添加)。

所以,这个函数需要两个项目才能在函数调用中存活下来。一个是返回地址,另一个是 array 参数或 array 元素值。


让我们在函数返回后任意选择取消引用 *array 参数。

使用堆栈空间来保存这些项目——通过分配一个堆栈帧。分配堆栈帧意味着在返回给调用者之前在最后释放它。由于这段代码没有循环表达,因此在这里使用 array 寄存器没有必要或优势,因此函数序言应该简单地分配 2 个字的堆栈空间并将返回地址存储在那里($s),并且$ra (array)。为了在函数调用后进行加法,$a0 参数的值应该从堆栈中重新加载、解引用,并添加到函数调用的返回值 (array) 中。>

函数结尾应该重新加载返回地址($v0)并释放堆栈空间。 (不需要为调用者恢复 ($ra)。)


另一种方法是在函数调用之前解引用$a0,这意味着堆栈空间的一个字将用于保存解引用的值,因此可以在函数调用后重新创建。

同理,分配2个字的栈空间,将返回地址存放在其中一个字中。另一个字用于上述加法表达式的计算,因此取消引用发生在调用之前,其值存储在另一个堆栈分配字中。在函数调用之后,取消引用的值被恢复到一个寄存器中,这样加法的两个操作数现在都在寄存器中并且可以求和为 array

Epilogue 需要恢复返回地址,否则释放栈空间,返回给调用者。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...