问题描述
我正在阅读一些关于将 C 语句转换为 MIPS 的 MIPS 注释。
swap ( int v[],int k) {
int temp;
temp = v[k];
v[k] = v[k + 1];
v[k + 1] = temp;
}
我被告知 k 映射到 $5,v[] 的基地址映射到 $4,temp 映射到 $15。 交换函数接受参数 k = 3 并假设 v 的基地址是 2000。
以下简化的 MIPS 版本:
swap:
sll $2,$5,2
add $2,$4,$2
lw $15,0($2)
lw $16,4($2)
sw $16,0($2)
sw $15,4($2)
这里的困惑是为什么翻译后的 MIPS 中有 sll 和 add?
解决方法
这来自于 byte addressable,就像大多数现代机器一样。
字节寻址意味着处理器可以访问内存的每个单独字节——在这样的系统中,将有效字节地址值加 1 意味着引用内存的下一个连续字节。
int
数据类型使用的字为 32 位宽,因此需要 4 个字节的内存。因此,a[0]
占用字节addr+0
、addr+1
、addr+2
和addr+3
,其中addr
是a
的字节地址. a[1]
与 a[0]
偏移 4 个字节,位于 addr+4
!
C 知道“int
数组”的元素每个需要 4 个字节,因此 4 个字节分隔,因此它知道引擎盖下的 a+i
表示 a + i * 4
,这将引用到数组中每个元素的 4 个连续地址,从 i*4
开始,为所有较低的元素留出空间。
计算 i * 4
有时被称为“缩放”。而在 C 中我们可以直接引用索引位置 a[i]
,而在汇编中我们必须显式地缩放索引。
sll
是乘以 4 的有效方法——sll
中的常数 2 表示向左 2 位(又名:* 1002,即 * 100 二进制)。
加法将数组基数与缩放索引相加,以得出数组引用所需字的实际地址。
我们还可以看到使用常量 0 或 4 生成的代码。因为这些常量也被缩放,所以 4 指的是超出计算值的数组的下一个元素。也就是说,如果 0($2)
指的是 a[k]
,那么 4($2)
指的是 a[k+1]
。