如何将涉及数组的高级语言语句转换为 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]
:
添加 i
和 1
,然后将结果乘以 4,然后添加 K
并在加载或存储指令中使用零作为偏移量。
将i
乘以4,然后加上K
并使用4作为存储指令中的偏移量。
表格 2 使用非零偏移值 4,即 +1 乘以 *4。这恰好比解决方案 1 短 1 条指令。
如何乘以一个小常数如4,假设要乘的数在$t0
中,结果希望在$t1
:
中
- 给自己加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
- 给自己加一次,然后给自己加一次
add $t1, $t0, $t0 # t1 = t0 + t0 = t0 * 2
add $t1, $t1, $t1 # t1 = t1 + t1 = t0 * 2 + t0 * 2 = t0 * 4
- 将数字左移 2(二进制)位
sll $t1, $t0, 2 # t1 = t0 << 2 = t0 * 4
这是高级函数: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]
:
添加
i
和1
,然后将结果乘以 4,然后添加K
并在加载或存储指令中使用零作为偏移量。将
i
乘以4,然后加上K
并使用4作为存储指令中的偏移量。
表格 2 使用非零偏移值 4,即 +1 乘以 *4。这恰好比解决方案 1 短 1 条指令。
如何乘以一个小常数如4,假设要乘的数在$t0
中,结果希望在$t1
:
- 给自己加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
- 给自己加一次,然后给自己加一次
add $t1, $t0, $t0 # t1 = t0 + t0 = t0 * 2
add $t1, $t1, $t1 # t1 = t1 + t1 = t0 * 2 + t0 * 2 = t0 * 4
- 将数字左移 2(二进制)位
sll $t1, $t0, 2 # t1 = t0 << 2 = t0 * 4