Do you have any simple ways to make a value in a register in MIPS as an absolute value?
5 Answers
Here's a branch-less variant:
# input and output in $t0
sra $t1,$t0,31
xor $t0,$t0,$t1
sub $t0,$t0,$t1
How does this work?
First, $t1
is filled with the sign-bit of $t0
. So if $t0
is positive $t1
will be set to 0, and if $t0
is negative $t1
will be set to 0xFFFFFFFF.
Next, each bit of $t0
is inverted if $t1
is 0xFFFFFFFF, or left unchanged if $t1
is 0. It just so happens that inverting all bits of a number is the same as setting it to (-number)-1
(in two's complement).
Finally, either 0xFFFFFFFF (which equals -1) or 0 is subtracted from the intermediate result.
So if $t0
originally was negative you'll get:
$t0 = ($t0 ^ 0xFFFFFFFF) - 0xFFFFFFFF
== (-$t0 - 1) - -1
== (-$t0 - 1) + 1
== -$t0
.
And if it originally was positive you'll get:
$t0 = ($t0 ^ 0) - 0
== $t0
.

- 57,169
- 9
- 80
- 125
-
6Warning: This method is covered by U.S. patent #6073150. Probably invalid as hell, though, since it's been known longer than 1997. – Myria Aug 08 '15 at 00:47
-
1@Myria: Compilers such as GCC have been using this for years on various ISAs. e.g. GCC4.4 for x86-64: https://godbolt.org/z/Mv843o. (Also shows 64-bit MIPS GCC5.4 using conditional move, `movn`, to select between `x` and `-x` like clang does for x86.) – Peter Cordes Oct 26 '20 at 00:44
Here is a pretty simple way to do it.
#assume you want the absolute value of r1
ori $2, $zero, $1 #copy r1 into r2
slt $3, $1, $zero #is value < 0 ?
beq $3, $zero, foobar #if r1 is positive, skip next inst
sub $2, $zero, $1 #r2 = 0 - r1
foobar:
#r2 now contains the absolute value of r1

- 7,377
- 4
- 32
- 34
-
Note that this is for a MIPS *without* branch-delay slots, like MARS / SPIM simulate by default. Otherwise you'd want to rearrange the `move` (`ori`) into the branch-delay slot. – Peter Cordes Oct 26 '20 at 00:47
Simplest way of all. There is a pseudo instruction that does this:
abs $t1, $t1
will take the absolute value of the value in register $t1 and place it in $t1

- 92,235
- 44
- 185
- 247

- 101
- 1
- 2
-
3This pseudo-instruction is the `sra/xor/sub` sequence shown in another answer. – Myria Aug 08 '15 at 00:52
Here's a size-optimized version of it. It's slower than the sra/xor/subu answer, due to branch prediction issues, but it's one instruction smaller:
bgtz $t0, label
label:
subu $t0, $zero, $t0
This works because of the MIPS delay slot: if $t0
is positive, the subu
instruction to negate $t0
executes twice. You may need to enable .set noreorder
in your assembler.

- 3,372
- 1
- 24
- 42
The easiest way would just to do a bit of binary math on the values.
http://en.wikipedia.org/wiki/Signed_number_representations describes how various systems store their negative numbers. I believe MIPS uses a two's complement scheme to store signed numbers. This makes it a bit harder than a bit flag, which could just be turned off by ANDing the number with 0b01111111, but it is still doable.

- 38,869
- 30
- 127
- 202