@@ -304,12 +304,15 @@ let allocate_closure ~st ~params ~body ~branch =
304304 let name = Var. fresh () in
305305 [ Let (name, Closure (params, (pc, [] ))) ], name
306306
307- let tail_call ~st ?(instrs = [] ) ~exact ~in_cps ~check ~f args =
308- assert (exact || check);
307+ let tail_call ~st ?(instrs = [] ) ~kind ~in_cps ~check ~f args =
308+ assert (
309+ match kind with
310+ | Generic -> check
311+ | Exact | Known _ -> true );
309312 let ret = Var. fresh () in
310313 if check then st.trampolined_calls := Var.Set. add ret ! (st.trampolined_calls);
311314 if in_cps then st.in_cps := Var.Set. add ret ! (st.in_cps);
312- instrs @ [ Let (ret, Apply { f; args; exact }) ], Return ret
315+ instrs @ [ Let (ret, Apply { f; args; kind }) ], Return ret
313316
314317let cps_branch ~st ~src (pc , args ) =
315318 match Addr.Set. mem pc st.blocks_to_transform with
@@ -327,14 +330,8 @@ let cps_branch ~st ~src (pc, args) =
327330 (* We check the stack depth only for backward edges (so, at
328331 least once per loop iteration) *)
329332 let check = Hashtbl. find st.block_order src > = Hashtbl. find st.block_order pc in
330- tail_call
331- ~st
332- ~instrs
333- ~exact: true
334- ~in_cps: false
335- ~check
336- ~f: (closure_of_pc ~st pc)
337- args
333+ let f = closure_of_pc ~st pc in
334+ tail_call ~st ~instrs ~kind: (Known f) ~in_cps: false ~check ~f args
338335
339336let cps_jump_cont ~st ~src ((pc , _ ) as cont ) =
340337 match Addr.Set. mem pc st.blocks_to_transform with
@@ -396,7 +393,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
396393 (* Is the number of successive 'returns' is unbounded is CPS, it
397394 means that we have an unbounded of calls in direct style
398395 (even with tail call optimization) *)
399- tail_call ~st ~exact: true ~in_cps: false ~check: false ~f: k [ x ]
396+ tail_call ~st ~kind: Exact ~in_cps: false ~check: false ~f: k [ x ]
400397 | Raise (x , rmode ) -> (
401398 assert (List. is_empty alloc_jump_closures);
402399 match Hashtbl. find_opt st.matching_exn_handler pc with
@@ -431,7 +428,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
431428 tail_call
432429 ~st
433430 ~instrs: (Let (exn_handler, Prim (Extern " caml_pop_trap" , [] )) :: instrs)
434- ~exact: true
431+ ~kind: Exact
435432 ~in_cps: false
436433 ~check: false
437434 ~f: exn_handler
@@ -481,6 +478,14 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
481478 @ (Let (exn_handler, Prim (Extern " caml_pop_trap" , [] )) :: body)
482479 , branch ))
483480
481+ let refine_kind k k' =
482+ match k, k' with
483+ | Known _ , _ -> k
484+ | _ , Known _ -> k'
485+ | Exact , _ -> k
486+ | _ , Exact -> k'
487+ | Generic , Generic -> k
488+
484489let cps_instr ~st (instr : instr ) : instr =
485490 match instr with
486491 | Let (x , Closure (params , (pc , _ ))) when Var.Set. mem x st.cps_needed ->
@@ -498,11 +503,15 @@ let cps_instr ~st (instr : instr) : instr =
498503 (Extern " caml_alloc_dummy_function" , [ size; Pc (Int (Targetint. succ a)) ])
499504 )
500505 | _ -> assert false )
501- | Let (x , Apply { f; args; _ } ) when not (Var.Set. mem x st.cps_needed) ->
506+ | Let (x , Apply { f; args; kind } ) when not (Var.Set. mem x st.cps_needed) ->
502507 (* At the moment, we turn into CPS any function not called with
503508 the right number of parameter *)
504- assert (Global_flow. exact_call st.flow_info f (List. length args));
505- Let (x, Apply { f; args; exact = true })
509+ let kind' = Global_flow. apply_kind st.flow_info f (List. length args) in
510+ assert (
511+ match kind' with
512+ | Generic -> false
513+ | Exact | Known _ -> true );
514+ Let (x, Apply { f; args; kind = refine_kind kind kind' })
506515 | Let (_ , (Apply _ | Prim (Extern ("%resume" | "%perform" | "%reperform" ), _ ))) ->
507516 assert false
508517 | _ -> instr
@@ -552,21 +561,21 @@ let cps_block ~st ~k pc block =
552561 [ Let (x, e) ], Return x)
553562 in
554563 match e with
555- | Apply { f; args; exact } when Var.Set. mem x st.cps_needed ->
564+ | Apply { f; args; kind } when Var.Set. mem x st.cps_needed ->
556565 Some
557566 (fun ~k ->
558- let exact =
559- exact || Global_flow. exact_call st.flow_info f (List. length args)
567+ let kind =
568+ refine_kind kind ( Global_flow. apply_kind st.flow_info f (List. length args) )
560569 in
561- tail_call ~st ~exact ~in_cps: true ~check: true ~f (args @ [ k ]))
570+ tail_call ~st ~kind ~in_cps: true ~check: true ~f (args @ [ k ]))
562571 | Prim (Extern "%resume" , [ Pv stack ; Pv f ; Pv arg ]) ->
563572 Some
564573 (fun ~k ->
565574 let k' = Var. fresh_n " cont" in
566575 tail_call
567576 ~st
568577 ~instrs: [ Let (k', Prim (Extern " caml_resume_stack" , [ Pv stack; Pv k ])) ]
569- ~exact : (Global_flow. exact_call st.flow_info f 1 )
578+ ~kind : (Global_flow. apply_kind st.flow_info f 1 )
570579 ~in_cps: true
571580 ~check: true
572581 ~f
0 commit comments