@@ -42,10 +42,35 @@ type t = { unambiguous_non_escaping : unit Var.Hashtbl.t }
4242let direct_calls_only info f =
4343 Config.Flag. optcall () && Var.Hashtbl. mem info.unambiguous_non_escaping f
4444
45- let call_graph p info call_info =
45+ let callee_if_known info call_info exact f =
46+ match get_approx info f with
47+ | Top -> None
48+ | Values { known; others } ->
49+ if
50+ exact
51+ && (not others)
52+ && Var.Set. for_all (fun f -> direct_calls_only call_info f) known
53+ then Some (Var.Set. choose known)
54+ else None
55+
56+ let propagate nodes edges eligible =
57+ let rec propagate n =
58+ List. iter
59+ ~f: (fun n' ->
60+ if (not (Var.Hashtbl. mem nodes n')) && eligible n'
61+ then (
62+ Var.Hashtbl. add nodes n' () ;
63+ propagate n'))
64+ (Var.Hashtbl. find_all edges n)
65+ in
66+ Var.Hashtbl. iter (fun n () -> propagate n) nodes
67+
68+ let call_graph p info call_info eligible =
4669 let under_handler = Var.Hashtbl. create 16 in
4770 let callees = Var.Hashtbl. create 16 in
4871 let callers = Var.Hashtbl. create 16 in
72+ let has_tail_calls = Var.Hashtbl. create 16 in
73+ let tail_callers = Var.Hashtbl. create 16 in
4974 let rec traverse name_opt pc visited nesting =
5075 if not (Addr.Set. mem pc visited)
5176 then (
@@ -80,6 +105,28 @@ let call_graph p info call_info =
80105 name_opt)
81106 | Let (_, (Closure _ | Prim _ | Block _ | Constant _ | Field _ | Special _))
82107 | Event _ | Assign _ | Set_field _ | Offset_ref _ | Array_set _ -> () );
108+ if nesting = 0
109+ then
110+ Option. iter
111+ ~f: (fun f ->
112+ Code. traverse
113+ { fold = Code. fold_children }
114+ (fun pc () ->
115+ let block = Addr.Map. find pc p.blocks in
116+ match block.branch with
117+ | Return x -> (
118+ match last_instr block.body with
119+ | Some (Let (x', Apply { f = g; exact; _ })) when Code.Var. equal x x'
120+ -> (
121+ match callee_if_known info call_info exact g with
122+ | None -> Var.Hashtbl. replace has_tail_calls f ()
123+ | Some g -> Var.Hashtbl. add tail_callers g f)
124+ | _ -> () )
125+ | _ -> () )
126+ pc
127+ p.blocks
128+ () )
129+ name_opt;
83130 Code. fold_children
84131 p.blocks
85132 pc
@@ -98,7 +145,8 @@ let call_graph p info call_info =
98145 p
99146 (fun name_opt _ (pc , _ ) _ () -> ignore (traverse name_opt pc Addr.Set. empty 0 ))
100147 () ;
101- under_handler, callers, callees
148+ propagate has_tail_calls tail_callers eligible;
149+ under_handler, callers, callees, has_tail_calls
102150
103151let function_do_raise p pc =
104152 Code. traverse
@@ -114,36 +162,28 @@ let function_do_raise p pc =
114162 p.blocks
115163 false
116164
117- let propagate nodes edges eligible =
118- let rec propagate n =
119- List. iter
120- ~f: (fun n' ->
121- if (not (Var.Hashtbl. mem nodes n')) && eligible n'
122- then (
123- Var.Hashtbl. add nodes n' () ;
124- propagate n'))
125- (Var.Hashtbl. find_all edges n)
126- in
127- Var.Hashtbl. iter (fun n () -> propagate n) nodes
128-
129165let raising_functions p info call_info eligible =
130- let under_handler, callers, callees = call_graph p info call_info in
131- propagate under_handler callees eligible;
166+ let under_handler, callers, callees, has_tail_calls =
167+ call_graph p info call_info eligible
168+ in
169+ propagate under_handler callees (fun f ->
170+ eligible f && not (Var.Hashtbl. mem has_tail_calls f));
132171 let h = Var.Hashtbl. create 16 in
172+ let eligible f =
173+ eligible f
174+ && Var.Hashtbl. mem under_handler f
175+ && not (Var.Hashtbl. mem has_tail_calls f)
176+ in
133177 Code. fold_closures
134178 p
135179 (fun name_opt _params (pc , _ ) _ () ->
136180 match name_opt with
137181 | None -> ()
138182 | Some name ->
139- if
140- direct_calls_only call_info name
141- && eligible name
142- && function_do_raise p pc
143- && Var.Hashtbl. mem under_handler name
183+ if direct_calls_only call_info name && eligible name && function_do_raise p pc
144184 then Var.Hashtbl. add h name () )
145185 () ;
146- propagate h callers ( fun f -> eligible f && Var.Hashtbl. mem under_handler f) ;
186+ propagate h callers eligible;
147187 if false
148188 then
149189 Var.Hashtbl. iter
@@ -180,5 +220,4 @@ let f p info =
180220
181221(*
182222- Optimize tail-calls
183- - Cannot change calling convention if the function has tail-calls
184223*)
0 commit comments