はじめに
mruby/cは少々効率を犠牲にしても省メモリに振ったユニークな処理系だと思いました。そんな処理系の命令セットがmrubyと同じなんて一貫性が無いので省メモリに振った命令セットを考えました。方針は以下の通りである。
mrubyのバイトコード列の意味を変えない
メソッドはあまり複雑なものはない。つまり、ローカル変数なんかは少ないプログラムを想定する
よく使う命令の組み合わせで命令融合させる。この際、32bitにはこだわらない
16bitの命令を用意して出来る限りそれを使うことでプログラムを小さくする。使える16bit命令が無い場合は32bit命令を使うわけだが、この場合はnop命令などを使って32bitにアライメントを合わせる。
ジャンプ命令は32bit命令列を前提にしているのでジャンプの飛び先は32bitにアライメントする
命令融合
OP_MOVE2
OP_MOVE Rn, Ra
OP_MOVE Rn+1, Rb
を1命令にする。ただし、n >= a, b。a,bの部分に0を入れることで、LOADSELFも融合できる。
ビットパターン
Rb Ra n オペコード(0x50)
オフセット FEDCBA98 76543210 FEDCBA987 6543210
内容 bbbbbbbb aaaaaaaa nnnnnnnnn 1010000
16bit命令
16bit命令にはすべて最後に16が付く
OP_NOP16
ビットパターン
常に0 オペコード(0x0)
オフセット FEDCBA987 6543210
内容 000000000 0000000
OP_NOPは32bitでall 0なのでOP_NOP16が2つ並んでいるものとして解釈できる。従来の命令コードの意味を変えた唯一の例である。
OP_LOADLOCAL16
dst(parameter) src(local) オペコード(0x50)
オフセット FEDC BA987 6543210
内容 0000 00000 1010000
OP_MOV命令と同じ意味だが、local変数領域のレジスタからパラメータ領域のmoveに特化している。
レジスタフィールドを節約するため、local変数領域とパラメータ領域に分ける。local変数領域はR1~R(irep->nlocals - 1)までのローカル変数が割り当てられた領域。パラメータ領域はそのあとのメソッド呼び出しの引数やワーキングで使ういわばスタックとしての領域である。
そして、local変数領域同士、パラメータ領域同士の代入のmove命令は生成されない。そこで、このようなレジスタ指定を行う命令フォーマットは無駄であるため、このように命令を分けた。
また、local変数領域はR1から始まることに注意されたい。R0はselfだが、loadselfという命令があるので、これを割り当てるのは無駄である。
OP_LOADPARM16
dst(local) src(parameter) オペコード(0x5)
オフセット FEDC BA987 6543210
内容 0000 00000 1010001
OP_MOV命令と同じ意味だが、パラメータ変数領域のレジスタからlocal領域のmoveに特化している。