@@ -336,12 +336,15 @@ let allocate_closure ~st ~params ~body ~branch =
336336 let name = Var. fresh () in
337337 [ Let (name, Closure (params, (pc, [] ))) ], name
338338
339- let tail_call ~st ?(instrs = [] ) ~exact ~in_cps ~check ~f args =
340- assert (exact || check);
339+ let tail_call ~st ?(instrs = [] ) ~kind ~in_cps ~check ~f args =
340+ assert (
341+ match kind with
342+ | Generic -> check
343+ | Exact | Known _ -> true );
341344 let ret = Var. fresh () in
342345 if check then st.trampolined_calls := Var.Set. add ret ! (st.trampolined_calls);
343346 if in_cps then st.in_cps := Var.Set. add ret ! (st.in_cps);
344- instrs @ [ Let (ret, Apply { f; args; exact }) ], Return ret
347+ instrs @ [ Let (ret, Apply { f; args; kind }) ], Return ret
345348
346349let cps_branch ~st ~src (pc , args ) =
347350 match Addr.Set. mem pc st.blocks_to_transform with
@@ -359,14 +362,8 @@ let cps_branch ~st ~src (pc, args) =
359362 (* We check the stack depth only for backward edges (so, at
360363 least once per loop iteration) *)
361364 let check = Hashtbl. find st.block_order src > = Hashtbl. find st.block_order pc in
362- tail_call
363- ~st
364- ~instrs
365- ~exact: true
366- ~in_cps: false
367- ~check
368- ~f: (closure_of_pc ~st pc)
369- args
365+ let f = closure_of_pc ~st pc in
366+ tail_call ~st ~instrs ~kind: (Known f) ~in_cps: false ~check ~f args
370367
371368let cps_jump_cont ~st ~src ((pc , _ ) as cont ) =
372369 match Addr.Set. mem pc st.blocks_to_transform with
@@ -433,7 +430,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
433430 (* If the number of successive 'returns' is unbounded in CPS, it
434431 means that we have an unbounded of calls in direct style
435432 (even with tail call optimization) *)
436- tail_call ~st ~exact: true ~in_cps: false ~check: false ~f: k [ x ]
433+ tail_call ~st ~kind: Exact ~in_cps: false ~check: false ~f: k [ x ]
437434 | Raise (x , rmode ) -> (
438435 assert (List. is_empty alloc_jump_closures);
439436 match Hashtbl. find_opt st.matching_exn_handler pc with
@@ -468,7 +465,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
468465 tail_call
469466 ~st
470467 ~instrs: (Let (exn_handler, Prim (Extern " caml_pop_trap" , [] )) :: instrs)
471- ~exact: true
468+ ~kind: Exact
472469 ~in_cps: false
473470 ~check: false
474471 ~f: exn_handler
@@ -522,6 +519,14 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
522519 @ (Let (exn_handler, Prim (Extern " caml_pop_trap" , [] )) :: body)
523520 , branch ))
524521
522+ let refine_kind k k' =
523+ match k, k' with
524+ | Known _ , _ -> k
525+ | _ , Known _ -> k'
526+ | Exact , _ -> k
527+ | _ , Exact -> k'
528+ | Generic , Generic -> k
529+
525530let rewrite_instr ~st (instr : instr ) : instr =
526531 match instr with
527532 | Let (x , Closure (_ , (pc , _ ))) when Var.Set. mem x st.cps_needed ->
@@ -542,34 +547,37 @@ let rewrite_instr ~st (instr : instr) : instr =
542547 (Extern " caml_alloc_dummy_function" , [ size; Pc (Int (Targetint. succ a)) ])
543548 )
544549 | _ -> assert false )
545- | Let (x , Apply { f; args; exact } ) when not (Var.Set. mem x st.cps_needed) ->
546- if double_translate ()
547- then
548- let exact =
549- (* If this function is unknown to the global flow analysis, then it was
550- introduced by the lambda lifting and we don't have exactness info any more. *)
551- exact
552- || Var. idx f < Var.Tbl. length st.flow_info.info_approximation
553- && Global_flow. exact_call st.flow_info f (List. length args)
554- in
555- Let (x, Apply { f; args; exact })
556- else (
557- (* At the moment, we turn into CPS any function not called with
558- the right number of parameter *)
559- assert (Global_flow. exact_call st.flow_info f (List. length args));
560- Let (x, Apply { f; args; exact = true }))
550+ | Let (x , Apply { f; args; kind } ) when not (Var.Set. mem x st.cps_needed) ->
551+ let kind' =
552+ (* If this function is unknown to the global flow analysis,
553+ then it was introduced by the lambda lifting before double
554+ translation and we don't have exactness info any more. *)
555+ if Var. idx f > = Var.Tbl. length st.flow_info.info_approximation
556+ then Generic
557+ else Global_flow. apply_kind st.flow_info f (List. length args)
558+ in
559+ assert (
560+ double_translate ()
561+ ||
562+ (* We turn into CPS any function not called with the right
563+ number of arguments *)
564+ match kind' with
565+ | Generic -> false
566+ | Exact | Known _ -> true );
567+ Let (x, Apply { f; args; kind = refine_kind kind kind' })
561568 | Let (_ , e ) when effect_primitive_or_application e ->
562569 (* For the CPS target, applications of CPS functions and effect primitives require
563570 more work (allocating a continuation and/or modifying end-of-block branches) and
564571 are handled in a specialized function. *)
565572 assert false
566573 | _ -> instr
567574
568- let call_exact flow_info (f : Var.t ) nargs : bool =
575+ let call_kind flow_info (f : Var.t ) nargs =
569576 (* If [f] is unknown to the global flow analysis, then it was introduced by
570577 the lambda lifting and we don't have exactness about it. *)
571- Var. idx f < Var.Tbl. length flow_info.Global_flow. info_approximation
572- && Global_flow. exact_call flow_info f nargs
578+ if Var. idx f > = Var.Tbl. length flow_info.Global_flow. info_approximation
579+ then Generic
580+ else Global_flow. apply_kind flow_info f nargs
573581
574582let cps_instr ~st (instr : instr ) : instr list =
575583 match instr with
@@ -578,7 +586,7 @@ let cps_instr ~st (instr : instr) : instr list =
578586 Otherwise, the runtime primitive is used. *)
579587 let unit = Var. fresh_n " unit" in
580588 [ Let (unit , Constant (Int Targetint. zero))
581- ; Let (x, Apply { exact = call_exact st.flow_info f 1 ; f; args = [ unit ] })
589+ ; Let (x, Apply { kind = call_kind st.flow_info f 1 ; f; args = [ unit ] })
582590 ]
583591 | _ -> [ rewrite_instr ~st instr ]
584592
@@ -653,11 +661,11 @@ let cps_block ~st ~k ~orig_pc block =
653661 [ Let (x, e) ], Return x)
654662 in
655663 match e with
656- | Apply { f; args; exact } when Var.Set. mem x st.cps_needed ->
664+ | Apply { f; args; kind } when Var.Set. mem x st.cps_needed ->
657665 Some
658666 (fun ~k ->
659- let exact = exact || call_exact st.flow_info f (List. length args) in
660- tail_call ~st ~exact ~in_cps: true ~check: true ~f (args @ [ k ]))
667+ let kind = refine_kind kind (call_kind st.flow_info f (List. length args) ) in
668+ tail_call ~st ~kind ~in_cps: true ~check: true ~f (args @ [ k ]))
661669 | Prim (Extern "%resume" , [ Pv stack ; Pv f ; Pv arg ; tail ]) ->
662670 Some
663671 (fun ~k ->
@@ -666,7 +674,7 @@ let cps_block ~st ~k ~orig_pc block =
666674 ~st
667675 ~instrs:
668676 [ Let (k', Prim (Extern " caml_resume_stack" , [ Pv stack; tail; Pv k ])) ]
669- ~exact: (call_exact st.flow_info f 1 )
677+ ~kind: (call_kind st.flow_info f 1 )
670678 ~in_cps: true
671679 ~check: true
672680 ~f
@@ -754,8 +762,8 @@ let rewrite_direct_block ~st ~cps_needed ~closure_info ~pc block =
754762 (* We just need to call [f] in direct style. *)
755763 let unit = Var. fresh_n " unit" in
756764 let unit_val = Int Targetint. zero in
757- let exact = call_exact st.flow_info f 1 in
758- [ Let (unit , Constant unit_val); Let (x, Apply { exact ; f; args = [ unit ] }) ]
765+ let kind = call_kind st.flow_info f 1 in
766+ [ Let (unit , Constant unit_val); Let (x, Apply { kind ; f; args = [ unit ] }) ]
759767 | (Let _ | Assign _ | Set_field _ | Offset_ref _ | Array_set _ | Event _) as instr
760768 -> [ instr ]
761769 in
0 commit comments