自作コンパイラでRISC-Vの四則演算ができるようになったのでまとめてみた。
RISC-Vで乗算命令を使う実績解除。
これが僕より先に僕が書いたコンパイラの実績解除になっていて感動している。
前回の話
Cソース
こんな感じの四則演算ができるようになりました。
int main(void) { putd(5+6*7); return 0; }
AST作るとこまでは問題なし。
RISC-V対応
演算部分
a0に左オペランド、a1に右オペランドが来るようにして、演算結果をa0に入れていいく。
match binop.op with | BinOpKind.Add -> fp.WriteLine " add a0, a0, a1" | BinOpKind.Sub -> fp.WriteLine " sub a0, a0, a1" | BinOpKind.Mult -> fp.WriteLine " mul a0, a0, a1" | BinOpKind.Div -> fp.WriteLine " div a0, a0, a1"
push, pop
5+6x7の部分で、一度5をどこかに保存しないと6*7の演算でa0が書きされてしまう。RISC-Vは死ぬほどレジスタあるので手書きならどうでもなるけど、レジスタの割当はまだまだ先の話なのでスタックを使うようにする。
RISC-Vにはpush、popが無いので命令を組み合わせて作る。 スタックポインタを直接操作するのが20年ぶりくらいなので自信ないけどあってる気がする。
let push (fp : StreamWriter, reg) = stack_count <- stack_count + 1 fp.WriteLine "# push %s{reg}" fp.WriteLine " addi sp, sp, -8" fp.WriteLine $" sd %s{reg}, 0(sp)" let pop(fp : StreamWriter, reg) = stack_count <- stack_count - 1 fp.WriteLine "# pop %s{reg}" fp.WriteLine $" ld %s{reg}, 0(sp)" fp.WriteLine " addi sp, sp, 8"
アセンブラ
出力されるアセンブラ。 絶対いらんやろみたいなpush, popが入っているけどこの辺を削っていくのももっともっと後の話。 まずはいろいろ動くようにしたい。
細かいところで、mainの戻り値を0を返すようにした。 pythonからテストをするときに0以外の値を返すと、外部プロセスの起動に失敗したのか、成功して変な値を返してきたのかわからなくなるため。
.globl main .text main: # Prologue addi sp,sp,-16 sd ra,8(sp) sd s0,0(sp) addi s0,sp,16 li a0, 7 # push a0 addi sp, sp, -8 sd a0, 0(sp) li a0, 6 # pop a1 ld a1, 0(sp) addi sp, sp, 8 mul a0, a0, a1 # push a0 addi sp, sp, -8 sd a0, 0(sp) li a0, 5 # pop a1 ld a1, 0(sp) addi sp, sp, 8 add a0, a0, a1 call putd # Epilogue .L.return.main: li a0, 0 ld ra,8(sp) ld s0,0(sp) addi sp,sp,16 jr ra