Skip to content

Commit 4e249c8

Browse files
committed
Disable tail-call optimization for Math builtins
V8 currently generates suboptimal code for this (the builtins are no longer inlined).
1 parent fdec717 commit 4e249c8

File tree

5 files changed

+81
-44
lines changed

5 files changed

+81
-44
lines changed

compiler/lib-wasm/code_generation.ml

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type context =
5959
; mutable globalized_variables : Var.Set.t
6060
; value_type : W.value_type
6161
; mutable unit_name : string option
62+
; mutable no_tail_call : unit Var.Hashtbl.t
6263
}
6364

6465
let make_context ~value_type =
@@ -82,6 +83,7 @@ let make_context ~value_type =
8283
; globalized_variables = Var.Set.empty
8384
; value_type
8485
; unit_name = None
86+
; no_tail_call = Var.Hashtbl.create 16
8587
}
8688

8789
type var =
@@ -224,27 +226,30 @@ let get_global name =
224226
| Some { init; _ } -> init
225227
| _ -> None)
226228

227-
let register_import ?(import_module = "env") ~name typ st =
228-
( (try
229-
let x, typ' =
230-
StringMap.find name (StringMap.find import_module st.context.imports)
231-
in
232-
(*ZZZ error message*)
233-
assert (Poly.equal typ typ');
234-
x
235-
with Not_found ->
236-
let x = Var.fresh_n name in
237-
st.context.imports <-
238-
StringMap.update
239-
import_module
240-
(fun m ->
241-
Some
242-
(match m with
243-
| None -> StringMap.singleton name (x, typ)
244-
| Some m -> StringMap.add name (x, typ) m))
245-
st.context.imports;
246-
x)
247-
, st )
229+
let register_import ?(allow_tail_call = true) ?(import_module = "env") ~name typ st =
230+
let x =
231+
try
232+
let x, typ' =
233+
StringMap.find name (StringMap.find import_module st.context.imports)
234+
in
235+
(*ZZZ error message*)
236+
assert (Poly.equal typ typ');
237+
x
238+
with Not_found ->
239+
let x = Var.fresh_n name in
240+
st.context.imports <-
241+
StringMap.update
242+
import_module
243+
(fun m ->
244+
Some
245+
(match m with
246+
| None -> StringMap.singleton name (x, typ)
247+
| Some m -> StringMap.add name (x, typ) m))
248+
st.context.imports;
249+
x
250+
in
251+
if not allow_tail_call then Var.Hashtbl.replace st.context.no_tail_call x ();
252+
x, st
248253

249254
let register_init_code code st =
250255
let st' = { var_count = 0; vars = Var.Map.empty; instrs = []; context = st.context } in
@@ -715,7 +720,7 @@ let function_body ~context ~param_names ~body =
715720
| Local (i, x, typ) -> local_types.(i) <- x, typ
716721
| Expr _ -> ())
717722
st.vars;
718-
let body = Tail_call.f body in
723+
let body = Tail_call.f ~no_tail_call:context.no_tail_call body in
719724
let param_count = List.length param_names in
720725
let locals =
721726
local_types

compiler/lib-wasm/code_generation.mli

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type context =
4242
; mutable globalized_variables : Code.Var.Set.t
4343
; value_type : Wasm_ast.value_type
4444
; mutable unit_name : string option
45+
; mutable no_tail_call : unit Code.Var.Hashtbl.t
4546
}
4647

4748
val make_context : value_type:Wasm_ast.value_type -> context
@@ -156,7 +157,11 @@ val register_type : string -> (unit -> type_def t) -> Wasm_ast.var t
156157
val heap_type_sub : Wasm_ast.heap_type -> Wasm_ast.heap_type -> bool t
157158

158159
val register_import :
159-
?import_module:string -> name:string -> Wasm_ast.import_desc -> Wasm_ast.var t
160+
?allow_tail_call:bool
161+
-> ?import_module:string
162+
-> name:string
163+
-> Wasm_ast.import_desc
164+
-> Wasm_ast.var t
160165

161166
val register_global :
162167
Wasm_ast.var

compiler/lib-wasm/gc_target.ml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,13 @@ module Math = struct
12971297
{ W.params = List.init ~len:n ~f:(fun _ : W.value_type -> F64); result = [ F64 ] }
12981298

12991299
let unary name x =
1300-
let* f = register_import ~import_module:"Math" ~name (Fun (float_func_type 1)) in
1300+
let* f =
1301+
register_import
1302+
~allow_tail_call:false
1303+
~import_module:"Math"
1304+
~name
1305+
(Fun (float_func_type 1))
1306+
in
13011307
let* x = x in
13021308
return (W.Call (f, [ x ]))
13031309

@@ -1340,7 +1346,13 @@ module Math = struct
13401346
let log10 f = unary "log10" f
13411347

