您是否有任何简单的方法可以将 MIPS 中的寄存器中的值作为绝对值?
5 回答
这是一个无分支的变体:
# input and output in $t0
sra $t1,$t0,31
xor $t0,$t0,$t1
sub $t0,$t0,$t1
这是如何运作的?
首先,$t1
用 的符号位填充$t0
。因此如果$t0
为正$t1
将设置为 0,如果$t0
为负$t1
将设置为 0xFFFFFFFF。
接下来,如果为 0xFFFFFFFF,则 的每一位都$t0
被反转$t1
,如果为 0,则保持不变$t1
。恰好反转一个数字的所有位与将其设置为相同(-number)-1
(在二进制补码中)。
最后,从中间结果中减去 0xFFFFFFFF(等于 -1)或 0。
因此,如果$t0
最初是负数,您将得到:
$t0 = ($t0 ^ 0xFFFFFFFF) - 0xFFFFFFFF
== (-$t0 - 1) - -1
== (-$t0 - 1) + 1
== -$t0
。
如果它最初是积极的,你会得到:
$t0 = ($t0 ^ 0) - 0
== $t0
。
这是一个非常简单的方法。
#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
最简单的方法。有一个伪指令可以做到这一点:
abs $t1, $t1
将获取寄存器 $t1 中值的绝对值并将其放入 $t1
这是它的尺寸优化版本。由于分支预测问题,它比 sra/xor/subu 答案慢,但它的指令更小:
bgtz $t0, label
label:
subu $t0, $zero, $t0
这是因为 MIPS 延迟槽起作用的:如果$t0
为正,则subu
取反指令$t0
执行两次。您可能需要.set noreorder
在您的汇编程序中启用。
最简单的方法就是对值进行一些二进制数学运算。
http://en.wikipedia.org/wiki/Signed_number_representations描述了各种系统如何存储它们的负数。我相信 MIPS 使用二进制补码方案来存储带符号的数字。这使得它比位标志更难,可以通过将数字与 0b01111111 进行与运算来关闭它,但它仍然是可行的。