【问题标题】:Why does the lw instruction's second argument take in both an offset and regSource?为什么 lw 指令的第二个参数同时包含偏移量和 regSource?
【发布时间】:2020-06-01 23:44:41
【问题描述】:

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

【问题讨论】:

    标签: assembly mips cpu-architecture


    【解决方案1】:

    因为你还打算用剩下的 32 位指令字做什么? (假设您是设计 MIPS 指令集的 CPU 架构师)。

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

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

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


    MIPS 只有一种寻址模式,imm16(reg) 可以节省大量的 addiu 指令,而不是 (reg)

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

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

    编译器生成(或手写)的 asm 需要从 seed 加载和存储,因此您需要将它放在寄存器中。但它是一个 32 位常量,不适合单条指令。在手写 asm 中,您可能会使用像 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
    

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

    • 如果编译器溢出任何内容,则访问堆栈上的局部变量
    • struct 字段
    • 展开循环中的数组访问。 (MIPS 有 32 个整数寄存器,并且非常适合软件流水线来展开循环)。
    • 小型编译时常量数组索引。

    正如我所说,对于非常适合 MIPS 的额外 16 位指令字,您无能为力。您可以为置换保留少于 16 位,但 MIPS 不是 PowerPC(其中有很多很多操作码)。

    【讨论】:

      猜你喜欢
      • 2021-10-31
      • 2019-11-13
      • 2017-08-03
      • 1970-01-01
      • 2016-07-28
      • 2020-07-31
      • 1970-01-01
      相关资源
      最近更新 更多