Skip to content

Commit ff0bd64

Browse files
committed
tail calls
1 parent 71efb2e commit ff0bd64

File tree

6 files changed

+49
-28
lines changed

6 files changed

+49
-28
lines changed

compiler/lib-wasm/code_generation.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ let need_dummy_fun ~cps ~arity st =
709709

710710
let init_code context = instrs context.init_code
711711

712-
let function_body ~context ~param_names ~body =
712+
let function_body ~context ~return_exn ~param_names ~body =
713713
let st = { var_count = 0; vars = Var.Map.empty; instrs = []; context } in
714714
let (), st = body st in
715715
let local_count, body = st.var_count, List.rev st.instrs in
@@ -721,7 +721,7 @@ let function_body ~context ~param_names ~body =
721721
| Local (i, x, typ) -> local_types.(i) <- x, typ
722722
| Expr _ -> ())
723723
st.vars;
724-
let body = Tail_call.f ~no_tail_call:context.no_tail_call body in
724+
let body = Tail_call.f ~return_exn ~no_tail_call:context.no_tail_call body in
725725
let param_count = List.length param_names in
726726
let locals =
727727
local_types

compiler/lib-wasm/code_generation.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ val need_dummy_fun : cps:bool -> arity:int -> Code.Var.t t
199199

200200
val function_body :
201201
context:context
202+
-> return_exn:bool
202203
-> param_names:Code.Var.t list
203204
-> body:unit t
204205
-> (Wasm_ast.var * Wasm_ast.value_type) list * Wasm_ast.instruction list

