モナリザ本の第7章を読んでみました。
- 作者: デイビッド・パターソン,アンドリュー・ウォーターマン,成田光彰
- 出版社/メーカー: 日経BP社
- 発売日: 2018/10/18
- メディア: 単行本
- この商品を含むブログを見る
前回の記事でRISC-Vのアセンブラについて調べていて気になっていた圧縮命令について書かれた章です。章といいつつこの章は実は参考文献のリストなどをあわせても7ページしかありません。
RISCのデメリット
RISC系のCPUは命令セットがシンプルな分アセンブラのコード量が多くなりがちです。シンプルな命令の組み合わせつつ、パイプラインを有効活用する事で命令あたりのクロックサイクルを少なくすることがRISCの戦略ということになりますが、命令を組み合わせる分、使用する命令数(サイズ)はCISC系と比べて多くなります。*1
使用する命令数(サイズ)が多くなるということは、テキストセクションのサイズが大きくなるということで、これは組込ソフトにおいてプログラム使用するROMのサイズが大きくなります。
マイコンの値段は内蔵ROMのサイズで変わってきますので、プログラム領域もデータ領域も(もちろん使用するメモリサイズも)小さいに越したことはありません。
前置きが長くなりましたが、ようするにRISCではプログラムサイズが多くなるというのがデメリットとして存在するわけですが、この問題に対するRISC-Vとしての解答がRV32Cの圧縮命令ということのようです。
圧縮命令の特徴
命令長が短い版の命令セットがあるという点ではARMのThumb命令も同じですのであまり珍しく感じませんでした。
RISC-Vの圧縮命令の特徴は何かあるのでしょうか。
7章を読んでみて分かったのですが、この圧縮命令はアセンブラとリンカだけが意識し、コンパイラ開発者やアセンブリ言語のプログラマは圧縮命令を意識する必要がないそうです。
お前は何を言っているんだ?
という気持ちになったのですが、要するに1つの命令のニーモニックは通常のRV32IでもRV32C(圧縮命令)でも共通になるということです。
気になったので改めて確認してみました。
実験
前回の記事、
mcommit.hatenadiary.com
でも少し触れましたが、同じli(load immediate)命令であってもエンコードのされ方に違いがあります。
asコマンドでアセンブリした場合、
$ cat tmp.s
li a0,0
$ riscv64-unknown-elf-as tmp.s # a.out が生成される
$ riscv64-unknown-elf-objdump.exe -S a.out
a.out: file format elf64-littleriscvDisassembly of section .text:
0000000000000000 <.text>:
0: 00000513 li a0,0
00000513という32bitでエンコードされています。
では、C言語で同様のアセンブリを期待したコードを書いて試してみます。
C言語のコンパイラを通すとなんと16bitでエンコードされています。
$ cat tmp.c
int return_zero(void)
{
return 0;
}$ riscv64-unknown-elf-gcc tmp.c -c -O1
$ riscv64-unknown-elf-objdump.exe -S tmp.otmp.o: file format elf64-littleriscv
Disassembly of section .text:
0000000000000000
:
0: 4501 li a0,0
2: 8082 ret
*2
というのはつまりこういうことなんだと思います。
ここでは同じ li a0, 0という命令が16bitにも32bitにもエンコードされました。
これはありがたい反面、コンパイラ(アセンブラ)の実装によっては思わぬトラブルを生み出しそうな気もします。
組込ソフト開発の場合、書いたコードがどういったバイナリになっているかをシビアに意識しないといけないケースもありますので出来れば明示的にコントロールしたいところです。
一般的にはこういった場合コンパイラに対するオプションとかで指定できたりすると思うのですが、gccの場合どう対応しているのでしょうか。まだそのあたりは調べれていませんが気になります。