···44module IntMap = Map.Make(Int)
55module IntSet = Set.Make(Int)
6677-(* Immediate dominator, derived correctly from full dominator sets.
88- The idom of n is the unique proper dominator d of n that is itself
99- dominated by every other proper dominator of n (i.e. the deepest one).
1010- This replaces the previous ad-hoc heuristic, which could mis-pick an outer
1111- dominator when a node had 3+ dominators. *)
1212-let idom cfg doms id =
77+let rev_postorder cfg =
88+ let visited = ref IntSet.empty in
99+ let order = ref [] in
1010+ let rec dfs id =
1111+ if IntSet.mem id !visited then ()
1212+ else begin
1313+ visited := IntSet.add id !visited;
1414+ let b = IntMap.find id cfg.blocks in
1515+ List.iter dfs b.succs;
1616+ order := id :: !order
1717+ end
1818+ in
1919+ dfs cfg.entry;
2020+ let remaining = IntMap.fold (fun k _ acc ->
2121+ if IntSet.mem k !visited then acc else k :: acc
2222+ ) cfg.blocks [] in
2323+ !order @ remaining
2424+2525+let dominators cfg =
2626+ let rpo = rev_postorder cfg in
2727+ let rpo_idx = Hashtbl.create 64 in
2828+ List.iteri (fun i x -> Hashtbl.add rpo_idx x i) rpo;
2929+ let idom = ref IntMap.empty in
3030+ let get_rank v =
3131+ try Hashtbl.find rpo_idx v with Not_found -> max_int in
3232+ List.iter (fun w ->
3333+ if w = cfg.entry then ()
3434+ else
3535+ let b = IntMap.find w cfg.blocks in
3636+ match b.preds with
3737+ | [] -> ()
3838+ | p0 :: ps ->
3939+ let find_best v =
4040+ try IntMap.find v !idom with Not_found -> v
4141+ in
4242+ let best = ref (find_best p0) in
4343+ let best_rank = ref (get_rank !best) in
4444+ List.iter (fun p ->
4545+ let candidate = find_best p in
4646+ let r = get_rank candidate in
4747+ if r < !best_rank then begin best := candidate; best_rank := r end
4848+ ) ps;
4949+ let semi_w = !best in
5050+ let rec walk cur best_id =
5151+ if cur = w then best_id
5252+ else
5353+ let r = get_rank cur in
5454+ let best_id = if r < get_rank best_id then cur else best_id in
5555+ try
5656+ let parent = IntMap.find cur !idom in
5757+ walk parent best_id
5858+ with Not_found -> best_id
5959+ in
6060+ let idom_w = walk semi_w w in
6161+ idom := IntMap.add w idom_w !idom;
6262+ ignore semi_w
6363+ ) rpo;
6464+ let doms = ref IntMap.empty in
6565+ List.iter (fun id ->
6666+ let rec collect v acc =
6767+ if IntSet.mem v acc then acc
6868+ else
6969+ let acc = IntSet.add v acc in
7070+ try collect (IntMap.find v !idom) acc with Not_found -> acc
7171+ in
7272+ doms := IntMap.add id (collect id IntSet.empty) !doms
7373+ ) rpo;
7474+ !doms
7575+7676+let dominates doms a b =
7777+ IntSet.mem a (IntMap.find b doms)
7878+7979+let idom_from_doms doms id =
1380 let s = IntMap.find id doms in
1481 let without = IntSet.diff s (IntSet.singleton id) in
1582 if IntSet.is_empty without then None
1683 else
1784 let strict_doms = IntSet.elements without in
1818- (* Find the d in strict_doms that every other strict dominator dominates. *)
1985 let rec find = function
2086 | [] -> None
2187 | d :: rest ->
···2591 in
2692 find strict_doms
27932828-let dominators cfg =
2929- let all = IntMap.fold (fun k _ s -> IntSet.add k s) cfg.blocks IntSet.empty in
3030- let init = IntSet.singleton cfg.entry in
3131- let rec fixpoint doms =
3232- let new_doms = IntMap.mapi (fun id _ ->
3333- if id = cfg.entry then init
3434- else
3535- let b = IntMap.find id cfg.blocks in
3636- match b.preds with
3737- | [] -> IntSet.empty
3838- | p :: ps ->
3939- let inter = List.fold_left (fun acc pr ->
4040- try IntSet.inter acc (IntMap.find pr doms)
4141- with Not_found -> acc
4242- ) (try IntMap.find p doms with Not_found -> IntSet.empty) ps in
4343- IntSet.add id inter
4444- ) cfg.blocks in
4545- if IntMap.equal IntSet.equal doms new_doms then doms
4646- else fixpoint new_doms
4747- in
4848- fixpoint (IntMap.map (fun _ -> all) cfg.blocks)
4949-5050-let dominates doms a b =
5151- IntSet.mem a (IntMap.find b doms)
5252-5394let dominance_frontiers cfg doms =
5495 let df = ref IntMap.empty in
5596 IntMap.iter (fun id _ -> df := IntMap.add id IntSet.empty !df) cfg.blocks;
···5798 match b.preds with
5899 | [] | [_] -> ()
59100 | _ ->
6060- let idom_y = idom cfg doms id in
101101+ let idom_y = idom_from_doms doms id in
61102 List.iter (fun p ->
6262- (* Runner p is a predecessor of Y (p <> Y). Add Y to DF at each node
6363- from p up to (but not including) Y's idom. p itself is included. *)
64103 let rec walk cur =
6565- if Some cur = idom_y then () (* reached idom(Y): stop, don't add *)
104104+ if Some cur = idom_y then ()
66105 else begin
67106 df := IntMap.add cur (IntSet.add id (IntMap.find cur !df)) !df;
6868- (match idom cfg doms cur with
107107+ (match idom_from_doms doms cur with
69108 | None -> ()
70109 | Some n -> walk n)
71110 end