Skip to content

Commit 197e32c

Browse files
committed
Optimize calling a known function
1 parent 0ea2d6f commit 197e32c

File tree

3 files changed

+82
-37
lines changed

3 files changed

+82
-37
lines changed

compiler/lib-wasm/generate.ml

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ module Generate (Target : Target_sig.S) = struct
3636
{ live : int array
3737
; in_cps : Effects.in_cps
3838
; deadcode_sentinal : Var.t
39+
; global_flow_info : Global_flow.info
3940
; types : Typing.typ Var.Tbl.t
4041
; blocks : block Addr.Map.t
4142
; closures : Closure_conversion.closure Var.Map.t
@@ -784,44 +785,49 @@ module Generate (Target : Target_sig.S) = struct
784785

785786
let rec translate_expr ctx context x e =
786787
match e with
787-
| Apply { f; args; exact }
788-
when exact || List.length args = if Var.Set.mem x ctx.in_cps then 2 else 1 ->
789-
let rec loop acc l =
790-
match l with
791-
| [] -> (
792-
let arity = List.length args in
793-
let funct = Var.fresh () in
794-
let* closure = tee funct (load f) in
795-
let* ty, funct =
796-
Memory.load_function_pointer
797-
~cps:(Var.Set.mem x ctx.in_cps)
798-
~arity
799-
(load funct)
800-
in
801-
let* b = is_closure f in
802-
if b
803-
then return (W.Call (f, List.rev (closure :: acc)))
804-
else
805-
match funct with
806-
| W.RefFunc g ->
807-
(* Functions with constant closures ignore their
788+
| Apply { f; args; exact; _ } ->
789+
if exact || List.length args = if Var.Set.mem x ctx.in_cps then 2 else 1
790+
then
791+
let rec loop acc l =
792+
match l with
793+
| [] -> (
794+
let arity = List.length args in
795+
let funct = Var.fresh () in
796+
let* closure = tee funct (load f) in
797+
let* ty, funct =
798+
Memory.load_function_pointer
799+
~cps:(Var.Set.mem x ctx.in_cps)
800+
~arity
801+
(load funct)
802+
in
803+
let* b = is_closure f in
804+
if b
805+
then return (W.Call (f, List.rev (closure :: acc)))
806+
else
807+
match funct with
808+
| W.RefFunc g ->
809+
(* Functions with constant closures ignore their
808810
environment. In case of partial application, we
809811
still need the closure. *)
810-
let* cl = if exact then Value.unit else return closure in
811-
return (W.Call (g, List.rev (cl :: acc)))
812-
| _ -> return (W.Call_ref (ty, funct, List.rev (closure :: acc))))
813-
| x :: r ->
814-
let* x = load_and_box ctx x in
815-
loop (x :: acc) r
816-
in
817-
loop [] args
818-
| Apply { f; args; _ } ->
819-
let* apply =
820-
need_apply_fun ~cps:(Var.Set.mem x ctx.in_cps) ~arity:(List.length args)
821-
in
822-
let* args = expression_list (fun x -> load_and_box ctx x) args in
823-
let* closure = load f in
824-
return (W.Call (apply, args @ [ closure ]))
812+
let* cl = if exact then Value.unit else return closure in
813+
return (W.Call (g, List.rev (cl :: acc)))
814+
| _ -> (
815+
match Global_flow.get_unique_closure ctx.global_flow_info f with
816+
| Some g -> return (W.Call (g, List.rev (closure :: acc)))
817+
| None -> return (W.Call_ref (ty, funct, List.rev (closure :: acc)))
818+
))
819+
| x :: r ->
820+
let* x = load_and_box ctx x in
821+
loop (x :: acc) r
822+
in
823+
loop [] args
824+
else
825+
let* apply =
826+
need_apply_fun ~cps:(Var.Set.mem x ctx.in_cps) ~arity:(List.length args)
827+
in
828+
let* args = expression_list (fun x -> load_and_box ctx x) args in
829+
let* closure = load f in
830+
return (W.Call (apply, args @ [ closure ]))
825831
| Block (tag, a, _, _) ->
826832
Memory.allocate
827833
~deadcode_sentinal:ctx.deadcode_sentinal
@@ -1390,6 +1396,7 @@ module Generate (Target : Target_sig.S) = struct
13901396
~warn_on_unhandled_effect
13911397
*)
13921398
~deadcode_sentinal
1399+
~global_flow_info
13931400
~types =
13941401
global_context.unit_name <- unit_name;
13951402
let p, closures = Closure_conversion.f p in
@@ -1400,6 +1407,7 @@ module Generate (Target : Target_sig.S) = struct
14001407
{ live = live_vars
14011408
; in_cps
14021409
; deadcode_sentinal
1410+
; global_flow_info
14031411
; types
14041412
; blocks = p.blocks
14051413
; closures
@@ -1512,7 +1520,17 @@ let f ~context ~unit_name p ~live_vars ~in_cps ~deadcode_sentinal ~global_flow_d
15121520
let types = Typing.f ~state ~info ~deadcode_sentinal p in
15131521
let t = Timer.make () in
15141522
let p = fix_switch_branches p in
1515-
let res = G.f ~context ~unit_name ~live_vars ~in_cps ~deadcode_sentinal ~types p in
1523+
let res =
1524+
G.f
1525+
~context
1526+
~unit_name
1527+
~live_vars
1528+
~in_cps
1529+
~deadcode_sentinal
1530+
~global_flow_info:info
1531+
~types
1532+
p
1533+
in
15161534
if times () then Format.eprintf " code gen.: %a@." Timer.print t;
15171535
res
15181536

compiler/lib/global_flow.ml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,31 @@ let exact_call info f n =
805805
| Expr _ | Phi _ -> assert false)
806806
known
807807

808+
let get_unique_closure info f =
809+
(* The specialize pass can create knew functions *)
810+
if Var.idx f >= Var.Tbl.length info.info_approximation
811+
then None
812+
else
813+
match Var.Tbl.get info.info_approximation f with
814+
| Top | Values { others = true; _ } -> None
815+
| Values { known; others = false } -> (
816+
match
817+
Var.Set.fold
818+
(fun g acc ->
819+
match info.info_defs.(Var.idx g) with
820+
| Expr (Closure _) -> (
821+
match acc with
822+
| None -> Some (Some g)
823+
| Some (Some _) -> Some None
824+
| Some None -> acc)
825+
| Expr (Block _) -> acc
826+
| Expr _ | Phi _ -> assert false)
827+
known
828+
None
829+
with
830+
| None -> None
831+
| Some kind -> kind)
832+
808833
let function_arity info f =
809834
match Var.Tbl.get info.info_approximation f with
810835
| Top | Values { others = true; _ } -> None

compiler/lib/global_flow.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,6 @@ val f : fast:bool -> Code.program -> state * info
8282

8383
val exact_call : info -> Var.t -> int -> bool
8484

85+
val get_unique_closure : info -> Var.t -> Var.t option
86+
8587
val function_arity : info -> Var.t -> int option

0 commit comments

Comments
 (0)