RISC-V gcc assembly 比較(2)

2019/05/08

RISC-V用のgccでコードを生成して比較する

ソースコード

重力多体問題の加速度を計算する少し複雑なコード。 OSなしで直接実行するため、libm等を使うのは面倒な気がする。 平方根命令(fsqrt.s)を出力するために、インラインで命令を書き込んでおく。 なお、RV32Fには逆数平方根命令はない。

コンパイル方法

ABIを指定して浮動小数点レジスタを値渡しに使うようにする。 ABIを"ilp32f"としない場合、関数の引数や返り値には整数レジスタ(a0 - a7)を使うため、 無駄なfmv.x.w/fmv.w.x命令が生成される。

~/x-tools/riscv32-unknown-elf/bin/riscv32-unknown-elf-gcc -march=rv32imf -mabi=ilp32f -S sum.c -o sum.s

実行した場合のサイクル数比較

最適化オプションを変えてコード生成した上で、シミュレータで実行にかかったサイクル数を計測した。 生成された命令数もカウントした。生成された命令数には別途リンクするstartup用のコード(8命令)を含む。

nが小さいと内側のループがアンローリングされてコードが変化するため、 n = 15でコード生成し実行した場合のサイクル数とCPIの近似値は以下のようになった。

opt 命令数 サイクル数 ループあたり CPI
-O0 792 40668 180.7 1.6
-O3 348 12307 54.4 2.2

最適化オプションなし/"-O0"の場合

配列アクセスはその都度アドレスをロードしている。 32ビットのアドレス即値をロードするには2命令かかるので効率が悪い。 再内側ループ(49 - 151行)は114命令(関数sqrtf呼び出し含めて)。

“-O3"の場合

最初に配列のアドレスを一斉にロード。 ループ内のコードはかなりシンプルになり、再内側ループ(47 - 76行)は25命令。