@@ -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+
1824module 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
646675let 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
675719let 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
0 commit comments