@@ -729,6 +729,54 @@ let build_graph ctx pc =
729729 in
730730 loop pc Addr.Set. empty [] ;
731731 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
732780 let () =
733781 (* Create an artificial frontier when we pop an exception handler *)
734782 let rec keep_front pc =
@@ -1417,6 +1465,10 @@ and compile_block st queue (pc : Addr.t) loop_stack frontier interm =
14171465 | false -> compile_block_no_loop st queue pc loop_stack frontier interm
14181466 | true ->
14191467 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
14201472 let never_body, body =
14211473 let lab =
14221474 match loop_stack with
@@ -1426,7 +1478,13 @@ and compile_block st queue (pc : Addr.t) loop_stack frontier interm =
14261478 let lab_used = ref false in
14271479 let loop_stack = (pc, (lab, lab_used)) :: loop_stack in
14281480 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
14301488 in
14311489 let body =
14321490 let rec remove_tailing_continue acc = function
@@ -1459,7 +1517,10 @@ and compile_block st queue (pc : Addr.t) loop_stack frontier interm =
14591517 in
14601518 never_body, [ for_loop ]
14611519 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
14631524
14641525(* Compile block. Loops have already been handled. *)
14651526and compile_block_no_loop st queue (pc : Addr.t ) loop_stack frontier interm =
0 commit comments