Skip to content

Commit c6f9616

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

File tree

1 file changed

+81
-36
lines changed

1 file changed

+81
-36
lines changed

compiler/lib/inline.ml

Lines changed: 81 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,69 @@ 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+
let f = Var.Map.find f subst in
577+
inline_function ~context i x f args rem state
578+
| _ -> i :: rem, state)
579+
~init:([], (block.branch, p))
580+
block.body
581+
in
582+
{ p with blocks = Addr.Map.add pc { block with body; branch } p.blocks })
583+
pc
584+
p.blocks
585+
p
586+
587+
and inline_function ~context i x f args rem state =
588+
let info = Var.Map.find f context.env in
589+
let { params; cont; _ } = info in
590+
trace_inlining ~context info x args;
591+
if should_inline ~context info args
592+
then (
593+
let branch, p = state in
594+
incr context.inline_count;
595+
if closure_count ~context info > 0 then context.has_closures := true;
596+
context.live_vars.(Var.idx f) <- context.live_vars.(Var.idx f) - 1;
597+
let p, params, cont =
598+
if context.live_vars.(Var.idx f) > 0
599+
then
600+
let p, _, params, cont = Duplicate.closure p ~f ~params ~cont in
601+
p, params, cont
602+
else p, params, cont
603+
in
604+
let p = inline_recursively ~context ~info p params cont args in
605+
rewrite_inlined_function p rem branch x params cont args)
606+
else i :: rem, state
607+
549608
let inline_in_block ~context pc block p =
550609
let body, (branch, p) =
551610
List.fold_right
552611
~f:(fun i (rem, state) ->
553612
match i with
554613
| 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
614+
inline_function ~context i x f args rem state
570615
| _ -> i :: rem, state)
571616
~init:([], (block.branch, p))
572617
block.body

0 commit comments

Comments
 (0)