絶対値命令の説明で、私はオペランドの値が固定小数点数の-1 (0x8000)のとき、ABS命令の実行結果がやはり-1(0x8000)になることに関して「妥当だ」と書きました。ここでそう思う理由を説明しておきましょう。
まず、2の補数表現の数の符号を反転する操作が「全ビット反転後、1LSBを足す」であることを思い出しましょう。例えば、固定小数点数の0.5に対して-0.5の表現を考えてみると、
です。この二つの数の16進表現を見ると、互いに「ビット反転+1LSB」の関係であることがわかります。
この知識を前提に改めて0x8000の反数を考えて見ましょう。この値をビット反転して1LSBを足すと、
となりますから、やはり-1 (0x8000)の反数が-1 (0x8000)であるというのは理にかなっています。であれば、この違和感は何なのでしょう。コンピューターの外側では-1の反数は1です!
この問題の正体はあふれです。もともとMSBは符号ビットです。上の操作の2番目で1LSBを足したとき、数値ビットから符号ビットにキャリーがおきたため、あふれが生じてしまっているのです。であれば、この操作は飽和を起こして結果が0x7FFF(あふれを起こさない正の最大値)にすべきだという意見もあるかもしれません。それは、一面では正しいといえますが、別の面もみたほうがいいでしょう。
指数部抽出命令はあふれを起こした結果を補正して正しい指数部を抽出した上で正規化を行う(HIX)オプションを持っています。先の状況であふれがおきたときに飽和させると、せっかくの指数部抽出命令のあふれ対応機能が無駄になってしまいます。
結局、どこで妥協するかという話になります。ABS(-1)の計算を行うときに飽和処理も行えば、単精度整数・固定小数点数演算は高速にできるかもしれませんが、浮動小数点数のエミュレーションは遅くなります。また、想定していなかった処理で、生の演算結果が欲しい場合も困るでしょう。ABS命令に飽和オプションがあれば文句なしですが、命令のビットフィールドに余裕があるかとか、そこまでしなければいけない問題かという疑問もあります。
結局219xコアのアーキテクトは飽和/ラップアラウンドの選択をモード変更で行うよう設計しました。飽和処理を行いたい場合は次のような命令列を使うと解決できます。
// モードそのものを切り替える方法 ena ar_sat; ax0 = 0x8000; ar = abs ax0; // 結果は0x7FFFになる。 // コードの一部だけで補正する方法 ax0 = 0x8000; ar = abs ax0; // 結果は0x8000になる。 if av ar = ar -1; // あふれがおきたときに限り結果を0x7FFFに補正する
⇒次はパイプラインの国のアリス