我正在尝试从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)
我的代码正确还是本书正确?
答案 0 :(得分:1)
两个版本在逻辑上都是正确的;本书版本的唯一问题是效率很低。
无法基于6
是一个汇编时间常数这一事实进行优化,因此6*4
可以是lw
中的立即位移,而不是在运行时计算一个寄存器,并分别添加到库中。
lw
可以容纳16位立即偏移量;不利用并限制自己只使用0
是很愚蠢的。由于某种原因,它是一种I型指令,它专用大量的编码空间来允许较大的偏移量。
除此之外,您的版本是等效的。书籍版本在寄存器中计算6<<2
,并将其添加到B
($s2
)的基数中。通过将初始6
添加到零寄存器,将其放入寄存器。
您和本书都使用add
而不是addu
。不知道为什么要陷在有符号的溢出上,尤其是在进行地址数学运算时。 C编译器通常始终使用addu
。 (在C语言中,签名溢出是未定义的行为,但是编译器开发人员知道,通常它比起引发异常更有用/静默包装)。