RISC-VのB拡張とB拡張対応gccのビルド方法

gcc12から、RISC-VのB拡張命令を使ったコンパイルが可能になりました。 B拡張には、ビット演算を取り扱う命令が含まれています。 したがって、B拡張に対応したCPUでは、gcc12でコンパイルすることによりプログラムが高速化することが期待できます。

RISC-VのB拡張は、複数の拡張(Zba, Zbb, Zbc, Zbs, Zbp, Zbm, Zbf, Zbe, Zbr, Zbt)に分かれています。 このうち、Zba, Zbb, Zbc, Zbs拡張のみがRISC-Vの公式に批准(Ratified)されており、残りの拡張はまだ仕様策定中です。 gcc12で対応しているのは、この批准されているZba, Zbb, Zbc, Zbs拡張のみです*1

以下の図は、RISC-VのB拡張に含まれる命令が、どのZb*拡張に含まれているかを示したものです。 例えば、sh1add命令はZba拡張に含まれており、andn命令はZbb拡張とZbp拡張に含まれています。 pack命令とその亜種は複数の拡張に含まれています。 矢印の先にある命令(zext.hrev8orc.bunzip8unzip16)は、それぞれ矢印の元にある命令(pack[w]grevigorciunshflishfli)の特殊パターンであり、その命令ビットパターンは将来Zbp拡張を批准したときに問題とならないよう、互換性があるように定義されています。 zext.w命令はpack命令の特別なパターンとして定義される予定でしたが、批准されている拡張に含まれるadd.uw命令の特別なパターンの動作としても定義できるため、現在はそのように定義されているようです。

図1: RISC-VのB拡張

さて、B拡張に対応したgcc12をビルドする方法を以下に説明します。

まず、riscv-gnu-toolchainリポジトリをクローンします。 ここで、--recursiveオプション付きでクローンすると以下の手順で失敗する*2ので気を付けてください。 riscv-gnu-toolchainリポジトリはsubmoduleをいくつか持っていますが、これらはビルド時に自動で取得されるため、--recursiveは不要です。 クローン後、gcc-12ブランチに移動します。 これは、現在のデフォルトブランチではgcc11がビルドされるためです。

git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain/
git checkout gcc-12

./configureコマンドを実行することで、ビルド方法の設定を行います。

--prefixには、出来上がったgcc等をインストールする場所を指定します。

もし、RV64GB対応のgcc12を作りたい場合、--with-archオプションや--with-abiオプションは何も指定する必要がありません。 RV32GB対応のgcc12を作りたい場合、--with-arch=rv32g_zba_zbb_zbc_zbs --with-abi=ilp32を指定してください。

./configure --prefix ~/riscv64gb_gcc121
make linux -j$(nproc)
./configure --prefix ~/riscv32gb_gcc121 --with-arch=rv32g_zba_zbb_zbc_zbs --with-abi=ilp32
make newlib -j$(nproc)

あとは待てば、自動的にできあがったgccがインストールされます。

コンパイル時に-march=rv64g_zba_zbb_zbc_zbsなどとオプションをつけることで、B拡張が使われたバイナリが生成されます。

*1:clang12は、まだ批准されていないZbt拡張に含まれる命令も使うようです。

*2:asコマンドのビルドに失敗し、結果としてgcc等が使えない状態で終了します。