MinCamlのバグ修正 ( test/non-tail-if )
#MinCaml #AArch64
test/non-tail-if.ml の以下のバグを直したい。→ 直した!
code:sh
$ ocaml test/non-tail-if.ml
-10
$ make test/non-tail-if
$ ./test/non-tail-if
sp = 0x16f5e6df8, hp = 0x158008000
-13
MLコード
code:test/non-tail-if.ml
let x = truncate 1.23 in
let y = truncate 4.56 in
let z = truncate (-.7.89) in
print_int
((if z < 0 then y else x) +
(if x > 0 then z else y) +
(if y < 0 then x else z))
x = 1
y = 4
z = -7
if z < 0 then y else x → 4
if x > 0 then z else y → -7
if y < 0 then x else z → -7
答え 10
中間表現
code:ml
- : Asm.prog =
Asm.Prog ((Id.L "l.30", 7.89); (Id.L "l.29", 4.56); (Id.L "l.28", 1.23),
[],
Asm.Let (("%d0", Type.Float), Asm.FLi (Id.L "l.28"),
Asm.Let (("%x0", Type.Int),
Asm.CallDir (Id.L "_min_caml_truncate", [], "%d0"),
Asm.Let (("%d0", Type.Float), Asm.FLi (Id.L "l.29"),
Asm.Let (("Tu32", Type.Unit), Asm.Save ("%x0", "x.13"),
Asm.Let (("%x0", Type.Int),
Asm.CallDir (Id.L "_min_caml_truncate", [], "%d0"),
Asm.Let (("%d0", Type.Float), Asm.FLi (Id.L "l.30"),
Asm.Let (("%d0", Type.Float), Asm.FNeg "%d0",
Asm.Let (("Tu33", Type.Unit), Asm.Save ("%x0", "y.14"),
Asm.Let (("%x0", Type.Int),
Asm.CallDir (Id.L "_min_caml_truncate", [], "%d0"),
Asm.Let (("%x1", Type.Int), Asm.Li 0,
Asm.Let (("%x1", Type.Int),
Asm.IfLE ("%x1", Asm.V "%x0",
Asm.Let (("%x1", Type.Int), Asm.Restore "x.13",
Asm.Ans (Asm.Mr "%x1")),
Asm.Let (("%x1", Type.Int), Asm.Restore "y.14",
Asm.Ans (Asm.Mr "%x1"))),
Asm.Let (("%x2", Type.Int), Asm.Li 0,
Asm.Let (("%x3", Type.Int), Asm.Restore "x.13",
Asm.Let (("%x2", Type.Int),
Asm.IfLE ("%x3", Asm.V "%x2",
Asm.Let (("%x2", Type.Int), Asm.Restore "y.14",
Asm.Ans (Asm.Mr "%x2")),
Asm.Ans (Asm.Mr "%x0")),
Asm.Let (("%x1", Type.Int), Asm.Add ("%x1", Asm.V "%x2"),
Asm.Let (("%x2", Type.Int), Asm.Li 0,
Asm.Let (("%x4", Type.Int), Asm.Restore "y.14",
Asm.Let (("%x0", Type.Int),
Asm.IfLE ("%x2", Asm.V "%x4", Asm.Ans (Asm.Mr "%x0"),
Asm.Ans (Asm.Mr "%x3")),
Asm.Let (("%x0", Type.Int), Asm.Add ("%x1", Asm.V "%x0"),
Asm.Ans
(Asm.CallDir (Id.L "_min_caml_print_int", "%x0", []))))))))))))))))))))))
アセンブリコード
code:test/non-tail-if.s
.data
.literal8
.align 3
l.30: # -7.890000
.long 687194767
.long -1071673508
.align 3
l.29: # 4.560000
.long -1546188227
.long 1074937200
.align 3
l.28: # 1.230000
.long 2061584302
.long 1072934420
.text
.globl _min_caml_start
.align 2
_min_caml_start: # main entry point
add x28, x0, 0
add x27, x1, 0
str fp, x28, 0
str lr, x28, 8
add x28, x28, 16
# main program starts
adrp x26, l.28@PAGE
ldr d0, x26, l.28@PAGEOFF
mov x26, lr
str x26, x28, 0
add x28, x28, 8
bl _min_caml_truncate
sub x28, x28, 8
ldr x26, x28, 0
mov lr, x26
adrp x26, l.29@PAGE
ldr d0, x26, l.29@PAGEOFF
str x0, x28, 0
mov x26, lr
str x26, x28, 8
add x28, x28, 16
bl _min_caml_truncate
sub x28, x28, 16
ldr x26, x28, 8
mov lr, x26
adrp x26, l.30@PAGE
ldr d0, x26, l.30@PAGEOFF
str x0, x28, 8
mov x26, lr
str x26, x28, 16
add x28, x28, 24
bl _min_caml_truncate
sub x28, x28, 24
ldr x26, x28, 16
mov lr, x26
cmp x0, 0
blt bge_else.34
ldr x1, x28, 0
b bge_cont.35
bge_else.34:
ldr x1, x28, 8
bge_cont.35:
ldr x2, x28, 0
cmp x2, 0
bgt ble_else.36
ldr x3, x28, 8
b ble_cont.37
ble_else.36:
mov x3, x0
ble_cont.37:
add x1, x1, x3
ldr x3, x28, 8
cmp x3, 0
blt bge_else.38
b bge_cont.39
bge_else.38:
mov x0, x2
bge_cont.39:
add x0, x1, x0
mov x26, lr
str x26, x28, 16
add x28, x28, 24
bl _min_caml_print_int
sub x28, x28, 24
ldr x26, x28, 16
mov lr, x26
# main program ends
sub x28, x28, 16
ldr fp, x28, 0
str lr, x28, 8
ret
原因
float を int に変換する際、32ビットのwレジスタに結果を格納してたため、マイナスの値を引数にとる if がうまく動いてなかったの原因。以下のように修正したらうまく動くようになった。
code:diff
diff --git a/AArch64/libmincaml.S b/AArch64/libmincaml.S
index 4d2f5b4..0c15feb 100644
--- a/AArch64/libmincaml.S
+++ b/AArch64/libmincaml.S
@@ -59,13 +59,13 @@ _min_caml_create_float_array_exit:
_min_caml_int_of_float:
.globl _min_caml_truncate
_min_caml_truncate:
- fcvtzs w0, d0
+ fcvtzs x0, d0
ret
# float_of_int
.globl _min_caml_float_of_int
_min_caml_float_of_int:
- scvtf d0, w0
+ scvtf d0, x0
ret