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

coc*_*s93 -2 arrays assembly mips mips32

这是高级函数: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
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*idt 5

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

\n
J[6] = K[d-e];\n
Run Code Online (Sandbox Code Playgroud)\n

首先我们看一下三地址码,这需要我们梳理出较小操作的方向和顺序:

\n
x1 = d-e             # store subt\nx2 = x1 * 4          # scaling by element size\nx3 = K + x2          # byte address pointer arithmetic\nx4 = *x3             # dereference to fetch K[d-e]\nx5 = J + 24          # compute byte address of J[6]\n*x5 = x4             # store into J[6] the value of K[d-e]\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

此外,MIPSJ[6]=无需单独计算即可完成此操作J+24,因此无需计算 x5。

\n

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

\n
\n

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

\n

你对 的想法是正确的$t3($s2),但 MIPS 不能做到这一点。\xc2\xa0 它只能做常量索引。

\n

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

\n

在此(不支持的形式) 中$t3($s2),这两个值$t3$t2如何组合?\xc2\xa0 通过加法:我们可以向指针添加索引并获取新指针。

\n

然而,由于 MIPS 是字节可寻址的机器,所以 MIPS 中的地址和指针指的是各个字节。\xc2\xa0 一个字节是一个 8 位数据。\xc2\xa0 因此,当我们在这样的机器上使用指针和地址时,这些地址和指针的类型是字节地址

\n

当我们使用 32 位字时,这些字占用多个字节,实际上 32 位字占用 4 x 8 位字节。\xc2\xa0 当 32 位是数组的元素时,该字占用 4 个字节,每个其中有自己的字节地址,因此也占用4个字节地址。

\n

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

\n

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

\n

所以,我们想要的更像是$t3*4($s2),但是当然 MIPS 也不能做到这一点。\xc2\xa0 但是使用单独的指令,MIPS 可以乘以 4,并且 MIPS 还可以将动态值加在一起。\xc2\xa0 一旦这些完成,我们可以使用 MIPS 提供的具有加性恒等式的 \xe2\x80\x94 的常数系数解引用形式,因为我们已经计算了完整的地址。

\n
\n

有两种方法可以做到K[i+1]::

\n
    \n
  1. i和相加1,然后将该结果乘以 4,然后相加K并使用零作为加载或存储指令中的偏移量。

    \n
  2. \n
  3. 乘以i4,然后添加K并使用 4 作为存储指令中的偏移量。

    \n
  4. \n
\n

形式 2 使用非零偏移值 4,即按 *4 缩放的 +1。\xc2\xa0 这恰好比解决方案 1 短 1 条指令。

\n
\n

如何乘以像 4 这样的小常数,假设要相乘的数字在 中$t0,并且希望结果在 中$t1

\n
    \n
  1. 将数字与自身相加 4 次,使用目标累加结果:
  2. \n
\n
    add $t1, $t0, $t0     # t1 = t0 + t0 = t0 * 2\n    add $t1, $t1, $t0     # t1 = t1 + t0 = t0 * 3\n    add $t1, $t1, $t0     # t1 = t1 + t0 = t0 * 4\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 将数字与其自身相加一次,然后将该数字与其自身相加一次
  2. \n
\n
    add $t1, $t0, $t0     # t1 = t0 + t0 = t0 * 2\n    add $t1, $t1, $t1     # t1 = t1 + t1 = t0 * 2 + t0 * 2 = t0 * 4\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 将数字左移 2 位(二进制)
  2. \n
\n
    sll $t1, $t0, 2       # t1 = t0 << 2 = t0 * 4\n
Run Code Online (Sandbox Code Playgroud)\n

  • 这三种方式是等效的——它们达到相同的结果,只是指令数量不同(以及如何处理溢出,但这是另一回事)。我没有提到使用 `mul`,但这也是等效的。 (2认同)