arrays - 用于二维数组和按位运算的 C 到 MIPS 转换
问题描述
我试图将下面的 C 代码翻译成 MIPS,但不知道如何翻译 m |= c;
上面的 MIPS 代码是什么?
解决方案
让我们分解这个语句:
m |= constant;
这在一个称为赋值运算符的类别中,这些扩展如下:
m = m | constant
^ ^
| |
| +--- source/read
|
+-- target/written
因此,虽然常规赋值 ( =
) 只写,但这些赋值运算符在左侧读取和写入目标表达式。(col++
也是一个读-修改-写操作,可以认为和col += 1
) col = col + 1
。一旦理解,这些赋值运算符就很方便和简洁,并且还有助于我们不必重复复杂的表达式,例如您示例中的数组索引。
运算符|
代表逻辑或。在 C 语言中,该运算符将对两个输入的每一位执行逻辑或运算,以产生相同大小的输出,因此对于int
4 个字节大,将逐个位置执行 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
我们希望在寄存器中并在函数调用中存活的任何其他内容。)
推荐阅读
- c - 为什么这个快速排序算法实现代码会出现分段错误错误?
- python-asyncio - TypeError:对象 NoneType 不能在“等待”表达式中使用
- excel - 如何使用我定义的最后一行作为我的范围的一部分?
- c# - 打印任何希望类的字段名称
- jenkins - 如何在 Jenkins Job DSL 中创建可扩展的基础作业?
- python - 从包含标题和分隔符的文本文件中提取列
- facebook-graph-api - 为什么从 graph.facebook 返回的个人资料图片 URL 会导致 404
- java - url中的字符串自定义排序顺序
- python - 在 python 3.6 中将不同的日期字符串转换为 unix 时间戳
- python - 通过使用 for 循环更改一列来创建多个数据框?