整数をプリントするだけのAArch64コードを出力
参考
PowerPC版をビルド
ARM64対応にあたりPowerPC版をベースに手を入れていく。以下の手順でPowerPC版をビルドする
code:sh
$ ./to_ppc
$ make min-caml
copy_int32 が無いよーとエラーが出たら float.c を以下のように 修正する
code:diff
diff --git a/float.c b/float.c
index 1508d9e..1165150 100644
--- a/float.c
+++ b/float.c
@@ -11,11 +11,11 @@ typedef union {
value gethi(value v) {
dbl d;
d.d = Double_val(v);
- return copy_int32(d.i0); + return caml_copy_int32(d.i0); }
value getlo(value v) {
dbl d;
d.d = Double_val(v);
- return copy_int32(d.i1); + return caml_copy_int32(d.i1); }
以下の整数を出力するだけのMinCamlのソースを...
code:test/print.ml
print_int 123;
print_int (-456);
print_int (789+0)
MinCamlでコンパイルすると...
code:sh
$ ./min-caml test/print
以下のPowerPCのアセンブリソースが出力される
code:test/print.s
.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, 123
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
li r2, -456
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
li r2, 789
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
AArch64版の事前準備
AArch64版はPowerPC版をベースとするためPowerPCディレクトリをAArch64としてコピーする
code:sh
cp -r PowerPC/ ./AArch64
AArch64/ ディレクトリに置かれた AArch64 版のソース MinCaml へ反映するスクリプトも用意する。 chmod +x to_aarch64 も忘れずに
code:to_aarch64
ln -sf AArch64/{*.ml{,i},libmincaml.S} .
cd test; ln -sf AArch64/{,too}manyargs.ml .; cd ..
cd shootout; ln -sf AArch64/Makefile .; cd ..
cd bytemark; ln -sf AArch64/Makefile .; cd ..
cd min-rt; ln -sf ../AArch64/globals.s .; cd ..
AArch64で動くように修正
code:diff
diff --git a/AArch64/asm.ml b/AArch64/asm.ml
index 491c82c..9cada30 100644
--- a/AArch64/asm.ml
+++ b/AArch64/asm.ml
@@ -43,20 +43,22 @@ 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)
+(* ひとまず x0 から x16 までを利用して様子を見る *)
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" |]
+ [| "%x0"; "%x1"; "%x2"; "%x5"; "%x6"; "%x7"; "%x8"; "%x9"; "%x10";
+ "%x11"; "%x12"; "%x13"; "%x14"; "%x15"; "%x16" |]
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 *) +(* AArch64 のスタックポインタは sp *)
+let reg_sp = "%sp" (* stack pointer *)
+(* PowerPCが4番レジスタを使ってたので、ひとまずそのままで様子を見る *)
+let reg_hp = "%x4" (* heap pointer (caml2html: sparcasm_reghp) *)
+(* 特に意図はなく x17 にしてる *)
+let reg_tmp = "%x17" (* XX ad hoc *) let is_reg x = (x.0 = '%') (* super-tenuki *)
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 323144d..501d9e9 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -59,7 +59,9 @@ let rec g oc = function (* 命令列のアセンブリ生成 (caml2html: emit_g)
and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprime) *)
(* 末尾でなかったら計算結果をdestにセット (caml2html: emit_nontail) *)
| NonTail(_), Nop -> ()
- | NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tli\t%s, %d\n" (reg x) i
+ (* Li は Mov で良いかな? *)
+ | NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tmov %s, %d\n" (reg x) i
+ (* TODO: こちらは後で実装する *)
| NonTail(x), Li(i) ->
let n = i lsr 16 in
let m = i lxor (n lsl 16) in
@@ -200,19 +202,17 @@ 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);
+ (* fpとlrをスタックへ退避 *)
+ Printf.fprintf oc "\tstp fp, lr, sp, -16!\n"; 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);
- 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)
+
+ (* 関数の頭に _ をつける *)
+ (* こんな感じ: min_caml_print_int => _min_caml_print_int *)
+ Printf.fprintf oc "\tbl _%s\n" x;
+
+ (* fpとlrをスタックから復元 *)
+ Printf.fprintf oc "\tldp fp, lr, sp, 16\n" 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 +275,18 @@ 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";
+
+ (* fpとlrをスタックへ退避 *)
+ Printf.fprintf oc "\tstp fp, lr, sp, -16!\n"; +
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"
+
+ (* fpとlrをスタックから復元 *)
+ Printf.fprintf oc "\tldp fp, lr, sp, 16\n"; +
+ (* 呼び出し元へ戻る *)
+ Printf.fprintf oc "\tret\n"
diff --git a/AArch64/regAlloc.ml b/AArch64/regAlloc.ml
index 9d8a4f3..e79a14e 100644
--- a/AArch64/regAlloc.ml
+++ b/AArch64/regAlloc.ml
@@ -44,10 +44,10 @@ let rec alloc dest cont regenv x t =
assert (not (M.mem x regenv));
let all =
match t with
- | Type.Unit -> "%r0" (* dummy *) + | Type.Unit -> "%x0" (* dummy *) | Type.Float -> allfregs
| _ -> allregs in
- if all = "%r0" then Alloc("%r0") else (* XX ad hoc optimization *) + if all = "%x0" then Alloc("%x0") else (* XX ad hoc optimization *) if is_reg x then Alloc(x) else
let free = fv cont in
try
コンパイルしてみる
code:sh
make clean && ./to_aarch64 && make min-caml && ./min-caml samples/4649
出力されたアセンブリファイル
code:samples/4649.s
.text
.globl _min_caml_start
.align 2
_min_caml_start: # main entry point
# main program starts
mov x0, 4649
bl _min_caml_print_int
bl _min_caml_print_newline
# main program ends
ret
コンパイルされたアセンブリファイルを呼び出す stub.c を用意して、
code:samples/stub.c
extern int min_caml_start();
int main() {
min_caml_start();
return 0;
}
void min_caml_print_int(int n) {
printf("%d", n);
}
void min_caml_print_newline() {
printf("\n");
}
ビルドして、
code:sh
gcc samples/4649.s samples/stub.c -o samples/4649
実行する。4649 が出力されれば大成功
code:sh
$ ./samples/4649
4649
$
(メモ)まとめてビルドと実行
code:sh
make clean && ./to_aarch64 && make min-caml && ./min-caml samples/4649 && gcc samples/4649.s samples/stub.c -o samples/4649 && ./samples/4649