13421348
let binary name x y =
1343-
let* f = register_import ~import_module:"Math" ~name (Fun (float_func_type 2)) in
1349+
let* f =
1350+
register_import
1351+
~allow_tail_call:false
1352+
~import_module:"Math"
1353+
~name
1354+
(Fun (float_func_type 2))
1355+
in
13441356
let* x = x in
13451357
let* y = y in
13461358
return (W.Call (f, [ x; y ]))

compiler/lib-wasm/tail_call.ml

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

27-
let rewrite_tail_call ~y i =
27+
let rewrite_tail_call ~no_tail_call ~y i =
2828
match i with
29-
| Wasm_ast.LocalSet (x, Call (symb, l)) when Code.Var.equal x y ->
29+
| Wasm_ast.LocalSet (x, Call (symb, l))
30+
when Code.Var.equal x y && not (Code.Var.Hashtbl.mem no_tail_call symb) ->
3031
Some (Wasm_ast.Return_call (symb, l))
3132
| LocalSet (x, Call_ref (ty, e, l)) when Code.Var.equal x y ->
3233
Some (Return_call_ref (ty, e, l))
3334
| _ -> None
3435

35-
let rec instruction ~tail i =
36+
let rec instruction ~no_tail_call ~tail i =
3637
match i with
37-
| Wasm_ast.Loop (ty, l) -> Wasm_ast.Loop (ty, instructions ~tail l)
38-
| Block (ty, l) -> Block (ty, instructions ~tail l)
39-
| If (ty, e, l1, l2) -> If (ty, e, instructions ~tail l1, instructions ~tail l2)
40-
| Return (Some (Call (symb, l))) -> Return_call (symb, l)
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)
40+
| If (ty, e, l1, l2) ->
41+
If (ty, e, instructions ~no_tail_call ~tail l1, instructions ~no_tail_call ~tail l2)
42+
| Return (Some (Call (symb, l))) when not (Code.Var.Hashtbl.mem no_tail_call symb) ->
43+
Return_call (symb, l)
4144
| Return (Some (Call_ref (ty, e, l))) -> Return_call_ref (ty, e, l)
42-
| Push (Call (symb, l)) when tail -> Return_call (symb, l)
45+
| Push (Call (symb, l)) when tail && not (Code.Var.Hashtbl.mem no_tail_call symb) ->
46+
Return_call (symb, l)
4347
| Push (Call_ref (ty, e, l)) when tail -> Return_call_ref (ty, e, l)
4448
| Push (Call_ref _) -> i
45-
| Drop (BlockExpr (typ, l)) -> Drop (BlockExpr (typ, instructions ~tail:false l))
49+
| Drop (BlockExpr (typ, l)) ->
50+
Drop (BlockExpr (typ, instructions ~no_tail_call ~tail:false l))
4651
| Drop _
4752
| LocalSet _
4853
| GlobalSet _
@@ -62,21 +67,28 @@ let rec instruction ~tail i =
6267
| Unreachable
6368
| Event _ -> i
6469

65-
and instructions ~tail l =
70+
and instructions ~no_tail_call ~tail l =
6671
match l with
6772
| [] -> []
68-
| [ i ] -> [ instruction ~tail i ]
69-
| i :: Nop :: rem -> instructions ~tail (i :: rem)
70-
| i :: i' :: Nop :: rem -> instructions ~tail (i :: i' :: rem)
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)
7176
| i :: i' :: (([] | [ Event _ ]) as event_opt) -> (
7277
(* There can be an event at the end of the function, which we
7378
should keep. *)
7479
match get_return ~tail i' with
75-
| None -> instruction ~tail:false i :: instruction ~tail i' :: event_opt
80+
| None ->
81+
instruction ~no_tail_call ~tail:false i
82+
:: instruction ~no_tail_call ~tail i'
83+
:: event_opt
7684
| Some y -> (
77-
match rewrite_tail_call ~y i with
78-
| None -> instruction ~tail:false i :: instruction ~tail i' :: event_opt
85+
match rewrite_tail_call ~no_tail_call ~y i with
86+
| None ->
87+
instruction ~no_tail_call ~tail:false i
88+
:: instruction ~no_tail_call ~tail i'
89+
:: event_opt
7990
| Some i'' -> i'' :: event_opt))
80-
| i :: rem -> instruction ~tail:false i :: instructions ~tail rem
91+
| i :: rem ->
92+
instruction ~no_tail_call ~tail:false i :: instructions ~no_tail_call ~tail rem
8193

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

compiler/lib-wasm/tail_call.mli

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@
1616
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1717
*)
1818

19-
val f : Wasm_ast.instruction list -> Wasm_ast.instruction list
19+
val f :
20+
no_tail_call:unit Code.Var.Hashtbl.t
21+
-> Wasm_ast.instruction list
22+
-> Wasm_ast.instruction list

0 commit comments

Comments
 (0)