Skip to content

Commit fdec717

Browse files
committed
Unboxed returned values
1 parent 2b256a5 commit fdec717

File tree

3 files changed

+110
-52
lines changed

3 files changed

+110
-52
lines changed

compiler/lib-wasm/generate.ml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,10 @@ module Generate (Target : Target_sig.S) = struct
11371137
args
11381138
params)
11391139
in
1140-
return (W.Call (g, args @ [ cl ]))
1140+
convert
1141+
~from:(Typing.return_type ctx.types g)
1142+
~into:(Typing.var_type ctx.types x)
1143+
(return (W.Call (g, args @ [ cl ])))
11411144
| None -> (
11421145
let funct = Var.fresh () in
11431146
let* closure = tee funct (return closure) in
@@ -1445,7 +1448,7 @@ module Generate (Target : Target_sig.S) = struct
14451448
then handler
14461449
else
14471450
let* () = handler in
1448-
instr (W.Return (Some (RefI31 (Const (I32 0l)))))
1451+
instr W.Unreachable
14491452
else body ~result_typ ~fall_through ~context
14501453

14511454
let wrap_with_handlers p pc ~result_typ ~fall_through ~context body =
@@ -1481,6 +1484,11 @@ module Generate (Target : Target_sig.S) = struct
14811484
((pc, _) as cont)
14821485
cloc
14831486
acc =
1487+
let return_type =
1488+
match name_opt with
1489+
| Some f -> Typing.return_type ctx.types f
1490+
| _ -> Typing.Top
1491+
in
14841492
let g = Structure.build_graph ctx.blocks pc in
14851493
let dom = Structure.dominator_tree g in
14861494
let rec translate_tree result_typ fall_through pc context =
@@ -1542,7 +1550,9 @@ module Generate (Target : Target_sig.S) = struct
15421550
match branch with
15431551
| Branch cont -> translate_branch result_typ fall_through pc cont context
15441552
| Return x -> (
1545-
let* e = load_and_box ctx x in
1553+
let* e =
1554+
convert ~from:(Typing.var_type ctx.types x) ~into:return_type (load x)
1555+
in
15461556
match fall_through with
15471557
| `Return -> instr (Push e)
15481558
| `Block _ | `Catch | `Skip -> instr (Return (Some e)))
@@ -1663,7 +1673,7 @@ module Generate (Target : Target_sig.S) = struct
16631673
wrap_with_handlers
16641674
p
16651675
pc
1666-
~result_typ:[ Type.value ]
1676+
~result_typ:[ Option.value ~default:Type.value (unboxed_type return_type) ]
16671677
~fall_through:`Return
16681678
~context:[]
16691679
(fun ~result_typ ~fall_through ~context ->
@@ -1698,7 +1708,7 @@ module Generate (Target : Target_sig.S) = struct
16981708
(unboxed_type (Typing.var_type ctx.types x)))
16991709
params
17001710
@ [ Type.value ]
1701-
; result = [ Type.value ]
1711+
; result = [ Option.value ~default:Type.value (unboxed_type return_type) ]
17021712
}
17031713
else Type.func_type (param_count - 1))
17041714
; param_names

compiler/lib-wasm/typing.ml

Lines changed: 93 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ let can_unbox_parameters fun_info f =
1515
have the same signature. *)
1616
Call_graph_analysis.direct_calls_only fun_info f
1717

18+
let can_unbox_return_value fun_info f =
19+
(* Unboxing return values can unoptimize a tail call. Since we are
20+
never unboxing then reboxing a value, this can only happen once
21+
in a sequence of tail calls, so this is not an issue. *)
22+
Call_graph_analysis.direct_calls_only fun_info f
23+
1824
module Integer = struct
1925
type kind =
2026
| Ref
@@ -429,10 +435,12 @@ let propagate st approx x : Domain.t =
429435
match st.global_flow_state.defs.(Var.idx g) with
430436
| Expr (Closure (params, _, _))
431437
when List.length args = List.length params ->
432-
Domain.box
433-
(Domain.join_set
434-
(fun y -> Var.Tbl.get approx y)
435-
(Var.Map.find g st.global_flow_state.return_values))
438+
let res =
439+
Domain.join_set
440+
(fun y -> Var.Tbl.get approx y)
441+
(Var.Map.find g st.global_flow_state.return_values)
442+
in
443+
if can_unbox_return_value st.fun_info g then res else Domain.box res
436444
| Expr (Closure (_, _, _)) ->
437445
(* The function is partially applied or over applied *)
438446
Top
@@ -596,52 +604,73 @@ let box_numbers p st types =
596604
match typ with
597605
| Number (_, Unboxed) | Top -> (
598606
match st.global_flow_state.defs.(Var.idx y) with
607+
| Expr (Apply { f; _ }) -> (
608+
match Global_flow.get_unique_closure st.global_flow_info f with
609+
| None -> ()
610+
| Some (g, _) ->
611+
if can_unbox_return_value st.fun_info g
612+
then
613+
let s = Var.Map.find g st.global_flow_info.info_return_vals in
614+
Var.Set.iter box s)
599615
| Expr _ -> ()
600616
| Phi { known; _ } -> Var.Set.iter box known)
601617
| Number (_, Boxed) | Int _ | Tuple _ | Bot -> ())
602618
in
603-
Addr.Map.iter
604-
(fun _ b ->
605-
List.iter
606-
~f:(fun i ->
607-
match i with
608-
| Let (_, e) -> (
609-
match e with
610-
| Apply { f; args; _ } ->
611-
if
612-
match Global_flow.get_unique_closure st.global_flow_info f with
613-
| None -> true
614-
| Some (g, _) ->
615-
not (Call_graph_analysis.direct_calls_only st.fun_info g)
616-
then List.iter ~f:box args
617-
| Block (tag, lst, _, _) -> if tag <> 254 then Array.iter ~f:box lst
618-
| Prim (Extern s, args) ->
619-
if not (String.Hashtbl.mem primitives_with_unboxed_parameters s)
620-
then
621-
List.iter
622-
~f:(fun a ->
623-
match a with
624-
| Pv y -> box y
625-
| Pc _ -> ())
626-
args
627-
| Prim ((Eq | Neq), args) ->
628-
List.iter
629-
~f:(fun a ->
630-
match a with
631-
| Pv y -> box y
632-
| Pc _ -> ())
633-
args
634-
| Prim ((Vectlength | Array_get | Not | IsInt | Lt | Le | Ult), _)
635-
| Field _ | Closure _ | Constant _ | Special _ -> ())
636-
| Set_field (_, _, Non_float, y) | Array_set (_, _, y) -> box y
637-
| Assign _ | Offset_ref _ | Set_field (_, _, Float, _) | Event _ -> ())
638-
b.body;
639-
match b.branch with
640-
| Return y -> box y
641-
| Raise _ | Stop | Branch _ | Cond _ | Switch _ | Pushtrap _ | Poptrap _ -> ())
642-
p.blocks
643-
644-
type t = { types : typ Var.Tbl.t }
619+
Code.fold_closures
620+
p
621+
(fun name_opt _ (pc, _) _ () ->
622+
traverse
623+
{ fold = Code.fold_children }
624+
(fun pc () ->
625+
let b = Addr.Map.find pc p.blocks in
626+
List.iter
627+
~f:(fun i ->
628+
match i with
629+
| Let (_, e) -> (
630+
match e with
631+
| Apply { f; args; _ } ->
632+
if
633+
match Global_flow.get_unique_closure st.global_flow_info f with
634+
| None -> true
635+
| Some (g, _) -> not (can_unbox_parameters st.fun_info g)
636+
then List.iter ~f:box args
637+
| Block (tag, lst, _, _) -> if tag <> 254 then Array.iter ~f:box lst
638+
| Prim (Extern s, args) ->
639+
if not (String.Hashtbl.mem primitives_with_unboxed_parameters s)
640+
then
641+
List.iter
642+
~f:(fun a ->
643+
match a with
644+
| Pv y -> box y
645+
| Pc _ -> ())
646+
args
647+
| Prim ((Eq | Neq), args) ->
648+
List.iter
649+
~f:(fun a ->
650+
match a with
651+
| Pv y -> box y
652+
| Pc _ -> ())
653+
args
654+
| Prim ((Vectlength | Array_get | Not | IsInt | Lt | Le | Ult), _)
655+
| Field _ | Closure _ | Constant _ | Special _ -> ())
656+
| Set_field (_, _, Non_float, y) | Array_set (_, _, y) -> box y
657+
| Assign _ | Offset_ref _ | Set_field (_, _, Float, _) | Event _ -> ())
658+
b.body;
659+
match b.branch with
660+
| Return y ->
661+
Option.iter
662+
~f:(fun g -> if not (can_unbox_return_value st.fun_info g) then box y)
663+
name_opt
664+
| Raise _ | Stop | Branch _ | Cond _ | Switch _ | Pushtrap _ | Poptrap _ -> ())
665+
pc
666+
p.blocks
667+
())
668+
()
669+
670+
type t =
671+
{ types : typ Var.Tbl.t
672+
; return_types : typ Var.Hashtbl.t
673+
}
645674

646675
let f ~global_flow_state ~global_flow_info ~fun_info ~deadcode_sentinal p =
647676
let t = Timer.make () in
@@ -670,6 +699,23 @@ let f ~global_flow_state ~global_flow_info ~fun_info ~deadcode_sentinal p =
670699
| Instr (Let (x, _)) -> Format.asprintf "{%a}" Domain.print (Var.Tbl.get types x)
671700
| _ -> "")
672701
p);
673-
{ types }
702+
let return_types = Var.Hashtbl.create 128 in
703+
Code.fold_closures
704+
p
705+
(fun name_opt _ _ _ () ->
706+
Option.iter
707+
~f:(fun f ->
708+
if can_unbox_return_value fun_info f
709+
then
710+
let s = Var.Map.find f global_flow_info.info_return_vals in
711+
Var.Hashtbl.replace
712+
return_types
713+
f
714+
(Var.Set.fold (fun x t -> Domain.join (Var.Tbl.get types x) t) s Bot))
715+
name_opt)
716+
();
717+
{ types; return_types }
674718

675719
let var_type info x = Var.Tbl.get info.types x
720+
721+
let return_type info f = try Var.Hashtbl.find info.return_types f with Not_found -> Top

compiler/lib-wasm/typing.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ type t
3030

3131
val var_type : t -> Code.Var.t -> typ
3232

33+
val return_type : t -> Code.Var.t -> typ
34+
3335
val f :
3436
global_flow_state:Global_flow.state
3537
-> global_flow_info:Global_flow.info

0 commit comments

Comments
 (0)