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
場合はの各ビットが反転され、が0の$t1
場合は変更されません。数値のすべてのビットを反転することは、 (2の補数で)に$t1
設定することと同じです。
最後に、0xFFFFFFFF(-1に等しい)または0のいずれかが中間結果から減算されます。(-number)-1
したがって、元々負であった場合は、次のようになり$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の回答よりも低速ですが、1命令小さくなります。
bgtz $t0, label
label:
subu $t0, $zero, $t0
これは、MIPS遅延スロットのために機能します。$t0
が正の場合、subu
否定する命令$t0
は2回実行されます。.set noreorder
アセンブラで有効にする必要がある場合があります。
最も簡単な方法は、値に対して少しバイナリ計算を行うことです。
http://en.wikipedia.org/wiki/Signed_number_representationsは、さまざまなシステムが負の数を格納する方法について説明しています。MIPSは、符号付き数値を格納するために2の補数スキームを使用していると思います。これにより、ビットフラグよりも少し難しくなります。ビットフラグは、数値を0b01111111とAND演算することでオフにできますが、それでも実行可能です。