AArch64へ移植中のMinCamlの配列まわりを実装
MinCamlの配列まわりを実装した。
ヒープ上に配列を確保するためのアセンブリコードを書く必要があったり、32ビットから64ビットになる上での気を付けるポイントがあったりして地味に苦労したけど、無事に動いてひと安心。
https://gyazo.com/64714f0a553cb2238bdd15ef4d2c1f39
コード
サンプルコード
code:test/array_test.ml
let a = Array.make 3 0 in
let _ = a.(0) <- 4649 in
let _ = a.(1) <- 5963 in
let _ = a.(2) <- 246911 in
let p = 3.14 in
let b = (Array.make 2 0.0) in
let _ = b.(0) <- p in
let _ = b.(1) <- p *. p in
(* print int array *)
print_int a.(0); (* => 4649 *)
print_newline ();
print_int a.(1); (* => 5963 *)
print_newline ();
print_int a.(2); (* => 249611 *)
print_newline ();
(* print float array *)
print_float b.(0); (* => 3.14 *)
print_newline ();
print_float b.(1); (* => 9.859600 *)
print_newline ()
スタブ
code:samples/stub.c
extern int min_caml_start(char *, char *);
int main() {
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;
}
void min_caml_print_int(int n) {
printf("%d", n);
}
// NOTE: d0 レジスタを引数に使う場合、引数の型は double にする必要がある
void min_caml_print_float(double n) {
printf("%lf", n);
}
void min_caml_print_newline() {
printf("\n");
}
code:libmincaml.S.asm
# create_array
# x0: number of elements
# x1: initial value
.globl _min_caml_create_array
_min_caml_create_array:
mov x2, x0 // x2 = number of elements
mov x0, x27 // x0 = hp
_min_caml_create_array_loop:
// if number of elements = 0
cmp x2, 0
b.eq _min_caml_create_array_exit
// if number of elements > 0
add x27, x27, 8
sub x2, x2, 1
b _min_caml_create_array_loop
_min_caml_create_array_exit:
ret
# create_float_array
# x0: number of elements
# d0: initial value
.globl _min_caml_create_float_array
_min_caml_create_float_array:
mov x2, x0 // x2 = number of elements
mov x0, x27 // x0 = hp
_min_caml_create_float_array_loop:
// if number of elements = 0
cmp x2, 0
b.eq _min_caml_create_float_array_exit
// if number of elements > 0
add x27, x27, 8
sub x2, x2, 1
b _min_caml_create_float_array_loop
_min_caml_create_float_array_exit:
ret
32ビット → 64ビット
int 型のサイズが32ビット(4バイト)から64ビット(8バイト)になるため、AArch64/virtual.ml を以下のように修正する必要があった。
int型
32ビット(4バイト) → 64ビット(8バイト)
float型
64ビット(8バイト) → 64ビット(8バイト)
変更なし
code:diff
diff --git a/AArch64/virtual.ml b/AArch64/virtual.ml
index 79a60a4..0bed2b0 100644
--- a/AArch64/virtual.ml
+++ b/AArch64/virtual.ml
@@ -125,10 +125,12 @@ let rec g env = function (* 式の仮想マシンコード生成 (caml2html: vir
(match M.find x env with
| Type.Array(Type.Unit) -> Ans(Nop)
| Type.Array(Type.Float) ->
+ (* float の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
Let((offset, Type.Int), Slw(y, C(3)),
Ans(Lfd(x, V(offset))))
| Type.Array(_) ->
- Let((offset, Type.Int), Slw(y, C(2)),
+ (* int の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
+ Let((offset, Type.Int), Slw(y, C(3)),
Ans(Lwz(x, V(offset))))
| _ -> assert false)
| Closure.Put(x, y, z) ->
@@ -136,10 +138,12 @@ let rec g env = function (* 式の仮想マシンコード生成 (caml2html: vir
(match M.find x env with
| Type.Array(Type.Unit) -> Ans(Nop)
| Type.Array(Type.Float) ->
+ (* float の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
Let((offset, Type.Int), Slw(y, C(3)),
Ans(Stfd(z, x, V(offset))))
| Type.Array(_) ->
- Let((offset, Type.Int), Slw(y, C(2)),
+ (* int の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
+ Let((offset, Type.Int), Slw(y, C(3)),
Ans(Stw(z, x, V(offset))))
| _ -> assert false)
| Closure.ExtArray(Id.L(x)) -> Ans(SetExtL(Id.L("min_caml_" ^ x)))