仕様書を読みながら、RISC-VのZc拡張について勉強する。
Zc拡張は、コードサイズの削減を主目的とした一連の拡張群であり、組み込み用途や省メモリ環境において特に有用である。
Zc拡張とは
Zc拡張は、既存のC(Compressed)拡張のサブセットや、16ビット命令のみで構成される新規拡張をまとめたものである。Zc拡張群には以下のサブセットが含まれる:
- Zca: 浮動小数点ロード/ストアを除くC拡張の命令群
- Zcf: 圧縮単精度浮動小数点ロード/ストア(RV32のみ)
- Zcd: 圧縮倍精度浮動小数点ロード/ストア
- Zcb: コードサイズ削減に特化した簡易命令群
- Zcmp: PUSH/POPやダブルムーブなど、組み込み向けの複雑な命令群
- Zcmt: テーブルジャンプ命令など、組み込み向けの複雑な命令群
これらの拡張は、16ビット命令の活用により、命令メモリの消費を抑えつつ、必要な機能を柔軟に追加できる点が特徴である。
各サブセットの詳細
Zca
Zcaは、C拡張から浮動小数点ロード/ストア命令(c.flw, c.fsw, c.fld, c.fsdなど)を除いた命令群である。整数演算や分岐、ロード/ストアなど、基本的な圧縮命令が含まれる。
Zcf(RV32のみ)
Zcfは、圧縮単精度浮動小数点ロード/ストア命令(c.flw, c.flwsp, c.fsw, c.fswsp)を提供する。RV32専用であり、ZcaおよびF拡張に依存する。
Zcd
Zcdは、圧縮倍精度浮動小数点ロード/ストア命令(c.fld, c.fldsp, c.fsd, c.fsdsp)を提供する。ZcaおよびD拡張に依存する。
Zcb
Zcbは、コードサイズ削減に寄与する簡易命令(c.lbu, c.lh, c.lhu, c.sb, c.sh, c.zext.b, c.sext.b, c.zext.h, c.sext.h, c.zext.w, c.mul, c.notなど)を追加する。 多くの命令は16ビット版として実装され、既存の32ビット命令と同等の機能を持つ。ZcbはZcaに依存する。
Zcmp
Zcmpは、組み込み用途向けに設計された複雑な圧縮命令群であり、特にPUSH/POP命令(cm.push, cm.pop, cm.popret, cm.popretz)が特徴的である。これらの命令は、関数のプロローグやエピローグで頻繁に行われるレジスタの保存・復元処理を、1命令でまとめて実現できる。
従来のRISC-Vでは、複数のレジスタをスタックに保存・復元する際、個別にsw/lw命令を並べ、spの加減算も都度記述する必要があった。ZcmpのPUSH/POP命令を使うことで、これら一連の処理を1命令で記述でき、コードサイズを大幅に削減できる。
例えば、GCCの-msave-restoreオプションを使った場合、プロローグ/エピローグは14バイト程度に短縮されるが、PUSH/POPRET命令を使うとさらに4バイトまで圧縮できる。分岐命令やミリコード呼び出しも不要となり、性能面でも有利となる。
PUSH/POP命令の使い方と展開例
- cm.push {ra, s0-s2}, -64
- 展開例:
sw s2, -4(sp)
sw s1, -8(sp)
sw s0, -12(sp)
sw ra, -16(sp)
addi sp, sp, -64
- cm.pop {ra, s0-s3}, 48
- 展開例:
lw s3, 44(sp)
lw s2, 40(sp)
lw s1, 36(sp)
lw s0, 32(sp)
lw ra, 28(sp)
addi sp, sp, 48
- cm.popretz {ra, s0-s11}, 96
- 展開例:
li a0, 0
lw ra, 92(sp)
lw s0, 88(sp)
...(省略)
lw s11, 44(sp)
addi sp, sp, 96
ret
命令の特徴と注意点
- PUSH/POP命令は、レジスタリストとスタックフレームサイズを指定するだけで、複数レジスタの保存・復元とsp調整を自動で行う。
- {ra, s0-s10}というリストはサポートされず、s11も含める必要がある。
- 命令の実行中に例外や割り込みが発生した場合、シーケンス全体が再実行される設計となっている。
- 非idempotentメモリ領域へのアクセスには注意が必要である。
このように、ZcmpのPUSH/POP命令は、組み込み用途や省メモリ環境での関数呼び出しコストを劇的に削減する強力な機能である。
Zcmt
Zcmtは、テーブルジャンプ命令(cm.jt, cm.jalt)やjvt CSR(ジャンプベクタテーブル制御レジスタ)を追加する。 こちらもc.fsdsp命令のエンコーディングを再利用しており、Zcdとは排他利用となる。ZcmtはZcaおよびZicsrに依存する。
Zce拡張との関係
Zce拡張は、マイクロコントローラ向けに設計された拡張であり、Zc拡張群を包括的に含む。RV32ではF拡張の有無により含まれるサブセットが変化し、RV64ではZcfは含まれない。
- RV32IMC → RV32IM_Zce
- RV32IMCF → RV32IMF_Zce
MISA.Cビットの意味
MISA.Cビットは、ZcaやZcf、Zcdの選択状況に応じて設定される。C拡張を有効にすると、Zcaは常に含まれ、FやDの有無によりZcfやZcdが追加される。