I'm struggling to grasp how to manipulate/compare data stored in registers (words/half-words/intermediate values) in MIPS. Does it matter if they each represent a different number of bytes? For example, is it valid to load an immediate value such as 5 via li, then load a word such as 5, and finally compare them using bne?
CodePudding user response:
Does it matter if they each represent a different number of bytes?
Short answer: No, it doesn't matter, as 5 is 5.
Longer answer: MIPS registers are all 32 bits wide, and, in a sense, there's no way to manipulate less than 32 bits at a time — except for the byte and half word load/store instructions.
For example, if your data is in memory and 8 bits wide (e.g. characters or bytes), and is a signed(unsigned) data type, then you can use lb
(lbu
) to load it into a 32 bit register while also sign(zero) extending the 8 bit value to 32 bits. Numerically, sign(zero) extension keeps the value the same, so you can now work with the 32 bit value in the register.
(Of course, you have to know in advance if the 8 bit data is numeric and should be sign vs. zero extended. We know this in high level languages by a logical variable's declared (and permanent) data type, but in assembly, we're working with physical storage that doesn't necessarily have a permanent data type.)
If your data is not 8 or 16 bits wide (or 32), you can either work with individual bytes, or load more from memory than you're interested in and clear or sign extend bits that are irrelevant to you.
CodePudding user response:
You know how C implicitly promotes every narrow integer type to int
when used with operators like
? That language design matches architectures like MIPS which don't natively have 8 or 16-bit integer operations, only int
/ unsigned int
sized. (Or wider if you do use multiple instructions to do extended-precision math).
MIPS instructions always sign-extend their immediate to 32-bit. (Or zero-extend for bitwise boolean instructions.)
Some operations can be used without caring about the high bits, if you only care about the low bits for a later sb
, but MIPS comparisons like slt
or beq
always looks at all the bits. Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?
In C, assigning the result to a narrow integer truncates the result again, so that's like doing an sb
or sh
. (Actually in C it defines it as modulo-reducing the value to fit in the type's value-range, but for unsigned or 2's complement signed integers that can be implemented as just truncation of the bit-pattern.)
See also Erik's answer for more asm details of using lb
vs. lbu
to do the sign- or zero- extending loads to 32-bit.
It's not a coincidence that MIPS's standard calling convention requires narrow function args and return values like char foo(short x)
to be correctly sign-extended to full register width. For more about that, see the MIPS comparison footnote on this x86-64 question about how that ISA handles narrow data: MOVZX missing 32 bit register to 64 bit register