首页 > 解决方案 > 用于二维数组和按位运算的 C 到 MIPS 转换

问题描述

我试图将下面的 C 代码翻译成 MIPS,但不知道如何翻译 m |= c; 上面的 MIPS 代码是什么?

标签: arrayscassemblybit-manipulationmips

解决方案


让我们分解这个语句:

m |= constant;

这在一个称为赋值运算符的类别中,这些扩展如下:

m = m | constant
^   ^
|   |
|   +--- source/read
|
+-- target/written

因此,虽然常规赋值 ( =) 只写,但这些赋值运算符在左侧读取和写入目标表达式。(col++也是一个读-修改-写操作,可以认为和col += 1) col = col + 1。一旦理解,这些赋值运算符就很方便和简洁,并且还有助于我们不必重复复杂的表达式,例如您示例中的数组索引。

运算符|代表逻辑或。在 C 语言中,该运算符将对两个输入的每一位执行逻辑或运算,以产生相同大小的输出,因此对于int4 个字节大,将逐个位置执行 32 个单独的“或”运算。

与常量“或”用于设置相应的位——常量中有 1 时,该位的输出将为 1,而常量中有 0 时,该位的输出将是另一个输入的值(在那个位位置)。

这就是说:取 的当前值m,然后在常数中进行 OR,然后写入该值以成为 的新当前值m

MIPS 有一个or指令和ori指令。

如果变量m在寄存器中,这可以在一条指令中完成,假设常量将适合 16 位立即数形式(否则,程序员,在某些情况下是汇编程序,可能会将其转换为两条或三条指令,额外一两个来显示完整的常量值,然后是 MIPS 或指令)。该or指令将为m.

但是,如果变量,m在内存中,那么,因为 MIPS 是一个加载/存储机器,我们必须将一个副本加载m到寄存器中,然后执行or操作(如上所述),然后将它存储回内存中以更新它所在的变量。

数组——更具体地说是它们的所有元素——必须在内存中,所以它们需要这种完整的处理。您已经有一个计算来获取元素的地址。


大多数人会使用移位:sll $t3, $t2, 2乘以 4,因为这在低端硬件上可能更便宜。

不要忘记row=0;在开始时进行初始化,而不是依靠模拟器来清除寄存器。

(并且不要忘记增加col++。)

作为la一种优化,网格可以移动到循环之外和之前,因为它产生的值在循环执行期间不会改变。(这称为循环不变代码运动$t0。)如果你这样做,只要它仍然需要,就不要破坏代码的另一部分。

汇编中还有其他可能的优化,例如row在外部循环而不是内部循环中进行第一次乘法(乘以列大小),因为在内部循环中,row变量不会改变,所以这是一个常数值对于内部循环的每次执行。

这些代码运动优化中的每一个都需要使用额外的 CPU 寄存器(在某个循环的持续时间内),这就是 MIPS 和其他较新的处理器具有如此多寄存器的原因之一。

(进一步的优化也可以通过从数组索引更改为指针,然后从重新计算元素的字节地址,到将该地址作为在整个循环中有效的变量来维护。)

建议总体上坚持使用$t寄存器,其中有 10 个非常适合您的代码。($s寄存器应该在使用时保存和恢复,它们由进行函数调用的代码使用,所以如果你的循环体有一个函数调用作为它的一部分或作为赋值语句的一部分,我们会选择$s寄存器row以及col我们希望在寄存器中并在函数调用中存活的任何其他内容。)


推荐阅读