0

我目前正在学习 MIPS,并希望对存储/加载字进行一些说明。

是:

sw $t0, 4($s0) 

一样

addi $s0, $s0, 4 # offsets are in bytes/word 8*4*4
sw   $t0, 0($s0)

此外,我了解偏移量是 16 位有符号立即数。但是,如果它比 32 位立即数更大呢?

例子

sw $t0, x($s0) # x is a 32bits offset
4

1 回答 1

0

如果它比 32 位立即数更大怎么办?

然后 MIPS 指令字必须更长,比如 48 位,才能为操作码和寄存器号加上 32 位立即数留出空间。


但我想你是在问如果你有一个太大而不能用作立即数的 32 位偏移量怎么办?

lui显而易见的方法是自己进行所有地址计算,用/将 32 位值具体化到一个临时寄存器中addiu,然后用addu它来计算寄存器中的最终地址。(因为 MIPS 没有 reg+reg 寻址模式,只有reg+imm16)。但是,我们根本不会在负载中利用 imm16。

我们可以通过使用偏移的低部分作为加载中的立即数来做得更好,只使用 2 个额外的指令而不是 3 个。编译器知道这个技巧,所以很容易展示一个例子:

char foo(char *p) {
    return p[0x123456];
}

在 Godbolt 编译器资源管理器上使用MIPS gcc5.4 编译到这个 asm:

# gcc5.4 -O3 -fno-delayed-branch
foo:
        li      $2,1179648              # 0x120000
        addu    $4,$4,$2
        lb      $2,13398($4)            # 0x3456($4)
        j       $31
        nop

$4$a0$2$v0。所以这是reg += %hi(0x123456)用 lui / addu 做的,然后%lo(0x123456)用作它的偏移量。

如果您使用静态数组和寄存器索引,则应该可以使用类似的技巧,但这不是 GCC 实际所做的。可能是因为它不知道静态地址的低 16 位是否会设置其高位,因此符号扩展为地址的上半部分创建了一个可能的非一。也许没有重定位类型可以解决这个问题并%hi()根据零件的高位调整%lo()零件,使得这种优化不可能:/

我使用charC 不会缩放我的索引:数组索引 = 字节偏移量,因为sizeof(char) = 1. lb是对字寄存器的符号扩展加载,因为这就是 MIPS 的调用约定对窄参数起作用的方式。

于 2019-10-16T20:25:07.000 回答