compiler/lib-wasm/curry.ml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ module Make (Target : Target_sig.S) = struct
9595
loop m [] f None
9696
in
9797
let param_names = args @ [ f ] in
98-
let locals, body = function_body ~context ~param_names ~body in
98+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
9999
W.Function
100100
{ name
101101
; exported_name = None
@@ -130,7 +130,7 @@ module Make (Target : Target_sig.S) = struct
130130
push (Closure.curry_allocate ~cps:false ~arity m ~f:name' ~closure:f ~arg:x)
131131
in
132132
let param_names = [ x; f ] in
133-
let locals, body = function_body ~context ~param_names ~body in
133+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
134134
W.Function
135135
{ name
136136
; exported_name = None
@@ -181,7 +181,7 @@ module Make (Target : Target_sig.S) = struct
181181
loop m [] f None
182182
in
183183
let param_names = args @ [ f ] in
184-
let locals, body = function_body ~context ~param_names ~body in
184+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
185185
W.Function
186186
{ name
187187
; exported_name = None
@@ -220,7 +220,7 @@ module Make (Target : Target_sig.S) = struct
220220
instr (W.Return (Some c))
221221
in
222222
let param_names = [ x; cont; f ] in
223-
let locals, body = function_body ~context ~param_names ~body in
223+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
224224
W.Function
225225
{ name
226226
; exported_name = None
@@ -264,7 +264,7 @@ module Make (Target : Target_sig.S) = struct
264264
build_applies (load f) l)
265265
in
266266
let param_names = l @ [ f ] in
267-
let locals, body = function_body ~context ~param_names ~body in
267+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
268268
W.Function
269269
{ name
270270
; exported_name = None
@@ -305,7 +305,7 @@ module Make (Target : Target_sig.S) = struct
305305
push (call ~cps:true ~arity:2 (load f) [ x; iterate ]))
306306
in
307307
let param_names = l @ [ f ] in
308-
let locals, body = function_body ~context ~param_names ~body in
308+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
309309
W.Function
310310
{ name
311311
; exported_name = None
@@ -340,7 +340,7 @@ module Make (Target : Target_sig.S) = struct
340340
instr (W.Return (Some e))
341341
in
342342
let param_names = l @ [ f ] in
343-
let locals, body = function_body ~context ~param_names ~body in
343+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
344344
W.Function
345345
{ name
346346
; exported_name = None

compiler/lib-wasm/generate.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,7 @@ module Generate (Target : Target_sig.S) = struct
19691969
let locals, body =
19701970
function_body
19711971
~context:ctx.global_context
1972+
~return_exn
19721973
~param_names
19731974
~body:
19741975
(let* () =
@@ -2037,6 +2038,7 @@ module Generate (Target : Target_sig.S) = struct
20372038
let locals, body =
20382039
function_body
20392040
~context
2041+
~return_exn:false
20402042
~param_names:[]
20412043
~body:
20422044
(List.fold_right
@@ -2067,7 +2069,7 @@ module Generate (Target : Target_sig.S) = struct
20672069

20682070
let entry_point context toplevel_fun entry_name =
20692071
let signature, param_names, body = entry_point ~toplevel_fun in
2070-
let locals, body = function_body ~context ~param_names ~body in
2072+
let locals, body = function_body ~context ~return_exn:false ~param_names ~body in
20712073
W.Function
20722074
{ name = Var.fresh_n "entry_point"
20732075
; exported_name = Some entry_name

compiler/lib-wasm/tail_call.ml

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,46 @@ let get_return ~tail i =
2424
| Push (LocalGet y) when tail -> Some y
2525
| _ -> None
2626

27-
let rewrite_tail_call ~no_tail_call ~y i =
27+
let rewrite_tail_call ~return_exn ~no_tail_call ~y i =
2828
match i with
2929
| Wasm_ast.LocalSet (x, Call (symb, l))
3030
when Code.Var.equal x y && not (Code.Var.Hashtbl.mem no_tail_call symb) ->
3131
Some (Wasm_ast.Return_call (symb, l))
3232
| LocalSet (x, Call_ref (ty, e, l)) when Code.Var.equal x y ->
3333
Some (Return_call_ref (ty, e, l))
34+
| LocalSet (x, Br_on_null (_, Call (symb, l))) when return_exn && Code.Var.equal x y ->
35+
Some (Wasm_ast.Return_call (symb, l))
36+
| LocalSet (x, Br_on_null (_, Call_ref (ty, e, l)))
37+
when return_exn && Code.Var.equal x y -> Some (Return_call_ref (ty, e, l))
3438
| _ -> None
3539

36-
let rec instruction ~no_tail_call ~tail i =
40+
let rec instruction ~return_exn ~no_tail_call ~tail i =
3741
match i with
38-
| Wasm_ast.Loop (ty, l) -> Wasm_ast.Loop (ty, instructions ~no_tail_call ~tail l)
39-
| Block (ty, l) -> Block (ty, instructions ~no_tail_call ~tail l)
42+
| Wasm_ast.Loop (ty, l) ->
43+
Wasm_ast.Loop (ty, instructions ~return_exn ~no_tail_call ~tail l)
44+
| Block (ty, l) -> Block (ty, instructions ~return_exn ~no_tail_call ~tail l)
4045
| If (ty, e, l1, l2) ->
41-
If (ty, e, instructions ~no_tail_call ~tail l1, instructions ~no_tail_call ~tail l2)
46+
If
47+
( ty
48+
, e
49+
, instructions ~return_exn ~no_tail_call ~tail l1
50+
, instructions ~return_exn ~no_tail_call ~tail l2 )
4251
| Return (Some (Call (symb, l))) when not (Code.Var.Hashtbl.mem no_tail_call symb) ->
4352
Return_call (symb, l)
4453
| Return (Some (Call_ref (ty, e, l))) -> Return_call_ref (ty, e, l)
4554
| Push (Call (symb, l)) when tail && not (Code.Var.Hashtbl.mem no_tail_call symb) ->
4655
Return_call (symb, l)
4756
| Push (Call_ref (ty, e, l)) when tail -> Return_call_ref (ty, e, l)
4857
| Push (Call_ref _) -> i
58+
| Return (Some (Br_on_null (_, Call (symb, l)))) when return_exn -> Return_call (symb, l)
59+
| Return (Some (Br_on_null (_, Call_ref (ty, e, l)))) when return_exn ->
60+
Return_call_ref (ty, e, l)
61+
| Push (Br_on_null (_, Call (symb, l))) when return_exn && tail -> Return_call (symb, l)
62+
| Push (Br_on_null (_, Call_ref (ty, e, l))) when return_exn && tail ->
63+
Return_call_ref (ty, e, l)
64+
| Push (Br_on_null (_, Call_ref _)) when return_exn -> i
4965
| Drop (BlockExpr (typ, l)) ->
50-
Drop (BlockExpr (typ, instructions ~no_tail_call ~tail:false l))
66+
Drop (BlockExpr (typ, instructions ~return_exn ~no_tail_call ~tail:false l))
5167
| Drop _
5268
| LocalSet _
5369
| GlobalSet _
@@ -67,28 +83,29 @@ let rec instruction ~no_tail_call ~tail i =
6783
| Unreachable
6884
| Event _ -> i
6985

70-
and instructions ~no_tail_call ~tail l =
86+
and instructions ~return_exn ~no_tail_call ~tail l =
7187
match l with
7288
| [] -> []
73-
| [ i ] -> [ instruction ~no_tail_call ~tail i ]
74-
| i :: Nop :: rem -> instructions ~no_tail_call ~tail (i :: rem)
75-
| i :: i' :: Nop :: rem -> instructions ~no_tail_call ~tail (i :: i' :: rem)
89+
| [ i ] -> [ instruction ~return_exn ~no_tail_call ~tail i ]
90+
| i :: Nop :: rem -> instructions ~return_exn ~no_tail_call ~tail (i :: rem)
91+
| i :: i' :: Nop :: rem -> instructions ~return_exn ~no_tail_call ~tail (i :: i' :: rem)
7692
| i :: i' :: (([] | [ Event _ ]) as event_opt) -> (
7793
(* There can be an event at the end of the function, which we
7894
should keep. *)
7995
match get_return ~tail i' with
8096
| None ->
81-
instruction ~no_tail_call ~tail:false i
82-
:: instruction ~no_tail_call ~tail i'
97+
instruction ~return_exn ~no_tail_call ~tail:false i
98+
:: instruction ~return_exn ~no_tail_call ~tail i'
8399
:: event_opt
84100
| Some y -> (
85-
match rewrite_tail_call ~no_tail_call ~y i with
101+
match rewrite_tail_call ~return_exn ~no_tail_call ~y i with
86102
| None ->
87-
instruction ~no_tail_call ~tail:false i
88-
:: instruction ~no_tail_call ~tail i'
103+
instruction ~return_exn ~no_tail_call ~tail:false i
104+
:: instruction ~return_exn ~no_tail_call ~tail i'
89105
:: event_opt
90106
| Some i'' -> i'' :: event_opt))
91107
| i :: rem ->
92-
instruction ~no_tail_call ~tail:false i :: instructions ~no_tail_call ~tail rem
108+
instruction ~return_exn ~no_tail_call ~tail:false i
109+
:: instructions ~return_exn ~no_tail_call ~tail rem
93110

94-
let f ~no_tail_call l = instructions ~no_tail_call ~tail:true l
111+
let f ~return_exn ~no_tail_call l = instructions ~return_exn ~no_tail_call ~tail:true l

compiler/lib-wasm/tail_call.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*)
1818

1919
val f :
20-
no_tail_call:unit Code.Var.Hashtbl.t
20+
return_exn:bool
21+
-> no_tail_call:unit Code.Var.Hashtbl.t
2122
-> Wasm_ast.instruction list
2223
-> Wasm_ast.instruction list

0 commit comments

Comments
 (0)