min-caml覚え書き
min-camlリポジトリ
macではmin-camlが動かないので、こちらを参考にDockerイメージ my/min-caml を作成しておくこと
RISC-V対応で参考になりそう
覚え書き
$ cd ~/src
$ cd min-caml
ソースの文字コードがEUC-JPなのでUTF-8に変換する
$ nkf -Ew --overwrite nkf --guess **/* | grep EUC | awk 'BEGIN{FS=":"} {print $1}'
x86で動かしてみる
$ docker run -it --rm -v pwd:/root -w /root my/min-caml bash
$ (コンテナの中)
$ ./to_x86
$ make
$ cd min-rt
$ make
$ (コンテナを抜ける)
min-rtのmakeが終わると(レイトレが走るので5分〜10分くらいかかります)min-rtディレクトリにレイトレ結果が出力される。
https://gyazo.com/84a15cee96b9310f058b65641eb7eccf
makeのログはこちら
min-camlディレクトリに実行ファイル「min-caml」が作成されるので、サンプルプログラムを動かしてみる
code:sh
# test/print.ml をコンパイル
$ ./min-caml test/print
free variable print_int assumed as external
iteration 1000
eliminating variable Ti7.13
eliminating variable Ti6.12
eliminating variable Ti4.15
iteration 999
register allocation: may take some time (up to a few minutes, depending on the size of functions)
generating assembly...
# test/print.s が出力されるので、gccでアセンブル
$ gcc -g -O2 -Wall -m32 test/print.s libmincaml.S stub.c -lm -o test/print
# 実行してみる
$ ./test/print
sp = 0xffa9dea0, hp = 0xf7856010 (stderrにスタックポイントなどが表示されるっぽい)
123-456789
code:print.ml
print_int 123;
print_int (-456);
print_int (789+0)
CPUごとのソースの差分
PowerPC vs SPARC
PowerPC vs x86
min-camlが出力したPowerPCコードをながめる
print_int (15 + 16) をコンパイルした結果をアセンブリコードとして出力。
code:sh
$ make min-caml
$ echo "print_int (15 + 16)" > a.ml && ./min-caml -iter=0 a && cat a.s
free variable print_int assumed as external
iteration 0
register allocation: may take some time (up to a few minutes, depending on the size of functions)
generating assembly...
.text
.globl _min_caml_start
.align 2
_min_caml_start: # main entry point
mflr r0
stmw r30, -8(r1)
stw r0, 8(r1)
stwu r1, -96(r1)
# main program starts
li r2, 15
addi r2, r2, 16
mflr r31
stw r31, 4(r3)
addi r3, r3, 8
bl min_caml_print_int
subi r3, r3, 8
lwz r31, 4(r3)
mtlr r31
# main program ends
lwz r1, 0(r1)
lwz r0, 8(r1)
mtlr r0
lmw r30, -8(r1)
blr
code:asm
.text
.globl _min_caml_start
.align 2
_min_caml_start: # main entry point
# r0 ← リンクレジスタ
mflr r0
# r30とr31の値(4バイト + 4バイト = 8バイト)をスタック(r1がスタックポインタ)に積む
stmw r30, -8(r1)
stw r0, 8(r1)
stwu r1, -96(r1)
# main program starts
li r2, 15
addi r2, r2, 16
mflr r31
stw r31, 4(r3)
addi r3, r3, 8
bl min_caml_print_int
subi r3, r3, 8
lwz r31, 4(r3)
mtlr r31
# main program ends
lwz r1, 0(r1)
lwz r0, 8(r1)
mtlr r0
lmw r30, -8(r1)
blr
命令
mflr $rd
Move from Link Register
rd ← リンクレジスタ
stmw RS, D(RA)
Store Multiple Word
RSで指定したレジスタからr31までの各レジスタの値を、M[D + RA] へ格納する
stw RS, D(RA)
Store Word
M[D+RA] ← RS
RSレジスタの値をあたいをメモリへ格納する
アーキテクチャごとの用意するファイルとその用途
asm.ml
PowerPC assembly with a few virtual instructions
emit.ml
組み立てた asm を .S ファイルとして出力
libmincaml.S
アセンブリで実装されたライブラリ関数
regAlloc.ml
レジスタ割り当て関係?
simm.ml
命令列の16bit即値最適化?
virtual.ml
仮想マシンコード生成