···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 =
1313- let s = IntMap.find id doms in
1414- let without = IntSet.diff s (IntSet.singleton id) in
1515- if IntSet.is_empty without then None
1616- else
1717- let strict_doms = IntSet.elements without in
1818- (* Find the d in strict_doms that every other strict dominator dominates. *)
1919- let rec find = function
2020- | [] -> None
2121- | d :: rest ->
2222- if List.for_all (fun m -> m = d || IntSet.mem d (IntMap.find m doms)) strict_doms
2323- then Some d
2424- else find rest
2525- in
2626- find strict_doms
2727-287let rev_postorder cfg =
298 let visited = ref IntSet.empty in
309 let order = ref [] in
···4423 !order @ remaining
45244625let dominators cfg =
4747- let all = IntMap.fold (fun k _ s -> IntSet.add k s) cfg.blocks IntSet.empty in
4848- let init = IntSet.singleton cfg.entry in
4926 let rpo = rev_postorder cfg in
5050- let rec fixpoint doms =
5151- let new_doms = List.fold_left (fun acc id ->
5252- if id = cfg.entry then IntMap.add id init acc
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
5368 else
5454- let b = IntMap.find id cfg.blocks in
5555- match b.preds with
5656- | [] -> IntMap.add id IntSet.empty acc
5757- | p :: ps ->
5858- let inter = List.fold_left (fun a pr ->
5959- try IntSet.inter a (IntMap.find pr acc)
6060- with Not_found -> a
6161- ) (try IntMap.find p acc with Not_found -> IntSet.empty) ps in
6262- IntMap.add id (IntSet.add id inter) acc
6363- ) IntMap.empty rpo in
6464- if IntMap.equal IntSet.equal doms new_doms then doms
6565- else fixpoint new_doms
6666- in
6767- fixpoint (IntMap.map (fun _ -> all) cfg.blocks)
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
68756976let dominates doms a b =
7077 IntSet.mem a (IntMap.find b doms)
71787979+let idom_from_doms doms id =
8080+ let s = IntMap.find id doms in
8181+ let without = IntSet.diff s (IntSet.singleton id) in
8282+ if IntSet.is_empty without then None
8383+ else
8484+ let strict_doms = IntSet.elements without in
8585+ let rec find = function
8686+ | [] -> None
8787+ | d :: rest ->
8888+ if List.for_all (fun m -> m = d || IntSet.mem d (IntMap.find m doms)) strict_doms
8989+ then Some d
9090+ else find rest
9191+ in
9292+ find strict_doms
9393+7294let dominance_frontiers cfg doms =
7395 let df = ref IntMap.empty in
7496 IntMap.iter (fun id _ -> df := IntMap.add id IntSet.empty !df) cfg.blocks;
···7698 match b.preds with
7799 | [] | [_] -> ()
78100 | _ ->
7979- let idom_y = idom cfg doms id in
101101+ let idom_y = idom_from_doms doms id in
80102 List.iter (fun p ->
8181- (* Runner p is a predecessor of Y (p <> Y). Add Y to DF at each node
8282- from p up to (but not including) Y's idom. p itself is included. *)
83103 let rec walk cur =
8484- if Some cur = idom_y then () (* reached idom(Y): stop, don't add *)
104104+ if Some cur = idom_y then ()
85105 else begin
86106 df := IntMap.add cur (IntSet.add id (IntMap.find cur !df)) !df;
8787- (match idom cfg doms cur with
107107+ (match idom_from_doms doms cur with
88108 | None -> ()
89109 | Some n -> walk n)
90110 end