mcommit's message

ソフトウェア開発の仕事をしているsimotinといいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

RV32C ~圧縮命令ってなんだ?~

モナリザ本の第7章を読んでみました。

RISC-V原典  オープンアーキテクチャのススメ

RISC-V原典 オープンアーキテクチャのススメ

前回の記事で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-littleriscv

Disassembly of section .text:

0000000000000000 <.text>:
0: 00000513 li a0,0

00000513という32bitエンコードされています。

では、C言語で同様のアセンブリを期待したコードを書いて試してみます。


$ cat tmp.c
int return_zero(void)
{
return 0;
}

$ riscv64-unknown-elf-gcc tmp.c -c -O1
$ riscv64-unknown-elf-objdump.exe -S tmp.o

tmp.o: file format elf64-littleriscv


Disassembly of section .text:

0000000000000000 :
0: 4501 li a0,0
2: 8082 ret

C言語コンパイラを通すとなんと16bitエンコードされています。
*2

コンパイラ開発者・アセンブリプログラマは圧縮命令を意識しなくてよい

というのはつまりこういうことなんだと思います。
ここでは同じ li a0, 0という命令が16bitにも32bitにもエンコードされました。

これはありがたい反面、コンパイラ(アセンブラ)の実装によっては思わぬトラブルを生み出しそうな気もします。
組込ソフト開発の場合、書いたコードがどういったバイナリになっているかをシビアに意識しないといけないケースもありますので出来れば明示的にコントロールしたいところです。

一般的にはこういった場合コンパイラに対するオプションとかで指定できたりすると思うのですが、gccの場合どう対応しているのでしょうか。まだそのあたりは調べれていませんが気になります。

*1:あと速度最適化の選択肢が少なくなると思います

*2:コンパイル時に-O1をつけましたがこれは最適化を付けないと冗長なアセンブラが吐かれるためです。-O1なしでも16bitでエンコードされます