If you need to multiply two arbitrary signed numbers in MIPS, is there a reason to prefer:
mul $t0 $s0 $s1
Or this:
mult $s0 $s1
mflo $t0
?
I'm finding inconsistent answers online with regard to what each one means. At first glance I would expect the former to be a pseudo-instruction for the latter. (And there's even a web page that claims that.) But looking at the machine code it appears that mult
is a valid R-type instruction (opcode 0) whereas mul
has a nonzero opcode (0x1c) and so shouldn't be an R-type, even though it contains 3 registers?!
RISC philosophy says to use pseudo-instructions frequently since we only have limited real instructions. But I'm just not thinking of why you'd need two different ways to multiply. Both affect lo
and hi
(using MARS), so you can check for overflow with either. So why the redundancy? Why not just tell everyone to use mul
all the time?
mul
is not a pseudo instruction. It does not modify either the hi
or lo
registers that mult
does. They are different real instructions in the instruction set.
In general, we have a = b * c
Since multiplying two 32 bit numbers together produces a 64 bit result, in the general case we use mult
and then get the lower 32 bits of the result with mflo
and the upper 32 bits with mfhi
. This allows greater accuracy at the expense of needing an extra instruction [or two] to get the result.
If we only care about the lower 32 bits of the result of the multiply (e.g. array index calculations), we can use mul
which allows the result to be in a different register from the arguments (in a single instruction)
Consider a simple program:
.text
.globl main
main:
mul $v0,$a0,$a1
mult $v1,$a2
mflo $v0
Now, if we assemble it using mars
, we get:
00400000: 70851002 mul $v0,$a0,$a1
00400004: 00660018 mult $v1,$a2
00400008: 00001012 mflo $v0
Notice that we have a real mflo
instruction on line 3. If mul
were a pseudo-op, mars
would [have to] inject an mflo $v0
between the mul
and mult
lines
UPDATE:
That's interesting. And you're right about it not being a pseudo-instruction. (You'd see that when it was assembled, if it were.) But when I use MARS, both mul and mult modify hi and lo. Maybe this is a MARS bug?
Possibly. spim
also modifies hi and lo.
Upon further reflection, this seems logical given the era of the original mips CPU cores (circa 1985) and the [extremely] limited number of gates they had.
But, real mips cores are still alive today. The company is "MIPS Technologies, Inc" and it still existed as of 2017.
The ISA reference manual from the company [AFAICT] has a copy here: https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00086-2B-MIPS32BIS-AFP-6.06.pdf
In that document, the mul
instruction does not list changing hi or lo as a side effect.
In some document I've seen [I can't recall which], it states [for old/real hardware] that you have to have an intervening instruction between the mult
and an mflo
(e.g. a nop
). The simulators don't require this.
As good practice, I probably wouldn't rely on lo/hi being valid for too long after mult
and not rely on them at all for mul
, so, for class work, it's a bit of a moot point.
It would be interesting to see what qemu
does. It's harder to use than spim
or mars
[which I prefer] but may be closer to what actual hardware does.