@@ -729,6 +729,54 @@ let build_graph ctx pc =
729
729
in
730
730
loop pc Addr.Set. empty [] ;
731
731
Hashtbl. add preds pc 1 ;
732
+ let () =
733
+ (* Create an artificial frontier when for-loops are not longer necessary *)
734
+ let loopback = Hashtbl. create 17 in
735
+ let rec loop pc loop_headers =
736
+ match Hashtbl. find loopback pc with
737
+ | x -> x
738
+ | exception Not_found ->
739
+ let loop_headers =
740
+ if Addr.Set. mem pc ! loops then Addr.Set. add pc loop_headers else loop_headers
741
+ in
742
+ let backs = Hashtbl. find backs pc in
743
+ let all_backs =
744
+ List. fold_left (Hashtbl. find succs pc) ~init: backs ~f: (fun acc pc ->
745
+ Addr.Set. union acc (loop pc loop_headers))
746
+ |> Addr.Set. inter loop_headers
747
+ in
748
+ Hashtbl. replace loopback pc all_backs;
749
+ all_backs
750
+ in
751
+ ignore (loop pc Addr.Set. empty);
752
+ let compute_exit_loop pc_loop =
753
+ let visited = Hashtbl. create 18 in
754
+ let rec find pc_loops pc acc =
755
+ if Hashtbl. mem visited pc
756
+ then acc
757
+ else if Addr.Set. cardinal (Addr.Set. inter pc_loops (Hashtbl. find loopback pc)) = 0
758
+ then Addr.Set. add pc acc
759
+ else
760
+ let pc_loops =
761
+ if Addr.Set. mem pc ! loops then Addr.Set. add pc pc_loops else pc_loops
762
+ in
763
+ let block = Addr.Map. find pc blocks in
764
+ let succs =
765
+ match block.branch with
766
+ | Pushtrap ((pc1 , _ ), _ , (pc_exn , _ ), _ ) ->
767
+ Addr.Set. add pc_exn (Hashtbl. find poptrap pc1) |> Addr.Set. elements
768
+ | _ -> Hashtbl. find succs pc
769
+ in
770
+ List. fold_left succs ~init: acc ~f: (fun acc pc' -> find pc_loops pc' acc)
771
+ in
772
+ find (Addr.Set. singleton pc_loop) pc_loop Addr.Set. empty
773
+ in
774
+ Addr.Set. iter
775
+ (fun pc_loop ->
776
+ let set = compute_exit_loop pc_loop in
777
+ add_cf_frontier pc_loop set)
778
+ ! loops
779
+ in
732
780
let () =
733
781
(* Create an artificial frontier when we pop an exception handler *)
734
782
let rec keep_front pc =
@@ -1417,6 +1465,10 @@ and compile_block st queue (pc : Addr.t) loop_stack frontier interm =
1417
1465
| false -> compile_block_no_loop st queue pc loop_stack frontier interm
1418
1466
| true ->
1419
1467
if debug () then Format. eprintf " @[<hv 2>for(;;) {@," ;
1468
+ let grey = dominance_frontier st pc in
1469
+ let exit_prefix, exit_cont, exit_interm, merge_node =
1470
+ colapse_frontier " for-loop" st grey interm
1471
+ in
1420
1472
let never_body, body =
1421
1473
let lab =
1422
1474
match loop_stack with
@@ -1426,7 +1478,13 @@ and compile_block st queue (pc : Addr.t) loop_stack frontier interm =
1426
1478
let lab_used = ref false in
1427
1479
let loop_stack = (pc, (lab, lab_used)) :: loop_stack in
1428
1480
let never_body, body =
1429
- compile_block_no_loop st queue pc loop_stack frontier interm
1481
+ compile_block_no_loop
1482
+ st
1483
+ queue
1484
+ pc
1485
+ loop_stack
1486
+ (Addr.Set. union frontier exit_cont)
1487
+ exit_interm
1430
1488
in
1431
1489
let body =
1432
1490
let rec remove_tailing_continue acc = function
@@ -1459,7 +1517,10 @@ and compile_block st queue (pc : Addr.t) loop_stack frontier interm =
1459
1517
in
1460
1518
never_body, [ for_loop ]
1461
1519
in
1462
- never_body, body
1520
+ let never_after, after =
1521
+ compile_merge_node st exit_cont loop_stack frontier interm merge_node
1522
+ in
1523
+ never_body || never_after, exit_prefix @ body @ after
1463
1524
1464
1525
(* Compile block. Loops have already been handled. *)
1465
1526
and compile_block_no_loop st queue (pc : Addr.t ) loop_stack frontier interm =
0 commit comments