如何将涉及数组的高级语言语句转换为 MIPS 32 位?

How to convert a high level language statement involving arrays into MIPS 32 bit?

这是高级函数:J[6] = K[d-e]

d = $t0, e = $t1, J = $s1, K = $s2, 最终结果进入 $s4

到目前为止我有:

lw $t2, 24($s1) #Load J[6] into $t2
sub $t3, $t0, $t1 #Subtract e from d to $t3

我知道我不能做的是 lw $t4, $t3($s2) 但我不确定如何翻译 K[$t0 - $t1]。

这只是我在评论者的帮助下解决了自己的作业问题。此答案的早期修订包括从 J[6] 加载的错误版本,而不是存储和过度使用临时工。

这是伪代码:

x1 = d-e             # store subtraction
x2 = x1 * 4          # scaling by element size
x3 = K + x2          # byte address pointer arithmetic

x4 = *x3             # dereference to fetch K[d-e]
x5 = J + 24          # compute byte address of J[6]
*x5 = x4             # store into J[6] the value of K[d-e]

这是尝试实现,唯一的问题是最后两步,在问题中它指定 $s4 保存最终答案,但 J[6] 仍然需要覆盖,因为那是赋值语句:

sub $t3, $t0, $t1  #Subtract d-e to $t3, next step is multiply by 4 to scale
add $t5, $t3, $t3  # t5 = t3 + t3 = t3 * 2
add $t5, $t5, $t5  # t5 = t5 + t5 = t3 * 4  = (d-e)*4 as a byte offset
add $t3, $s2, $t5  #Add d-e index plus K's 0th index to get final index into $t3 temp

lw $t3, 0($t3)     #Load K's pointer based on index into the value of K
sw $s1, 0($t3)     #Store the value of K into J[6]
sw $s4, 24($s1)    #Store J[6] into $s4, it's 24 because index 6 x 4-byte array element size

后两个的另一种可能性是这样的,我不太确定:

lw $s1, 24($s1)    # compute byte address of J[6], its old value doesn't matter
sw $s1, 0($t3)     #Store the value of K into J[6]
sw $s4, 24($s1)    #Store J[6] into $s4, it's 24 because index 6 x 4-byte array element size

开始:将此语句翻译成汇编,

J[6] = K[d-e];

先来看三地址码,需要梳理一下小操作的方向和顺序:

x1 = d-e             # store subt
x2 = x1 * 4          # scaling by element size
x3 = K + x2          # byte address pointer arithmetic
x4 = *x3             # dereference to fetch K[d-e]
x5 = J + 24          # compute byte address of J[6]
*x5 = x4             # store into J[6] the value of K[d-e]

(请注意,三地址代码从不重用临时变量,尽管在 MIPS 等价物中,这对于 reuse/repurpose 临时结果寄存器(当不再需要旧的临时值时)很常见)。

MIPS 也可以在不单独计算 J+24 的情况下执行 J[6]=,因此不必计算 x5。

* 操作,称为解引用的 C 运算符,当它出现在 = 赋值的右侧时,它作为从内存中获取数据的加载指令完成。当它出现在 = 赋值的左侧时,这是作为将数据存储到内存中的存储指令完成的。


接下来,让我们看看地址计算以及 MIPS 能做什么和不能做什么。

您对 $t3($s2) 的想法是正确的,但 MIPS 做不到。它只能做常量索引。

那么,$t3($s2)代表什么?它是动态索引与基地址的组合,产生元素地址。

在这种(不受支持的形式)$t3($s2) 中,$t3$t2 这两个值如何合并?另外:我们可以给一个指针加一个索引,得到一个新的指针。

但是,因为 MIPS 是字节寻址机器,MIPS 中的地址和指针指的是单个字节。一个字节是一个 8 位数据。所以,当我们在这样的机器上使用指针和地址时,这些地址和指针的类型是byte addresses.

当我们使用32位字时,这些占用多个字节,实际上对于一个32位字来说是4 x 8位字节。当一个32位为数组元素时,word占4个字节,每个字节都有自己的字节地址,所以它也占4个字节地址。

与有时通过其起始地址(其索引 0)引用整个数组的方式类似,整个元素(4 字节)通过其最低字节的地址引用。从一个元素移动到下一个元素,意味着移动 4 字节地址。

因此,给定一个索引,我们将该索引转换为字节偏移量,在此上下文中,这称为缩放。比例因子与数组中元素的大小相同,这里是一个整数数组,因此每个元素 4 个字节。因此比例因子为 4.

所以,我们想要的更像是$t3*4($s2),但是MIPS当然也不能做到这一点。但是使用单独的指令,MIPS可以乘以4,MIPS也可以把动态值加在一起。一旦这些都完成了,我们就可以使用 MIPS 提供的常系数解引用形式——加上附加恒等式,因为我们已经计算了完整的地址。


有两种方法:K[i+1]:

  1. 添加 i1,然后将结果乘以 4,然后添加 K 并在加载或存储指令中使用零作为偏移量。

  2. i乘以4,然后加上K并使用4作为存储指令中的偏移量。

表格 2 使用非零偏移值 4,即 +1 乘以 *4。这恰好比解决方案 1 短 1 条指令。


如何乘以一个小常数如4,假设要乘的数在$t0中,结果希望在$t1:

  1. 给自己加4次,使用目标累加结果:
    add $t1, $t0, $t0     # t1 = t0 + t0 = t0 * 2
    add $t1, $t1, $t0     # t1 = t1 + t0 = t0 * 3
    add $t1, $t1, $t0     # t1 = t1 + t0 = t0 * 4
  1. 给自己加一次,然后给自己加一次
    add $t1, $t0, $t0     # t1 = t0 + t0 = t0 * 2
    add $t1, $t1, $t1     # t1 = t1 + t1 = t0 * 2 + t0 * 2 = t0 * 4
  1. 将数字左移 2(二进制)位
    sll $t1, $t0, 2       # t1 = t0 << 2 = t0 * 4