@@ -336,12 +336,15 @@ let allocate_closure ~st ~params ~body ~branch =
336
336
let name = Var. fresh () in
337
337
[ Let (name, Closure (params, (pc, [] ))) ], name
338
338
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 );
341
344
let ret = Var. fresh () in
342
345
if check then st.trampolined_calls := Var.Set. add ret ! (st.trampolined_calls);
343
346
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
345
348
346
349
let cps_branch ~st ~src (pc , args ) =
347
350
match Addr.Set. mem pc st.blocks_to_transform with
@@ -359,14 +362,8 @@ let cps_branch ~st ~src (pc, args) =
359
362
(* We check the stack depth only for backward edges (so, at
360
363
least once per loop iteration) *)
361
364
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
370
367
371
368
let cps_jump_cont ~st ~src ((pc , _ ) as cont ) =
372
369
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 =
433
430
(* If the number of successive 'returns' is unbounded in CPS, it
434
431
means that we have an unbounded of calls in direct style
435
432
(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 ]
437
434
| Raise (x , rmode ) -> (
438
435
assert (List. is_empty alloc_jump_closures);
439
436
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 =
468
465
tail_call
469
466
~st
470
467
~instrs: (Let (exn_handler, Prim (Extern " caml_pop_trap" , [] )) :: instrs)
471
- ~exact: true
468
+ ~kind: Exact
472
469
~in_cps: false
473
470
~check: false
474
471
~f: exn_handler
@@ -522,6 +519,14 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last =
522
519
@ (Let (exn_handler, Prim (Extern " caml_pop_trap" , [] )) :: body)
523
520
, branch ))
524
521
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
+
525
530
let rewrite_instr ~st (instr : instr ) : instr =
526
531
match instr with
527
532
| Let (x , Closure (_ , (pc , _ ))) when Var.Set. mem x st.cps_needed ->
@@ -542,34 +547,37 @@ let rewrite_instr ~st (instr : instr) : instr =
542
547
(Extern " caml_alloc_dummy_function" , [ size; Pc (Int (Targetint. succ a)) ])
543
548
)
544
549
| _ -> 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' })
561
568
| Let (_ , e ) when effect_primitive_or_application e ->
562
569
(* For the CPS target, applications of CPS functions and effect primitives require
563
570
more work (allocating a continuation and/or modifying end-of-block branches) and
564
571
are handled in a specialized function. *)
565
572
assert false
566
573
| _ -> instr
567
574
568
- let call_exact flow_info (f : Var.t ) nargs : bool =
575
+ let call_kind flow_info (f : Var.t ) nargs =
569
576
(* If [f] is unknown to the global flow analysis, then it was introduced by
570
577
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
573
581
574
582
let cps_instr ~st (instr : instr ) : instr list =
575
583
match instr with
@@ -578,7 +586,7 @@ let cps_instr ~st (instr : instr) : instr list =
578
586
Otherwise, the runtime primitive is used. *)
579
587
let unit = Var. fresh_n " unit" in
580
588
[ 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 ] })
582
590
]
583
591
| _ -> [ rewrite_instr ~st instr ]
584
592
@@ -653,11 +661,11 @@ let cps_block ~st ~k ~orig_pc block =
653
661
[ Let (x, e) ], Return x)
654
662
in
655
663
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 ->
657
665
Some
658
666
(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 ]))
661
669
| Prim (Extern "%resume" , [ Pv stack ; Pv f ; Pv arg ; tail ]) ->
662
670
Some
663
671
(fun ~k ->
@@ -666,7 +674,7 @@ let cps_block ~st ~k ~orig_pc block =
666
674
~st
667
675
~instrs:
668
676
[ 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 )
670
678
~in_cps: true
671
679
~check: true
672
680
~f
@@ -754,8 +762,8 @@ let rewrite_direct_block ~st ~cps_needed ~closure_info ~pc block =
754
762
(* We just need to call [f] in direct style. *)
755
763
let unit = Var. fresh_n " unit" in
756
764
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 ] }) ]
759
767
| (Let _ | Assign _ | Set_field _ | Offset_ref _ | Array_set _ | Event _) as instr
760
768
-> [ instr ]
761
769
in
0 commit comments