今回から再びRISC-Vの実機(K210)を使って、浮動小数点命令を動かしていきたいと思います。今回は第44回でやったサイクル数の計測を浮動小数点の割り算命令に適用。流石に割り算命令には時間かかっているっしょ、みたいなところを眺めてみたいです。でもま、たまたまK210の実装で、この命令列ならこの程度くらいな数字かと。
※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら
特にスーパースカラー化されていない組み込み用途のRISC機であれば、整数型の命令は、1命令1サイクルというのが「相場」です。実際32bit RISC-V機であるGigaDevice GD32VF103でも、64bit RISC-V機である Kendryte K210でも そのようです。
しかし、浮動小数点演算となるとそうも言ってられません。浮動小数点演算では、仮数部を計算した後でないと指数部の値を最終決定できなかったりする(また仮数部の丸めは指数部に関係)ので、必然的に手間がかかります。しかし、ボロリンと腹の中を見せるのは避けたいので、浮動小数点の手間のかかる演算パスはパイプライン化してスループット的には早くするもんです。結果、命令シーケンスによってレジスタの依存関係などが変化するので見かけのサイクル数が変動したりすることはよくあります(多分。)
K210搭載のRISC-Vコアの実装がどうなっているのか良くわからないですが、そういうことはあるつもりで行きたいと思います。K210の場合、RV64I命令セットに加えて単精度、倍精度の浮動小数点命令もサポートする結構ゴージャスなRISC-Vではあるものの、売りの計算能力はAIアクセラレータ側にあり、RISC-Vにはそれほど大きな期待がかかっていない雰囲気もあります。「それなり」かね。
実験に使用したコード
例によってビルド環境は Windows10 上の VSCode + PlatformIO です。ターゲットボードは、Maix Bit with mic、プラットフォームはお手軽 Arduinoプラットフォーム選択です。
単精度浮動小数点割り算を行い、ついでにサイクル数を測る実験コードが以下に。
TestFloat 型は、以前も使った、浮動小数点型と符号無整数型の共用体です。浮動小数点数を書き込んで整数として読み出し、浮動小数点データのビット表現などを確かめるのに便利なので使っているだけです。
とくにビルドオプションなどは操作していないので、インライン・アセンブラへの引数は整数レジスタ経由で与えています。
今回のターゲットは中ほどにある fdiv.s 一命令です。第2オペランドのレジスタの中の数を第3オペランドのレジスタの数で割って、商を第1オペランドのレジスタに格納するものです。割り算は加減乗除の計算の中で一番「メンドイ」ので、一番時間がかかることが多いと予想されます。これの実行サイクル数を押さえておけば、加減算や乗算はきっとこれより速いだろ~と期待(多分。)
実験結果
実験結果を以下に示します。
2を3で割ったら、0.666667とちゃんと割り算しているようです。単精度の浮動小数点なのでOKですな、多分。
その下に結果のビットパターンもあります。MSBの符号ビットは0、つまり+。その後の指数部8ビットは2進で01111110と読めるので、126ですか。指数部は127下駄をはいている筈なので、2のマイナス1乗、つまり0より小さい数であることが分かります。仮数部は先頭に暗黙の1があるので、0.5よりは大きいと判明。後のビットを加えていけばきっと0.666…となるのでしょうが、ここまで暗算して力尽きました(もうろくして頭のネジも緩んでる?)
実行サイクル数はというと7と表示されています。rdcycle命令自体の1サイクルも載っているので、fdiv自体は6サイクルですかね。ちゃんと割り算用のハードウエアを搭載している数字ですな(当然か。)多分こういう単純なシーケンスではなく他の命令を挟んだりすると多少変わるかもしれません。知らんけど。
一応、「面倒そうな」fdivのサイクル数計測が出来た雰囲気があるので、今度は前回、前々回のテーマだった丸めと例外も観察しておきますかね。ううむ、浮動小数点メンドイな。。。