浏览代码

[analyzer] add idom calculation

Simon Krajewski 9 年之前
父节点
当前提交
6f9b80d395
共有 1 个文件被更改,包括 103 次插入0 次删除
  1. 103 0
      src/optimization/analyzer.ml

+ 103 - 0
src/optimization/analyzer.ml

@@ -936,7 +936,110 @@ module Graph = struct
 				prerr_endline (Printf.sprintf "Outgoing edge %i -> %i has no matching incoming edge" edge.cfg_from.bb_id edge.cfg_to.bb_id)
 		)
 
+	let calculate_immediate_dominators g =
+		let semi = Hashtbl.create 0 in
+		let semi_size = ref 0 in
+		let parent = Hashtbl.create 0 in
+		let bucket = Hashtbl.create 0 in
+		let idom = Hashtbl.create 0 in
+		let label = Hashtbl.create 0 in
+		let ancestor = Hashtbl.create 0 in
+		let nodes = DynArray.create () in
+		let get_semi k = Hashtbl.find semi k in
+		let set_semi k v = Hashtbl.replace semi k v in
+		let get_parent k = Hashtbl.find parent k in
+		let set_parent k v = Hashtbl.add parent k v in
+		let get_label k = Hashtbl.find label k in
+		let set_label k v = Hashtbl.replace label k v in
+		let get_ancestor k = Hashtbl.find ancestor k in
+		let set_ancestor k v = Hashtbl.replace ancestor k v in
+		let has_ancestor k = Hashtbl.mem ancestor k in
+		let get_idom k = Hashtbl.find idom k in
+		let set_idom k v = Hashtbl.replace idom k v in
+		let get_bucket k = try Hashtbl.find bucket k with Not_found -> [] in
+		let add_to_bucket k v = Hashtbl.replace bucket k (v :: (get_bucket k)) in
+		let clear_bucket k = Hashtbl.replace bucket k [] in
+		let rec loop bb =
+			bb.bb_dominated <- [];
+			DynArray.add nodes bb;
+			set_semi bb.bb_id !semi_size;
+			incr semi_size;
+			set_label bb.bb_id bb.bb_id;
+			List.iter (fun edge ->
+				let bb_to = edge.cfg_to in
+				if not (Hashtbl.mem semi bb_to.bb_id) then begin
+					set_parent bb_to.bb_id bb;
+					loop bb_to
+				end
+			) bb.bb_outgoing
+		in
+		loop g.g_root;
+		let compress v =
+			let rec loop l a = try
+				loop (a :: l) (Hashtbl.find ancestor a)
+			with Not_found ->
+				l
+			in
+			let worklist = loop [v] (get_ancestor v) in
+			match worklist with
+				| a :: worklist ->
+					ignore(List.fold_left (fun (a,min_semi) desc ->
+						let semi = get_semi (get_label desc) in
+						if semi > min_semi then begin
+							set_label desc (get_label a);
+							(desc,min_semi)
+						end else
+							(desc,semi)
+					) (a,get_semi (get_label a)) worklist)
+				| [] ->
+					assert false
+		in
+		let eval v =
+			if has_ancestor v then begin
+				compress v;
+				get_label v;
+			end else
+				v
+		in
+		let link p c =
+			set_ancestor c p
+		in
+		let rec loop nodes' = match nodes' with
+			| [node] -> set_idom node.bb_id node.bb_id
+			| [] -> assert false
+			| w :: nodes' ->
+				let p = get_parent w.bb_id in
+				let semi = List.fold_left (fun acc v -> min acc (get_semi (eval v.cfg_from.bb_id))) (get_semi w.bb_id) w.bb_incoming in
+				set_semi w.bb_id semi;
+				add_to_bucket (DynArray.get nodes semi).bb_id w;
+				link p.bb_id w.bb_id;
+				List.iter (fun v ->
+					let v = v.bb_id in
+					let u = eval v in
+					if get_semi u < get_semi v then
+						set_idom v u
+					else
+						set_idom v p.bb_id
+				) (get_bucket p.bb_id);
+				clear_bucket p.bb_id;
+				loop nodes'
+		in
+		loop (List.rev (DynArray.to_list nodes));
+		List.iter (fun w ->
+			let w = w.bb_id in
+			let i = get_idom w in
+			if i <> (DynArray.get nodes (get_semi w)).bb_id then
+				set_idom w (get_idom i)
+		) (List.tl ((DynArray.to_list nodes)));
+		Hashtbl.iter (fun k v ->
+			let bb = Hashtbl.find g.g_nodes k in
+			let bb' = Hashtbl.find g.g_nodes v in
+			bb.bb_dominator <- bb';
+			if bb != bb' then bb'.bb_dominated <- bb :: bb'.bb_dominated
+		) idom
+
 	let finalize g bb_exit =
+		calculate_immediate_dominators g;
 		g.g_exit <- bb_exit
 end