4649を出力するだけのRISC-Vコードを出力
https://gyazo.com/22fa37d2ee684abab6750fa1c5c71427
最初は 4649 を出力するだけのコードをコンパイルできるようにする。
テストコード
code:test/4649.ml
print_int 4649; print_newline ()
ビルドと実行
code:sh
$ make test/4649
$ spike /opt/riscv/pk/riscv32-unknown-elf/bin/pk test/4649
bbl loader
sp = 0x7ff0bb40, hp = 0x31c80
4649
ホストのコンパイラとターゲットのコンパイラ
MinCamlをビルドするのはホスト(AArch64)のコンパイラだけど、MinCamlが出力したアセンブリをビルドするのはRISC-Vターゲットのコンパイラを使う必要がある。そのためMakefileを以下のように修正した。
code:diff
diff --git a/Makefile b/Makefile
index 23a02f5..0940af3 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,7 @@
RESULT = min-caml
NCSUFFIX = .opt
CC = gcc
+TGT_CC = riscv32-unknown-elf-gcc
CFLAGS = -g -O2 -Wall
OCAMLLDFLAGS=-warn-error -31
@@ -43,9 +44,9 @@ TRASH = $(TESTS:%=test/%.s) $(TESTS:%=test/%) $(TESTS:%=test/%.res) $(TESTS:%=te
test/%.s: $(RESULT) test/%.ml
./$(RESULT) test/$*
test/%: test/%.s libmincaml.S stub.c
- $(CC) $(CFLAGS) $^ -lm -o $@
+ $(TGT_CC) $(CFLAGS) $^ -lm -o $@
test/%.res: test/%
レジスタ
以下に気を付けつつ適当にレジスタを並べた
OCamlの世界のスタックポインタとCの世界のスタックポインタを混ぜると危険なので分けた
関数の引数は a0 a1...なので、regs の頭の方に a0 a1 ... を持ってきた(MinCaml では regs の頭から引数として渡される)
code:diff
diff --git a/RV32/asm.ml b/RV32/asm.ml
index 491c82c..48ae39d 100644
--- a/RV32/asm.ml
+++ b/RV32/asm.ml
@@ -43,20 +43,57 @@ type prog = Prog of (Id.l * float) list * fundef list * t
let fletd(x, e1, e2) = Let((x, Type.Float), e1, e2)
let seq(e1, e2) = Let((Id.gentmp Type.Unit, Type.Unit), e1, e2)
+(* zero, ra, sp, gp, s0(fp) は除外 *)
+(* s10 は reg_sp として、s11 は reg_hp として、t0 は reg_tmp として利用するため除外 *)
let regs = (* Array.init 27 (fun i -> Printf.sprintf "_R_%d" i) *)
- [| "%r2"; "%r5"; "%r6"; "%r7"; "%r8"; "%r9"; "%r10";
- "%r11"; "%r12"; "%r13"; "%r14"; "%r15"; "%r16"; "%r17"; "%r18";
- "%r19"; "%r20"; "%r21"; "%r22"; "%r23"; "%r24"; "%r25"; "%r26";
- "%r27"; "%r28"; "%r29"; "%r30" |]
+ [|
+ "%a0"; "%a1"; "%a2"; "%a3"; "%a4"; "%a5"; "%a6"; "%a7";
+ "%s1"; "%s2"; "%s3"; "%s4"; "%s5"; "%s6"; "%s7"; "%s8"; "%s9";
+ "%t1"; "%t2"; "%t3"; "%t4"; "%t5"; "%t6"
+ |]
let fregs = Array.init 32 (fun i -> Printf.sprintf "%%f%d" i)
let allregs = Array.to_list regs
let allfregs = Array.to_list fregs
let reg_cl = regs.(Array.length regs - 1) (* closure address (caml2html: sparcasm_regcl) *)
let reg_sw = regs.(Array.length regs - 2) (* temporary for swap *)
let reg_fsw = fregs.(Array.length fregs - 1) (* temporary for swap *)
-let reg_sp = "%r3" (* stack pointer *)
-let reg_hp = "%r4" (* heap pointer (caml2html: sparcasm_reghp) *)
-let reg_tmp = "%r31" (* XX ad hoc *) +let reg_sp = "%s10" (* stack pointer *)
+let reg_hp = "%s11" (* heap pointer (caml2html: sparcasm_reghp) *)
+let reg_tmp = "%t0" (* t0 を tmp として使ってみる *)
let is_reg x = (x.0 = '%') 変更箇所
code:diff
diff --git a/Makefile b/Makefile
index 23a02f5..0940af3 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,7 @@
RESULT = min-caml
NCSUFFIX = .opt
CC = gcc
+TGT_CC = riscv32-unknown-elf-gcc
CFLAGS = -g -O2 -Wall
OCAMLLDFLAGS=-warn-error -31
@@ -33,7 +34,7 @@ adder funcomp cls-rec cls-bug cls-bug2 cls-reg-bug \
shuffle spill spill2 spill3 join-stack join-stack2 join-stack3 \
join-reg join-reg2 non-tail-if non-tail-if2 \
inprod inprod-rec inprod-loop matmul matmul-flat \
-manyargs
+manyargs 4649
do_test: $(TESTS:%=test/%.cmp)
@@ -43,9 +44,9 @@ TRASH = $(TESTS:%=test/%.s) $(TESTS:%=test/%) $(TESTS:%=test/%.res) $(TESTS:%=te
test/%.s: $(RESULT) test/%.ml
./$(RESULT) test/$*
test/%: test/%.s libmincaml.S stub.c
- $(CC) $(CFLAGS) $^ -lm -o $@
+ $(TGT_CC) $(CFLAGS) $^ -lm -o $@
test/%.res: test/%
- $< > $@
+ spike /opt/riscv/pk/riscv32-unknown-elf/bin/pk $< | grep -v "bbl loader" | grep -v "sp =" > $@
test/%.ans: test/%.ml
ocaml $< > $@
test/%.cmp: test/%.res test/%.ans
diff --git a/RV32/asm.ml b/RV32/asm.ml
index 491c82c..48ae39d 100644
--- a/RV32/asm.ml
+++ b/RV32/asm.ml
@@ -43,20 +43,57 @@ type prog = Prog of (Id.l * float) list * fundef list * t
let fletd(x, e1, e2) = Let((x, Type.Float), e1, e2)
let seq(e1, e2) = Let((Id.gentmp Type.Unit, Type.Unit), e1, e2)
+(* zero, ra, sp, gp, s0(fp) は除外 *)
+(* s10 は reg_sp として、s11 は reg_hp として、t0 は reg_tmp として利用するため除外 *)
let regs = (* Array.init 27 (fun i -> Printf.sprintf "_R_%d" i) *)
- [| "%r2"; "%r5"; "%r6"; "%r7"; "%r8"; "%r9"; "%r10";
- "%r11"; "%r12"; "%r13"; "%r14"; "%r15"; "%r16"; "%r17"; "%r18";
- "%r19"; "%r20"; "%r21"; "%r22"; "%r23"; "%r24"; "%r25"; "%r26";
- "%r27"; "%r28"; "%r29"; "%r30" |]
+ [|
+ "%a0"; "%a1"; "%a2"; "%a3"; "%a4"; "%a5"; "%a6"; "%a7";
+ "%s1"; "%s2"; "%s3"; "%s4"; "%s5"; "%s6"; "%s7"; "%s8"; "%s9";
+ "%t1"; "%t2"; "%t3"; "%t4"; "%t5"; "%t6"
+ |]
let fregs = Array.init 32 (fun i -> Printf.sprintf "%%f%d" i)
let allregs = Array.to_list regs
let allfregs = Array.to_list fregs
let reg_cl = regs.(Array.length regs - 1) (* closure address (caml2html: sparcasm_regcl) *)
let reg_sw = regs.(Array.length regs - 2) (* temporary for swap *)
let reg_fsw = fregs.(Array.length fregs - 1) (* temporary for swap *)
-let reg_sp = "%r3" (* stack pointer *)
-let reg_hp = "%r4" (* heap pointer (caml2html: sparcasm_reghp) *)
-let reg_tmp = "%r31" (* XX ad hoc *) +let reg_sp = "%s10" (* stack pointer *)
+let reg_hp = "%s11" (* heap pointer (caml2html: sparcasm_reghp) *)
+let reg_tmp = "%t0" (* t0 を tmp として使ってみる *)
let is_reg x = (x.0 = '%') (* super-tenuki *)
diff --git a/RV32/emit.ml b/RV32/emit.ml
index 323144d..0223256 100644
--- a/RV32/emit.ml
+++ b/RV32/emit.ml
@@ -200,19 +200,25 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
| (NonTail(a), CallDir(Id.L(x), ys, zs)) ->
- Printf.fprintf oc "\tmflr\t%s\n" (reg reg_tmp);
+ (* ra を tmp レジスタへ退避 *)
+ Printf.fprintf oc "\tmv %s, ra\n" (reg reg_tmp);
+
g'_args oc [] ys zs;
let ss = stacksize () in
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
- Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
- Printf.fprintf oc "\tbl\t%s\n" x;
- Printf.fprintf oc "\tsubi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
+ Printf.fprintf oc "\tsw %s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
+ Printf.fprintf oc "\taddi %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+
+ Printf.fprintf oc "\tcall %s\n" x;
+
+ Printf.fprintf oc "\taddi %s, %s, %d\n" (reg reg_sp) (reg reg_sp) (ss * (-1));
+ Printf.fprintf oc "\tlw %s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
if List.mem a allregs && a <> regs.(0) then
Printf.fprintf oc "\tmr\t%s, %s\n" (reg a) (reg regs.(0))
else if List.mem a allfregs && a <> fregs.(0) then
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
- Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
+
+ (* tmp レジスタから ra を復帰 *)
+ Printf.fprintf oc "\tmv ra, %s\n" (reg reg_tmp)
and g'_tail_if oc e1 e2 b bn =
let b_else = Id.genid (b ^ "_else") in
Printf.fprintf oc "\t%s\tcr7, %s\n" bn b_else;
@@ -275,18 +281,28 @@ let f oc (Prog(data, fundefs, e)) =
Printf.fprintf oc "\t.align 2\n";
List.iter (fun fundef -> h oc fundef) fundefs;
Printf.fprintf oc "_min_caml_start: # main entry point\n";
- Printf.fprintf oc "\tmflr\tr0\n";
- Printf.fprintf oc "\tstmw\tr30, -8(r1)\n";
- Printf.fprintf oc "\tstw\tr0, 8(r1)\n";
- Printf.fprintf oc "\tstwu\tr1, -96(r1)\n";
+
+ (* sp と hp を設定 *)
+ Printf.fprintf oc "\tmv %s, %s\n" (reg reg_sp) (reg "%a0");
+ Printf.fprintf oc "\tmv %s, %s\n" (reg reg_hp) (reg "%a1");
+
+ (* スタックへ sp と s0 を退避 *)
+ Printf.fprintf oc "\taddi %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
+ Printf.fprintf oc "\tsw ra, -8(%s)\n" (reg reg_sp);
+ Printf.fprintf oc "\tsw s0, -4(%s)\n" (reg reg_sp);
+ (* 新しい fp を s0 へ設定 *)
+ Printf.fprintf oc "\taddi s0, %s, -16\n" (reg reg_sp);
+
Printf.fprintf oc "#\tmain program starts\n";
stackset := S.empty;
stackmap := [];
g oc (NonTail("_R_0"), e);
Printf.fprintf oc "#\tmain program ends\n";
- (* Printf.fprintf oc "\tmr\tr3, %s\n" regs.(0); *)
- Printf.fprintf oc "\tlwz\tr1, 0(r1)\n";
- Printf.fprintf oc "\tlwz\tr0, 8(r1)\n";
- Printf.fprintf oc "\tmtlr\tr0\n";
- Printf.fprintf oc "\tlmw\tr30, -8(r1)\n";
- Printf.fprintf oc "\tblr\n"
+
+ (* スタックから sp と s0 を復帰 *)
+ Printf.fprintf oc "\tlw ra, -8(%s)\n" (reg reg_sp);
+ Printf.fprintf oc "\tlw s0, -4(%s)\n" (reg reg_sp);
+ Printf.fprintf oc "\taddi %s, %s, -16\n" (reg reg_sp) (reg reg_sp);
+
+ (* リターン *)
+ Printf.fprintf oc "\tret\n"
diff --git a/RV32/libmincaml.S b/RV32/libmincaml.S
index a639289..1c2c771 100644
--- a/RV32/libmincaml.S
+++ b/RV32/libmincaml.S
@@ -1,636 +1,10 @@
- .cstring
.align 2
LC0:
.ascii "%d\0"
.align 2
LC1:
.ascii "%lf\0"
- .literal8
.align 3
LC2:
.long 1127219200
.long -2147483648
- .text
- .align 2
- .globl min_caml_print_newline
-min_caml_print_newline:
- mflr r0
- stmw r30, -8(r1)
- stw r0, 8(r1)
- stw r3, 12(r1)
- stw r4, 16(r1)
- stwu r1, -80(r1)
- mr r30, r1
- li r3, 10
- bl putchar
- lwz r1, 0(r1)
- lwz r0, 8(r1)
- lwz r3, 12(r1)
- lwz r4, 16(r1)
- mtlr r0
- lmw r30, -8(r1)
- blr
-