[Linux] 405の浮動小数点

405 コアのパンフレット等を見ると積和演算を 2 clock で行うことができると書いてあったりする。それで、ずーと、405 コアには浮動小数点用のユニット(FPU)があるものだと勘違いしていた。やっとわかったのだが、405 コアにはFPU は搭載されていない。載っているのは整数演算に対する積和演算回路だ。
Virtex-II は 405B3 というコアらしいが、Virtex-4 はPPC405F6らしい。いずれにせよ、FPU はない。
さてそこで 405 コアの Linux 上で fmul, fdiv などの浮動小数点演算を実行するとどうなるか?リビジョンにもよるだろうが、Linux 2.4.22 では浮動小数点演算をエミュレートしてくれない。通常(かどうかは知らないが)、同じ種類のコアならカーネルとしては、エミュレートするのが筋だろう。例えば、私の知っている Unix の OS では、 68030 から 68040 へ移行したとき、幾つか削られた浮動小数点演算に対して、カーネルがそれをリカバーするようなエミュレート機構をつくりこんでいた。そうすることにより、68030 の OS で動いていたアプリケーションは 68040 でもそのまま動作する。
勿論、アプリケーション・プログラマはカーネルの機能に頼らず、ソフト的に実現した浮動小数点演算のライブラリを使うべきだ。それはなぜか?
アプリケーションで fmul や fdiv などを使うと 405 のような浮動小数点演算の無い CPU はイリーガル・インストラクションのエクセプションを起こすだろう。そのままほっておけば(カーネルが何もしなければ)、そのプロセスは死ぬ。(該当するシグナルがあがる。Linux/PPC なら 4 番のシグナル)そこで、ちょっとかしこいカーネルなら例外が起こった場所とインストラクションを解析して FPU の代わりに処理を行う。つまりエミュレーションだ。アプリケーションは死なずに動くが、スピードは早くない。例外をキャッチする分、時間がかかるだろう。
あらかじめアプリケーションを浮動小数点演算のライブラリとリンクしておいたほうが、fmul は使用されずにその代わりに bl __muldf3 などのライブラリを呼ぶだけなので効率的だ。具体的には、コンパイル時に gcc -msoft-float 等とする。
かといって、すべてのコアに対して Linux ががんばってエミュレートするのは大変かもしれない。例えば AltiVec 演算などはどうだろう?これも、OS がエミュレートすべきなのだろうか?
そういう意味では、やはりアプリケーションが意識して CPU にあったライブラリをリンクすべきなのだと思う。さて、Windows ではどうしているのだろう?AMDIntel で違うコードがあるはずだが。

kuro-box

405 Linux では先に書いたとおり、fmul などの命令を含んだオブジェクトを実行させると、イリーガル・インストラクションで落ちてしまうのだが、kuro-box ではどうだろう?これは簡単に実験できる。double の掛け算、足し算を繰り返す単純なプログラムだが、その結果は一目瞭然。

$ time ./double_hard <= -mhard-float でコンパイルした
real 0m19.641s
user 0m19.640s
sys 0m0.010s
$ time ./double_soft <= -msoft-float でコンパイルした
real 4m41.487s
user 4m41.480s
sys 0m0.000s

82XX というモトーロラー系の石だが浮動小数点演算ユニットを持っている。19秒と280秒じゃ勝負にならない。なんの勝負だかは謎だが。

Linux の math emu

とここまで書いて 2.4.22 のソースを見たらちゃんと math-emu というディレクトリがある。.config に CONFIG_MATH_EMULATION=y と書いておけばいいらしい。もしかして今使っているカーネルが単純に CONFIG_MATH_EMULATOIN=n になっているだけだったりして。