Skip to content

Commit 2b903c4

Browse files
committed
No tail-calls
1 parent e8cea31 commit 2b903c4

File tree

1 file changed

+62
-23
lines changed

1 file changed

+62
-23
lines changed

compiler/lib-wasm/call_graph_analysis.ml

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,35 @@ type t = { unambiguous_non_escaping : unit Var.Hashtbl.t }
4242
let 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

103151
let 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-
129165
let 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

Comments
 (0)