为什么lw指令的第二个参数同时接受offset和regSource? [英] Why does the lw instruction's second argument take in both an offset and regSource?

查看:323
本文介绍了为什么lw指令的第二个参数同时接受offset和regSource?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So the lw instruction is in the following format: lw RegDest, Offset(RegSource). Why does the second argument take in both an offset and register source? Why not only one (i.e. only register source)?

推荐答案

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

Because what else are you going to do with the rest of the 32-bit instruction word? (Assuming you're the CPU architect designing the MIPS instruction set).

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

It lets LUI + LW load from any arbitrary 32-bit address in 2 instructions, instead of 3. And for loop unrolling or struct pointer->member access, avoiding ADDIU instructions for pointer math. i.e. spending that amount of coding space on LW/SW allows MIPS programs to be more efficient. Sometimes you only need 0($reg), but other times it would be a waste of instructions to compute the final address in a register.

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

Leaving out the 16-bit immediate displacement can't make the instruction shorter. MIPS is a RISC with fixed-length instruction words. (It could be R-type instead of I-type, but you'd still have unused bits in that format. Classic MIPS had lots of unused coding space, and spending coding space on LW/SW, LB/LBU/SB, and so on, is worth it.)

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

MIPS doesn't have a lot of different opcodes (especially classic MIPS without any FPU instructions, and without 64-bit instructions). It uses a lot of the instruction coding space to support an immediate form for most instructions, with a large immediate. (Unlike ARM32 for example which uses 4 bits in each instruction for predicated execution, and more bits for "flexible" source operand (optional rotate or shift by a constant or another register, or an immediate constant). But ARM immediates are encoded as 8 bits with a rotation, allowing lots of useful bit patterns that are common in real life.)

MIPS仅具有一种寻址模式,并且imm16(reg)可以保存大量的addiu指令,而不仅仅是(reg).

MIPS only has one addressing mode, and imm16(reg) can save a significant number of addiu instructions vs. just (reg).

例如,考虑一个C函数,该函数加载或存储到静态(或全局)变量中.像

For example, consider a C function that loads or stores to a static (or global) variable. Like

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位地址的一半).

The compiler-generated (or hand-written) asm needs to load and store from seed, so you need it in a register. But it's a 32-bit constant that doesn't fit in a single instruction. In hand-written asm you'd probably use a pseudo-instruction like la $t0, rng.seed, which will assemble to lui $t0, hi(rng.seed) / ori $t0, $t0, lo(rng.seed). (hi and lo get half of the 32-bit address).

但是您可以做得更好:

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

即将地址的低16位用作装入指令中的16位位移.实际上这就是

i.e. use the low 16 bits of the address as the 16-bit displacement in the load instruction. This is in fact what 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

从寄存器中立即移出还有很多其他用途.例如:

There are lots of other uses for small immediate displacements from a register. For example:

  • 如果编译器溢出任何内容,则访问堆栈上的本地变量
  • struct字段
  • 展开循环中的数组访问. (MIPS具有32个整数寄存器,并且几乎是为通过软件管道展开循环而设计的.)
  • 小的编译时常量数组索引.
  • accessing locals on the stack if the compiler spills anything
  • struct fields
  • Array access in an unrolled loop. (MIPS has 32 integer registers, and is pretty much designed for software-pipelining to unroll loops).
  • small compile-time constant array indices.

正如我所说,使用指令字的那些额外的16位,您可以做的很多事情都非常适合MIPS.您可以保留少于16位的位移,但是MIPS不是PowerPC(那里有很多操作码).

As I said, there isn't much else you could do with those extra 16 bits of the instruction word that would be a good fit for MIPS. You could leave fewer than 16 bits for the displacement, but MIPS isn't PowerPC (where there are lots and lots of opcodes).

这篇关于为什么lw指令的第二个参数同时接受offset和regSource?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