My teacher just went over the topic but I'm still left questioning why exactly offset is used. Is it to categorize values with the help of a sort of prefix? If you could explain in an easy way of why offset is used in these instructions I'd be grateful.
CodePudding user response:
The offset is used in several different scenarios. Here are some examples:
Many algorithms naturally involve expressions like
A[i 1]
. The compiler will computeA i
, and use an offset of 4 to get the 1 (assumingA
is an array of 4 byte elements).After unrolling loops even involving only
A[i]
, the unrolled parts introduce usages ofA[i 1]
,A[i 2]
, etc.. for which the offset is useful.When we access stack-based memory, the base register is going to be the stack pointer, register
$sp
. Here the offset says which stack slot to access, so very handy for accessing local stack-based variables.There are hidden usages of the stack (hidden from the C programmer), which involve preserving
$s
register values, the return address register value$ra
, and potentially also parameters that were passed in registers. These are accessed also using$sp
as base register and an appropriate offset to get to the right slot.Parameters that don't fit into the registers are passed on the stack and accessed using
$sp
as base and an appropriate offset, by both caller (setting the parameters) and callee (accessing them).Global variables can be accessed using a two instruction sequence, using
lui
followed bylw
orsw
with an appropriate offset. Thelui
instruction forms an upper 16 bits and thelw
orsw
instruction provides a lower 16 bits. Thus, a 32-bit address can be formed, to access a global variable anywhere in the address space.Objects have fields, and accessing the fields is done using a pointer to the object and the offset of the field within the object. So, in C,
p->f1
, wheref1
has an offset of 8, would use a load or store withp
as base register and 8 as offset.p->f2
would use the samep
but different offset.
In summary, there are quite a few scenarios where base non-zero constant is useful. The zero constant is also very useful, as you already know for *p
(simple dereference) and A[i]
(array indexing), and as such MIPS chooses to provide only one form of addressing mode.
Other architectures provide several addressing modes, e.g. dereference with offset and without offset (among others), so for them you choose without offset rather than providing an offset that is zero. Then you can use a shorter instruction since there is no offset encoded (and short instructions are good for code density, which is good for instruction cache performance). However, to take advantage of this, you would need a variable length instruction set, and more encodings, both of which MIPS chose against, in keeping with its RISC philosophy.