@@ -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
397400and 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+
549616let 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