【发布时间】:2010-02-22 16:55:51
【问题描述】:
你有什么简单的方法可以在 MIPS 中将寄存器中的值设为绝对值吗?
【问题讨论】:
标签: assembly mips absolute-value
你有什么简单的方法可以在 MIPS 中将寄存器中的值设为绝对值吗?
【问题讨论】:
标签: assembly mips absolute-value
这是一个无分支的变体:
# 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。
接下来,如果 $t1 为 0xFFFFFFFF,则 $t0 的每一位都被反转,如果 $t1 为 0,则保持不变。恰好反转一个数字的所有位与将其设置为 (-number)-1 相同(在二进制补码)。
最后,从中间结果中减去 0xFFFFFFFF(等于 -1)或 0。
所以如果 $t0 最初是负数,你会得到:$t0 = ($t0 ^ 0xFFFFFFFF) - 0xFFFFFFFF == (-$t0 - 1) - -1 == (-$t0 - 1) + 1 == -$t0。
如果它最初是肯定的,你会得到:$t0 = ($t0 ^ 0) - 0 == $t0。
【讨论】:
movn,在 x 和 -x 之间进行选择,就像 clang 对 x86 所做的那样。)
这是一个非常简单的方法。
#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
【讨论】:
move (ori) 重新排列到分支延迟槽中。
最简单的方法。 有一个伪指令可以做到这一点:
abs $t1, $t1
将寄存器$t1中值的绝对值放入$t1中
【讨论】:
sra/xor/sub序列。
这是它的尺寸优化版本。由于分支预测问题,它比 sra/xor/subu 答案慢,但它的指令更小:
bgtz $t0, label
label:
subu $t0, $zero, $t0
这是因为 MIPS 延迟槽而起作用的:如果 $t0 为正数,则用于否定 $t0 的 subu 指令执行两次。您可能需要在您的汇编程序中启用.set noreorder。
【讨论】:
最简单的方法就是对值进行一些二进制数学运算。
http://en.wikipedia.org/wiki/Signed_number_representations 描述了各种系统如何存储它们的负数。我相信 MIPS 使用 二进制补码 方案来存储带符号的数字。这使得它比一个位标志更难,可以通过将数字与 0b01111111 进行与运算来关闭它,但它仍然是可行的。
【讨论】: