使用LW的位移对已知常数索引进行MIPS阵列索引?

时间:2019-01-03 20:30:30

标签: assembly mips micro-optimization

我正在尝试从C转换嵌套数组p=A[B[6]]的这行代码,这是我在研究MIPS的书中发现的。 因为我很确定书中的解决方案是错误的,或者至少比它需要的解决方案复杂得多。

数组A []的基地址存储在寄存器$ s1中,数组B []的基地址存储在$ s2中,而g的值存储在$ s0中。

我对p=A[B[6]]的翻译是(请告诉我它是否正确):

lw $t0, 24($s2) #load from memory B[6] in the register $t0
sll $t0, $t0, 2 #$t0=$t0*4
add $t0, $t0, $s1 #add to $t0 the address of A[B[6]]
lw $t0, 0($t0) #$t0=A[B[6]]

相反,这本书(充满其他错误)提供了以下解决方案:

addi $t0, $0, 6
sll sll $t0, $t0 2 
add $t1, $s2, $t0 
lw $t2, 0 ($t1)
sll $t2, $t2 2 
add $t3, $s1, $t2
lw $s0, 0 ($t3)

我的代码正确还是本书正确?

1 个答案:

答案 0 :(得分:1)

两个版本在逻辑上都是正确的;本书版本的唯一问题是效率很低。

无法基于6是一个汇编时间常数这一事实进行优化,因此6*4可以是lw中的立即位移,而不是在运行时计算一个寄存器,并分别添加到库中。

lw可以容纳16位立即偏移量;不利用并限制自己只使用0是很愚蠢的。由于某种原因,它是一种I型指令,它专用大量的编码空间来允许较大的偏移量。

除此之外,您的版本是等效的。书籍版本在寄存器中计算6<<2,并将其添加到B$s2)的基数中。通过将初始6添加到零寄存器,将其放入寄存器。

您和本书都使用add而不是addu。不知道为什么要陷在有符号的溢出上,尤其是在进行地址数学运算时。 C编译器通常始终使用addu。 (在C语言中,签名溢出是未定义的行为,但是编译器开发人员知道,通常它比起引发异常更有用/静默包装)。