Skip to content

Commit a34bd2f

Browse files
committed
Inline functions recursively
When inlining a function with "interesting parameters", only inline the corresponding arguments in the function body.
1 parent 7119cc4 commit a34bd2f

File tree

1 file changed

+89
-36
lines changed

1 file changed

+89
-36
lines changed

compiler/lib/inline.ml

Lines changed: 89 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -371,28 +371,31 @@ let rec small_function ~context info args =
371371
&& body_size ~context info <= 15
372372
&& closure_count ~context info = 0
373373
&& (not (List.is_empty args))
374-
&&
374+
&& not (Var.Map.is_empty (relevant_arguments ~context info args))
375+
376+
and relevant_arguments ~context info args =
375377
let relevant_params = interesting_parameters ~context info in
376-
try
377-
List.iter2 args info.params ~f:(fun arg param ->
378+
List.fold_left2
379+
args
380+
info.params
381+
~f:(fun m arg param ->
382+
if
383+
Var.Map.mem arg context.env
384+
&& List.exists ~f:(fun (p, _) -> Var.equal p param) relevant_params
385+
then
386+
let info' = Var.Map.find arg context.env in
387+
let _, arity = List.find ~f:(fun (p, _) -> Var.equal p param) relevant_params in
378388
if
379-
Var.Map.mem arg context.env
380-
&& List.exists ~f:(fun (p, _) -> Var.equal p param) relevant_params
381-
then
382-
let info' = Var.Map.find arg context.env in
383-
let _, arity = List.find ~f:(fun (p, _) -> Var.equal p param) relevant_params in
384-
if
385-
List.compare_length_with info'.params ~len:arity = 0
386-
&& should_inline
387-
~context:
388-
{ context with
389-
in_loop = context.in_loop || contains_loop ~context info
390-
}
391-
info'
392-
[]
393-
then raise Exit);
394-
false
395-
with Exit -> true
389+
List.compare_length_with info'.params ~len:arity = 0
390+
&& should_inline
391+
~context:
392+
{ context with in_loop = context.in_loop || contains_loop ~context info }
393+
info'
394+
[]
395+
then Var.Map.add param arg m
396+
else m
397+
else m)
398+
~init:Var.Map.empty
396399

397400
and should_inline ~context info args =
398401
(* Typically, in JavaScript implementations, a closure contains a
@@ -521,7 +524,7 @@ let rewrite_closure blocks cont_pc clos_pc =
521524
blocks
522525
blocks
523526

524-
let inline_function p rem branch x params cont args =
527+
let rewrite_inlined_function p rem branch x params cont args =
525528
let blocks, cont_pc, free_pc =
526529
match rem, branch with
527530
| [], Return y when Var.equal x y ->
@@ -546,27 +549,77 @@ let inline_function p rem branch x params cont args =
546549
in
547550
[], (Branch (fresh_addr, args), { p with blocks; free_pc })
548551

552+
let rec inline_recursively ~context ~info p params (pc, _) args =
553+
let relevant_args = relevant_arguments ~context info args in
554+
if Var.Map.is_empty relevant_args
555+
then p
556+
else
557+
let subst =
558+
List.fold_left2
559+
params
560+
info.params
561+
~f:(fun m param param' ->
562+
if Var.Map.mem param' relevant_args
563+
then Var.Map.add param (Var.Map.find param' relevant_args) m
564+
else m)
565+
~init:Var.Map.empty
566+
in
567+
Code.traverse
568+
{ fold = Code.fold_children }
569+
(fun pc p ->
570+
let block = Addr.Map.find pc p.blocks in
571+
let body, (branch, p) =
572+
List.fold_right
573+
~f:(fun i (rem, state) ->
574+
match i with
575+
| Let (x, Apply { f; args; _ }) when Var.Map.mem f subst ->
576+
(* The [exact] field might not be accurate since it
577+
considers all possible values of [f], before the
578+
current function is inlined, not just the one
579+
called after inlining. We have checked in
580+
[relevant_arguments] that the call was exact.
581+
We have also checked that it made sense to inline
582+
this call. In particular, this function is
583+
applied only once. *)
584+
let f = Var.Map.find f subst in
585+
inline_function ~context i x f args rem state
586+
| _ -> i :: rem, state)
587+
~init:([], (block.branch, p))
588+
block.body
589+
in
590+
{ p with blocks = Addr.Map.add pc { block with body; branch } p.blocks })
591+
pc
592+
p.blocks
593+
p
594+
595+
and inline_function ~context i x f args rem state =
596+
let info = Var.Map.find f context.env in
597+
let { params; cont; _ } = info in
598+
trace_inlining ~context info x args;
599+
if should_inline ~context info args
600+
then (
601+
let branch, p = state in
602+
incr context.inline_count;
603+
if closure_count ~context info > 0 then context.has_closures := true;
604+
context.live_vars.(Var.idx f) <- context.live_vars.(Var.idx f) - 1;
605+
let p, params, cont =
606+
if context.live_vars.(Var.idx f) > 0
607+
then
608+
let p, _, params, cont = Duplicate.closure p ~f ~params ~cont in
609+
p, params, cont
610+
else p, params, cont
611+
in
612+
let p = inline_recursively ~context ~info p params cont args in
613+
rewrite_inlined_function p rem branch x params cont args)
614+
else i :: rem, state
615+
549616
let inline_in_block ~context pc block p =
550617
let body, (branch, p) =
551618
List.fold_right
552619
~f:(fun i (rem, state) ->
553620
match i with
554621
| Let (x, Apply { f; args; exact = true; _ }) when Var.Map.mem f context.env ->
555-
let info = Var.Map.find f context.env in
556-
let { params; cont; _ } = info in
557-
trace_inlining ~context info x args;
558-
if should_inline ~context info args
559-
then (
560-
let branch, p = state in
561-
incr context.inline_count;
562-
if closure_count ~context info > 0 then context.has_closures := true;
563-
context.live_vars.(Var.idx f) <- context.live_vars.(Var.idx f) - 1;
564-
if context.live_vars.(Var.idx f) > 0
565-
then
566-
let p, _, params, cont = Duplicate.closure p ~f ~params ~cont in
567-
inline_function p rem branch x params cont args
568-
else inline_function p rem branch x params cont args)
569-
else i :: rem, state
622+
inline_function ~context i x f args rem state
570623
| _ -> i :: rem, state)
571624
~init:([], (block.branch, p))
572625
block.body

0 commit comments

Comments
 (0)