assembly - 为什么 lw 指令的第二个参数同时采用偏移量和 regSource?

标签 assembly mips cpu-architecture

所以lw指令的格式如下:lw RegDest, Offset(RegSource)。为什么第二个参数同时采用偏移量和寄存器源?为什么不只有一个(即仅注册源)?

最佳答案

因为您还要对 32 位指令字的其余部分做什么? (假设您是设计 MIPS 指令集的 CPU 架构师)。

它允许LUI + LW 在 2 条指令(而不是 3 条)中从任意 32 位地址加载。以及 for 循环展开或结构指针->成员访问,避免指针数学的 ADDIU 指令。即在 LW/SW 上花费大量的编码空间可以使 MIPS 程序更加高效。有时您只需要 0($reg),但其他时候这将是浪费指令来计算寄存器中的最终地址。

省略 16 位立即移位不能使指令更短。 MIPS 是一种具有固定长度指令字的 RISC。 (它可以是 R 类型而不是 I 类型,但该格式中仍然有未使用的位。经典 MIPS 有大量未使用的编码空间,并且将编码空间花费在 LW/SW、LB/LBU/SB 和等等,这是值得的。)

MIPS 没有很多不同的操作码(尤其是没有任何 FPU 指令且没有 64 位指令的经典 MIPS)。它使用大量指令编码空间来支持大多数指令的立即数形式,并具有较大的立即数。 (与 ARM32 不同,ARM32 在每条指令中使用 4 位用于谓词执行,更多位用于“灵活”源操作数(可选通过常量或另一个寄存器或立即常量进行循环或移位)。但是 ARM 立即数被编码为 8具有旋转的位,允许使用现实生活中常见的许多有用的位模式。)


MIPS 只有一种寻址模式,与仅 (reg) 相比,imm16(reg) 可以节省大量 addiu 指令

例如,考虑一个加载或存储静态(或全局)变量的 C 函数。喜欢

unsigned rng(void) {
    static unsigned seed = 1234;
    return (seed = seed * 5678 + 0x1234);
}

编译器生成的(或手写的)asm需要从seed加载和存储,因此您需要将其存储在寄存器中。但它是一个 32 位常量,不适合单个指令。在手写汇编中,您可能会使用像 la $t0, rng.seed 这样的伪指令,它将汇编为 lui $t0, hi(rng.seed)/ori $t0, $t0, lo(rng.seed). (hi 和 lo 获得 32 位地址的一半)。

但你可以做得更好:

lui   $t0, hi(rng.seed)
lw    $t1, lo(rng.seed) ($t0)

即使用地址的低16位作为加载指令中的16位位移。这实际上就是compilers like gcc do :

rng:    # gcc5.4 -O3
    lui     $5,%hi(seed.1482)
    lw      $4,%lo(seed.1482)($5)
    nop                       ; classic MIPS has a 1-cycle "shadow" for loads before the result is usable, with no pipeline interlock
    sll     $3,$4,5          ; I should have picked a simpler multiply constant (with fewer bits set)
    sll     $2,$4,3
    subu    $2,$3,$2
    sll     $3,$2,3
    subu    $2,$3,$2
    subu    $2,$2,$4
    sll     $3,$2,4
    addu    $2,$2,$3
    sll     $2,$2,1
    addiu   $2,$2,4660
    j       $31
    sw      $2,%lo(seed.1482)($5)       ; branch-delay slot

seed.1482:
    .word   1234

寄存器中的小立即位移还有很多其他用途。例如:

  • 如果编译器溢出任何内容,则访问堆栈上的局部变量
  • 结构体字段
  • 展开循环中的数组访问。 (MIPS 有 32 个整数寄存器,几乎是为软件流水线设计以展开循环)。
  • 小型编译时常量数组索引。

正如我所说,对于那些额外的 16 位指令字,您没有什么可以做的,这非常适合 MIPS。您可以为位移保留少于 16 位,但 MIPS 不是 PowerPC(其中有很多很多操作码)。

关于assembly - 为什么 lw 指令的第二个参数同时采用偏移量和 regSource?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48140313/

相关文章:

assembly - Bochs无法加载img文件并加载

assembly - MIPS 和 ARM 数据路径之间的区别

java - volatile 语句的负载屏障在哪里?

assembly - 我可以从 EAX/RAX 获取 int 到 FPU 的寄存器(如 st0)吗?

linux - 如何打印单个 ASCII 字符?

c# - 处理器架构问题(x86 与任何 cpu)

intel - 为什么 Intel Haswell XEON CPU 偶尔会错误计算 FFT 和 ART?

arrays - 向地址添加直接值

基于 MIPS 的架构中的 C 程序错误

assembly - 关于加载字 (lw) 与加载地址 (la) 以及 mips 程序集中偏移的混淆?