フィボナッチ数を計算するAArch64コードを出力
https://gyazo.com/d08bda965c508de8894d7678697937d6
主に以下を修正して、無事にフィボナッチ数が計算できるようになった。
レジスタの値のスタックへの退避(Save)
code:diff
(* 退避の仮想命令の実装 (caml2html: emit_save) *)
| NonTail(_), Save(x, y) when List.mem x allregs && not (S.mem y !stackset) ->
save y;
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(_), Save(x, y) when List.mem x allfregs && not (S.mem y !stackset) ->
savef y;
Printf.fprintf oc "\tstfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
| NonTail(_), Save(x, y) -> assert (S.mem y !stackset); ()
スタックからレジスタへの値の復帰(Restore)
code:diff
(* 復帰の仮想命令の実装 (caml2html: emit_restore) *)
| NonTail(x), Restore(y) when List.mem x allregs ->
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) スタックに確保するサイズを32ビッチ(4バイト)から64ビット(8バイト)へ
code:diff
-let offset x = 4 * List.hd (locate x)
-let stacksize () = align ((List.length !stackmap + 1) * 4)
+
+(* NOTE: 64ビットなので 4 バイトから 8 バイトに修正 *)
+let offset x = 8 * List.hd (locate x)
+let stacksize () = align ((List.length !stackmap + 1) * 8)
stpとldpを使わないようにした
謎のエラーが出ていたのだけど、stpとldpを使ってる箇所をベタに書き直したらいい感じに動くようになった。
code:diff
+ (* sp と hp を設定 *)
+ Printf.fprintf oc "\tadd %s, %s, 0\n" (reg reg_sp) (reg "%x0");
+ Printf.fprintf oc "\tadd %s, %s, 0\n" (reg reg_hp) (reg "%x1");
+
(* fpとlrをスタックへ退避 *)
- Printf.fprintf oc "\tstp fp, lr, sp, -16!\n"; + Printf.fprintf oc "\tstr fp, %s, 0\n" (reg reg_sp); + Printf.fprintf oc "\tstr lr, %s, 8\n" (reg reg_sp); + Printf.fprintf oc "\tadd %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
Printf.fprintf oc "#\tmain program starts\n";
stackset := S.empty;
@@ -284,7 +298,9 @@ let f oc (Prog(data, fundefs, e)) =
Printf.fprintf oc "#\tmain program ends\n";
(* fpとlrをスタックから復元 *)
- Printf.fprintf oc "\tldp fp, lr, sp, 16\n"; + Printf.fprintf oc "\tsub %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
+ Printf.fprintf oc "\tldr fp, %s, 0\n" (reg reg_sp); + Printf.fprintf oc "\tstr lr, %s, 8\n" (reg reg_sp); (* 呼び出し元へ戻る *)
Printf.fprintf oc "\tret\n"
diff の全体像
code:diff
diff --git a/AArch64/asm.ml b/AArch64/asm.ml
index 9cada30..7530076 100644
--- a/AArch64/asm.ml
+++ b/AArch64/asm.ml
@@ -43,10 +43,12 @@ 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 までを利用して様子を見る *)
+(* fp (x29) と lr(x30) は除外 *)
+(* x28 は sp として、x27 は hp として、x26 は tmp として利用するため除外 *)
let regs = (* Array.init 27 (fun i -> Printf.sprintf "_R_%d" i) *)
- [| "%x0"; "%x1"; "%x2"; "%x5"; "%x6"; "%x7"; "%x8"; "%x9"; "%x10";
- "%x11"; "%x12"; "%x13"; "%x14"; "%x15"; "%x16" |]
+ [| "%x0"; "%x1"; "%x2"; "%x3"; "%x4"; "%x5"; "%x6"; "%x7"; "%x8"; "%x9"; "%x10";
+ "%x11"; "%x12"; "%x13"; "%x14"; "%x15"; "%x16"; "%x17"; "%x18"; "%x19"; "%x20";
+ "%x21"; "%x22"; "%x23"; "%x24"; "%x25"; "%x26"; "%x27"; "%x28" |]
let fregs = Array.init 32 (fun i -> Printf.sprintf "%%f%d" i)
let allregs = Array.to_list regs
let allfregs = Array.to_list fregs
@@ -54,11 +56,11 @@ let reg_cl = regs.(Array.length regs - 1) (* closure address (caml2html: sparcas
let reg_sw = regs.(Array.length regs - 2) (* temporary for swap *)
let reg_fsw = fregs.(Array.length fregs - 1) (* temporary for swap *)
(* AArch64 のスタックポインタは sp *)
-let reg_sp = "%sp" (* stack pointer *)
+let reg_sp = "%x28" (* stack pointer *)
(* PowerPCが4番レジスタを使ってたので、ひとまずそのままで様子を見る *)
-let reg_hp = "%x4" (* heap pointer (caml2html: sparcasm_reghp) *)
+let reg_hp = "%x27" (* heap pointer (caml2html: sparcasm_reghp) *)
(* 特に意図はなく x17 にしてる *)
-let reg_tmp = "%x17" (* XX ad hoc *) +let reg_tmp = "%x26" (* XX ad hoc *) let is_reg x = (x.0 = '%') (* super-tenuki *)
@@ -90,4 +92,5 @@ let rec concat e1 xt e2 =
| Ans(exp) -> Let(xt, exp, e2)
| Let(yt, exp, e1') -> Let(yt, exp, concat e1' xt e2)
+(* NOTE: 修正が必要になるかもしれない *)
let align i = (if i mod 8 = 0 then i else i + 4)
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 81c9ac2..2cbfe2f 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -21,8 +21,10 @@ let locate x =
| y :: zs when x = y -> 0 :: List.map succ (loc zs)
| y :: zs -> List.map succ (loc zs) in
loc !stackmap
-let offset x = 4 * List.hd (locate x)
-let stacksize () = align ((List.length !stackmap + 1) * 4)
+
+(* NOTE: 64ビットなので 4 バイトから 8 バイトに修正 *)
+let offset x = 8 * List.hd (locate x)
+let stacksize () = align ((List.length !stackmap + 1) * 8)
let reg r =
if is_reg r
@@ -78,9 +80,9 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), Mr(y) -> Printf.fprintf oc "\tmr\t%s, %s\n" (reg x) (reg y)
| NonTail(x), Neg(y) -> Printf.fprintf oc "\tneg\t%s, %s\n" (reg x) (reg y)
| NonTail(x), Add(y, V(z)) -> Printf.fprintf oc "\tadd\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Add(y, C(z)) -> Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg x) (reg y) z
+ | NonTail(x), Add(y, C(z)) -> Printf.fprintf oc "\tadd\t%s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Sub(y, V(z)) -> Printf.fprintf oc "\tsub\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsubi\t%s, %s, %d\n" (reg x) (reg y) z
+ | NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsub\t%s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Slw(y, V(z)) -> Printf.fprintf oc "\tslw\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Slw(y, C(z)) -> Printf.fprintf oc "\tslwi\t%s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Lwz(y, V(z)) -> Printf.fprintf oc "\tlwzx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
@@ -102,14 +104,14 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
(* 退避の仮想命令の実装 (caml2html: emit_save) *)
| NonTail(_), Save(x, y) when List.mem x allregs && not (S.mem y !stackset) ->
save y;
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(_), Save(x, y) when List.mem x allfregs && not (S.mem y !stackset) ->
savef y;
Printf.fprintf oc "\tstfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
| NonTail(_), Save(x, y) -> assert (S.mem y !stackset); ()
(* 復帰の仮想命令の実装 (caml2html: emit_restore) *)
| NonTail(x), Restore(y) when List.mem x allregs ->
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(x), Restore(y) ->
assert (List.mem x allfregs);
Printf.fprintf oc "\tlfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
@@ -194,7 +196,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tlwz\t%s, 0(%s)\n" (reg reg_tmp) (reg reg_cl);
Printf.fprintf oc "\tmtctr\t%s\n" (reg reg_tmp);
Printf.fprintf oc "\tbctrl\n";
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))
@@ -202,15 +204,21 @@ 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)) ->
- (* fpとlrをスタックへ退避 *)
- Printf.fprintf oc "\tstp fp, lr, sp, -16!\n"; g'_args oc [] ys zs;
let ss = stacksize () in
-
+ (* lrをスタックへ退避 *)
+ Printf.fprintf oc "\tmov %s, lr\n" (reg reg_tmp);
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); + Printf.fprintf oc "\tadd %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
Printf.fprintf oc "\tbl %s\n" x;
-
- (* fpとlrをスタックから復元 *)
- Printf.fprintf oc "\tldp fp, lr, sp, 16\n" + Printf.fprintf oc "\tsub %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); + if List.mem a allregs && a <> regs.(0) then
+ Printf.fprintf oc "\t@@@@mov\t%s, %s\n" (reg a) (reg regs.(0))
+ else if List.mem a allfregs && a <> fregs.(0) then
+ Printf.fprintf oc "\t@@@@fmr\t%s, %s\n" (reg a) (reg fregs.(0));
+ (* lrをスタックから復元 *)
+ Printf.fprintf oc "\tmov lr, %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 %s\n" bn b_else;
@@ -240,7 +248,7 @@ and g'_args oc x_reg_cl ys zs =
(0, x_reg_cl)
ys in
List.iter
- (fun (y, r) -> Printf.fprintf oc "\tmr\t%s, %s\n" (reg r) (reg y))
+ (fun (y, r) -> Printf.fprintf oc "\tmov %s, %s\n" (reg r) (reg y))
(shuffle reg_sw yrs);
let (d, zfrs) =
List.fold_left
@@ -274,8 +282,14 @@ let f oc (Prog(data, fundefs, e)) =
List.iter (fun fundef -> h oc fundef) fundefs;
Printf.fprintf oc "_min_caml_start: # main entry point\n";
+ (* sp と hp を設定 *)
+ Printf.fprintf oc "\tadd %s, %s, 0\n" (reg reg_sp) (reg "%x0");
+ Printf.fprintf oc "\tadd %s, %s, 0\n" (reg reg_hp) (reg "%x1");
+
(* fpとlrをスタックへ退避 *)
- Printf.fprintf oc "\tstp fp, lr, sp, -16!\n"; + Printf.fprintf oc "\tstr fp, %s, 0\n" (reg reg_sp); + Printf.fprintf oc "\tstr lr, %s, 8\n" (reg reg_sp); + Printf.fprintf oc "\tadd %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
Printf.fprintf oc "#\tmain program starts\n";
stackset := S.empty;
@@ -284,7 +298,9 @@ let f oc (Prog(data, fundefs, e)) =
Printf.fprintf oc "#\tmain program ends\n";
(* fpとlrをスタックから復元 *)
- Printf.fprintf oc "\tldp fp, lr, sp, 16\n"; + Printf.fprintf oc "\tsub %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
+ Printf.fprintf oc "\tldr fp, %s, 0\n" (reg reg_sp); + Printf.fprintf oc "\tstr lr, %s, 8\n" (reg reg_sp); (* 呼び出し元へ戻る *)
Printf.fprintf oc "\tret\n"
diff --git a/samples/stub.c b/samples/stub.c
index bf4c3b5..7e562c5 100644
--- a/samples/stub.c
+++ b/samples/stub.c
@@ -1,10 +1,19 @@
-extern int min_caml_start();
+extern int min_caml_start(char *, char *);
int main() {
- min_caml_start();
+ char *hp, *sp;
+
+ sp = alloca(1000000); hp = malloc(4000000);
+ if (hp == NULL || sp == NULL) {
+ fprintf(stderr, "malloc or alloca failed\n");
+ return 1;
+ }
+ fprintf(stderr, "sp = %p, hp = %p\n", sp, hp);
+ min_caml_start(sp, hp);
+
return 0;
}