Browse Source

[analyzer] cleanup and optimize

* remove some unused functions
* use Hashtbl instead of IntMap
* remove some redundant data
* avoid some useless blocks
* don't waste time dealing with elements in unreachable places
* add cfg-ssa dot-graph
Simon Krajewski 9 years ago
parent
commit
edb3fd44d4
1 changed files with 147 additions and 114 deletions
  1. 147 114
      src/optimization/analyzer.ml

+ 147 - 114
src/optimization/analyzer.ml

@@ -28,15 +28,6 @@ let rec is_true_expr e1 = match e1.eexpr with
 	| TParenthesis e1 -> is_true_expr e1
 	| TParenthesis e1 -> is_true_expr e1
 	| _ -> false
 	| _ -> false
 
 
-let rec is_const_expression e = match e.eexpr with
-	| TConst _ ->
-		true
-	| TParenthesis e1
-	| TMeta(_,e1) ->
-		is_const_expression e1
-	| _ ->
-		false
-
 let map_values ?(allow_control_flow=true) f e =
 let map_values ?(allow_control_flow=true) f e =
 	let branching = ref false in
 	let branching = ref false in
 	let efinal = ref None in
 	let efinal = ref None in
@@ -131,10 +122,6 @@ let is_pure c cf = has_pure_meta c.cl_meta || has_pure_meta cf.cf_meta
 let wrap_meta s e =
 let wrap_meta s e =
 	mk (TMeta((Meta.Custom s,[],e.epos),e)) e.etype e.epos
 	mk (TMeta((Meta.Custom s,[],e.epos),e)) e.etype e.epos
 
 
-let rec expr_eq e1 e2 = match e1.eexpr,e2.eexpr with
-	| TConst ct1,TConst ct2 -> ct1 = ct2
-	| _ -> false
-
 let is_unbound v =
 let is_unbound v =
 	Meta.has Meta.Unbound v.v_meta
 	Meta.has Meta.Unbound v.v_meta
 
 
@@ -240,25 +227,7 @@ module Config = struct
 			false
 			false
 
 
 	let is_ignored meta =
 	let is_ignored meta =
-		try
-			let rec loop ml = match ml with
-				| (Meta.Analyzer,el,_) :: ml ->
-					if List.exists (fun (e,p) ->
-						match e with
-							| EConst(Ident s2) when flag_ignore = s2 -> true
-							| _ -> false
-					) el then
-						true
-					else
-						loop ml
-				| _ :: ml ->
-					loop ml
-				| [] ->
-					false
-			in
-			loop meta
-		with Not_found ->
-			false
+		has_analyzer_option meta flag_ignore
 
 
 	let get_base_config com =
 	let get_base_config com =
 		{
 		{
@@ -458,16 +427,16 @@ module Fusion = struct
 				acc
 				acc
 		in
 		in
 		let changed = ref false in
 		let changed = ref false in
-		let var_uses = ref IntMap.empty in
-		let var_writes = ref IntMap.empty in
+		let var_uses = Hashtbl.create 0 in
+		let var_writes = Hashtbl.create 0 in
 		let get_num_uses v =
 		let get_num_uses v =
-			try IntMap.find v.v_id !var_uses with Not_found -> 0
+			try Hashtbl.find var_uses v.v_id with Not_found -> 0
 		in
 		in
 		let get_num_writes v =
 		let get_num_writes v =
-			try IntMap.find v.v_id !var_writes with Not_found -> 0
+			try Hashtbl.find var_writes v.v_id with Not_found -> 0
 		in
 		in
 		let change map v delta =
 		let change map v delta =
-			map := IntMap.add v.v_id ((try IntMap.find v.v_id !map with Not_found -> 0) + delta) !map;
+			Hashtbl.replace map v.v_id ((try Hashtbl.find map v.v_id with Not_found -> 0) + delta);
 		in
 		in
 		let change_num_uses v delta =
 		let change_num_uses v delta =
 			change var_uses v delta
 			change var_uses v delta
@@ -745,6 +714,13 @@ module BasicBlock = struct
 		| BKException -> "BKException"
 		| BKException -> "BKException"
 		| BKUnreachable -> "BKUnreachable"
 		| BKUnreachable -> "BKUnreachable"
 
 
+	let s_cfg_edge_kind = function
+		| CFGGoto -> "CFGGoto"
+		| CFGFunction -> "CFGFunction"
+		| CFGMaybeThrow -> "CFGMaybeThrow"
+		| CFGCondBranch e -> "CFGCondBranch " ^ (s_expr_pretty e)
+		| CFGCondElse -> "CFGCondElse"
+
 	let has_flag edge flag =
 	let has_flag edge flag =
 		List.mem flag edge.cfg_flags
 		List.mem flag edge.cfg_flags
 
 
@@ -784,6 +760,7 @@ module Graph = struct
 	type texpr_lookup = BasicBlock.t * bool * int
 	type texpr_lookup = BasicBlock.t * bool * int
 	type tfunc_info = BasicBlock.t * Type.t * pos * tfunc
 	type tfunc_info = BasicBlock.t * Type.t * pos * tfunc
 	type var_write = BasicBlock.t list
 	type var_write = BasicBlock.t list
+	type 'a itbl = (int,'a) Hashtbl.t
 
 
 	type var_info = {
 	type var_info = {
 		vi_var : tvar;                            (* The variable itself *)
 		vi_var : tvar;                            (* The variable itself *)
@@ -800,9 +777,8 @@ module Graph = struct
 		mutable g_root : BasicBlock.t;             (* The unique root block *)
 		mutable g_root : BasicBlock.t;             (* The unique root block *)
 		mutable g_exit : BasicBlock.t;             (* The unique exit block *)
 		mutable g_exit : BasicBlock.t;             (* The unique exit block *)
 		mutable g_unreachable : BasicBlock.t;      (* The unique unreachable block *)
 		mutable g_unreachable : BasicBlock.t;      (* The unique unreachable block *)
-		mutable g_functions : tfunc_info IntMap.t; (* A map of functions, indexed by their block IDs *)
-		mutable g_nodes : BasicBlock.t IntMap.t;   (* A map of all blocks *)
-		mutable g_cfg_edges : cfg_edge list;       (* A list of all CFG edges *)
+		mutable g_functions : tfunc_info itbl;     (* A map of functions, indexed by their block IDs *)
+		mutable g_nodes : BasicBlock.t itbl;       (* A map of all blocks *)
 		g_var_infos : var_info DynArray.t;         (* A map of variable information *)
 		g_var_infos : var_info DynArray.t;         (* A map of variable information *)
 		mutable g_loops : BasicBlock.t IntMap.t;   (* A map containing loop information *)
 		mutable g_loops : BasicBlock.t IntMap.t;   (* A map containing loop information *)
 	}
 	}
@@ -837,7 +813,6 @@ module Graph = struct
 	let add_cfg_edge g bb_from bb_to kind =
 	let add_cfg_edge g bb_from bb_to kind =
 		if bb_from != g.g_unreachable then begin
 		if bb_from != g.g_unreachable then begin
 			let edge = { cfg_from = bb_from; cfg_to = bb_to; cfg_kind = kind; cfg_flags = [] } in
 			let edge = { cfg_from = bb_from; cfg_to = bb_to; cfg_kind = kind; cfg_flags = [] } in
-			g.g_cfg_edges <- edge :: g.g_cfg_edges;
 			bb_from.bb_outgoing <- edge :: bb_from.bb_outgoing;
 			bb_from.bb_outgoing <- edge :: bb_from.bb_outgoing;
 			bb_to.bb_incoming <- edge :: bb_to.bb_incoming;
 			bb_to.bb_incoming <- edge :: bb_to.bb_incoming;
 		end
 		end
@@ -849,7 +824,7 @@ module Graph = struct
 	(* nodes *)
 	(* nodes *)
 
 
 	let add_function g tf t p bb =
 	let add_function g tf t p bb =
-		g.g_functions <- IntMap.add bb.bb_id (bb,t,p,tf) g.g_functions
+		Hashtbl.add g.g_functions bb.bb_id (bb,t,p,tf)
 
 
 	let alloc_id =
 	let alloc_id =
 		let r = ref 1 in
 		let r = ref 1 in
@@ -862,7 +837,7 @@ module Graph = struct
 		let bb = BasicBlock._create (alloc_id()) kind scopes t p in
 		let bb = BasicBlock._create (alloc_id()) kind scopes t p in
 		bb.bb_dominator <- bb_dom;
 		bb.bb_dominator <- bb_dom;
 		bb_dom.bb_dominated <- bb :: bb_dom.bb_dominated;
 		bb_dom.bb_dominated <- bb :: bb_dom.bb_dominated;
-		g.g_nodes <- IntMap.add bb.bb_id bb g.g_nodes;
+		Hashtbl.add g.g_nodes bb.bb_id bb;
 		bb
 		bb
 
 
 	let close_node g bb =
 	let close_node g bb =
@@ -878,6 +853,9 @@ module Graph = struct
 		in
 		in
 		loop g.g_root
 		loop g.g_root
 
 
+	let iter_edges g f =
+		iter_dom_tree g (fun bb -> List.iter f bb.bb_outgoing)
+
 	(* expressions *)
 	(* expressions *)
 
 
 	let add_texpr g bb e =
 	let add_texpr g bb e =
@@ -922,19 +900,20 @@ module Graph = struct
 	let create t p =
 	let create t p =
 		let bb_root = BasicBlock._create 1 BKRoot [] t p; in
 		let bb_root = BasicBlock._create 1 BKRoot [] t p; in
 		let bb_unreachable = BasicBlock._create 0 BKUnreachable [] t_dynamic null_pos in
 		let bb_unreachable = BasicBlock._create 0 BKUnreachable [] t_dynamic null_pos in
+		let nodes = Hashtbl.create 0 in
+		Hashtbl.add nodes bb_root.bb_id bb_root;
 		{
 		{
 			g_root = bb_root;
 			g_root = bb_root;
 			g_exit = bb_unreachable;
 			g_exit = bb_unreachable;
 			g_unreachable = bb_unreachable;
 			g_unreachable = bb_unreachable;
-			g_functions = IntMap.empty;
-			g_nodes = IntMap.add bb_root.bb_id bb_root IntMap.empty;
-			g_cfg_edges = [];
+			g_functions = Hashtbl.create 0;
+			g_nodes = nodes;
 			g_var_infos = DynArray.create();
 			g_var_infos = DynArray.create();
 			g_loops = IntMap.empty;
 			g_loops = IntMap.empty;
 		}
 		}
 
 
 	let calculate_df g =
 	let calculate_df g =
-		List.iter (fun edge ->
+		iter_edges g (fun edge ->
 			let rec loop bb =
 			let rec loop bb =
 				if bb != g.g_unreachable && bb != edge.cfg_to && bb != edge.cfg_to.bb_dominator then begin
 				if bb != g.g_unreachable && bb != edge.cfg_to && bb != edge.cfg_to.bb_dominator then begin
 					if edge.cfg_to != g.g_exit then bb.bb_df <- edge.cfg_to :: bb.bb_df;
 					if edge.cfg_to != g.g_exit then bb.bb_df <- edge.cfg_to :: bb.bb_df;
@@ -942,7 +921,7 @@ module Graph = struct
 				end
 				end
 			in
 			in
 			loop edge.cfg_from
 			loop edge.cfg_from
-		) g.g_cfg_edges
+		)
 
 
 	let finalize g bb_exit =
 	let finalize g bb_exit =
 		g.g_exit <- bb_exit;
 		g.g_exit <- bb_exit;
@@ -1296,19 +1275,24 @@ module TexprTransformer = struct
 				scope();
 				scope();
 				let dead_then = bb_then_next == g.g_unreachable in
 				let dead_then = bb_then_next == g.g_unreachable in
 				let dead_else = bb_else_next == g.g_unreachable in
 				let dead_else = bb_else_next == g.g_unreachable in
-				let dom = match dead_then,dead_else with
-					| false,false -> bb
-					| true,true -> g.g_unreachable
-					| true,false -> bb_else_next
-					| false,true -> bb_then_next
-				in
-				let bb_next = create_node BKNormal dom bb.bb_type bb.bb_pos in
-				set_syntax_edge g bb (SEIfThenElse(bb_then,bb_else,bb_next,e.etype));
-				add_cfg_edge g bb_then_next bb_next CFGGoto;
-				add_cfg_edge g bb_else_next bb_next CFGGoto;
-				close_node g bb_then_next;
-				close_node g bb_else_next;
-				bb_next
+				begin try
+					let dom = match dead_then,dead_else with
+						| false,false -> bb
+						| true,true -> raise Exit
+						| true,false -> bb_else_next
+						| false,true -> bb_then_next
+					in
+					let bb_next = create_node BKNormal dom bb.bb_type bb.bb_pos in
+					set_syntax_edge g bb (SEIfThenElse(bb_then,bb_else,bb_next,e.etype));
+					add_cfg_edge g bb_then_next bb_next CFGGoto;
+					add_cfg_edge g bb_else_next bb_next CFGGoto;
+					close_node g bb_then_next;
+					close_node g bb_else_next;
+					bb_next
+				with Exit ->
+					set_syntax_edge g bb (SEIfThenElse(bb_then,bb_else,g.g_unreachable,e.etype));
+					g.g_unreachable
+				end
 			| TSwitch(e1,cases,edef) ->
 			| TSwitch(e1,cases,edef) ->
 				let is_exhaustive = edef <> None || Optimizer.is_exhaustive e1 in
 				let is_exhaustive = edef <> None || Optimizer.is_exhaustive e1 in
 				let bb,e1 = bind_to_temp bb false e1 in
 				let bb,e1 = bind_to_temp bb false e1 in
@@ -1337,19 +1321,25 @@ module TexprTransformer = struct
 						add_cfg_edge g bb bb_case (CFGCondElse);
 						add_cfg_edge g bb bb_case (CFGCondElse);
 						Some (bb_case)
 						Some (bb_case)
 				in
 				in
-				let dom = if not is_exhaustive then begin
-					bb
-				end else match !reachable with
-					| [] -> g.g_unreachable
-					| [bb_case] -> bb_case
-					| _ -> bb
-				in
-				let bb_next = create_node BKNormal dom bb.bb_type bb.bb_pos in
-				if not is_exhaustive then add_cfg_edge g bb bb_next CFGGoto;
-				List.iter (fun bb -> add_cfg_edge g bb bb_next CFGGoto) !reachable;
-				set_syntax_edge g bb (SESwitch(cases,def,bb_next));
-				close_node g bb;
-				bb_next
+				begin try
+					let dom = if not is_exhaustive then begin
+						bb
+					end else match !reachable with
+						| [] -> raise Exit
+						| [bb_case] -> bb_case
+						| _ -> bb
+					in
+					let bb_next = create_node BKNormal dom bb.bb_type bb.bb_pos in
+					if not is_exhaustive then add_cfg_edge g bb bb_next CFGGoto;
+					List.iter (fun bb -> add_cfg_edge g bb bb_next CFGGoto) !reachable;
+					set_syntax_edge g bb (SESwitch(cases,def,bb_next));
+					close_node g bb;
+					bb_next
+				with Exit ->
+					set_syntax_edge g bb (SESwitch(cases,def,g.g_unreachable));
+					close_node g bb;
+					g.g_unreachable;
+				end
 			| TWhile(e1,e2,NormalWhile) ->
 			| TWhile(e1,e2,NormalWhile) ->
 				let bb_loop_pre = create_node BKNormal bb e1.etype e1.epos in
 				let bb_loop_pre = create_node BKNormal bb e1.etype e1.epos in
 				add_cfg_edge g bb bb_loop_pre CFGGoto;
 				add_cfg_edge g bb bb_loop_pre CFGGoto;
@@ -1502,18 +1492,22 @@ module TexprTransformer = struct
 			| [] ->
 			| [] ->
 				List.fold_left block_element bb el;
 				List.fold_left block_element bb el;
 			| bbl ->
 			| bbl ->
-				List.fold_left (fun bb e ->
-					if not (can_throw e) then
-						block_element bb e
-					else begin
-						let bb' = create_node BKNormal bb e.etype e.epos in
-						add_cfg_edge g bb bb' CFGGoto;
-						List.iter (fun bb_exc -> add_cfg_edge g bb bb_exc CFGMaybeThrow) bbl;
-						set_syntax_edge g bb (SEMerge bb');
-						close_node g bb;
-						block_element bb' e
-					end
-				) bb el
+				let rec loop bb el = match el with
+					| [] -> bb
+					| e :: el ->
+						let bb = if not (can_throw e) then
+							block_element bb e
+						else begin
+							let bb' = create_node BKNormal bb e.etype e.epos in
+							add_cfg_edge g bb bb' CFGGoto;
+							List.iter (fun bb_exc -> add_cfg_edge g bb bb_exc CFGMaybeThrow) bbl;
+							set_syntax_edge g bb (SEMerge bb');
+							close_node g bb;
+							block_element bb' e
+						end in
+						if bb == g.g_unreachable then bb else loop bb el
+				in
+				loop bb el
 		and block bb e =
 		and block bb e =
 			let el = match e.eexpr with
 			let el = match e.eexpr with
 				| TBlock el -> el
 				| TBlock el -> el
@@ -1571,7 +1565,7 @@ module TexprTransformer = struct
 				| Some p -> com.warning "Unreachable code" p
 				| Some p -> com.warning "Unreachable code" p
 				| None -> ()
 				| None -> ()
 		in
 		in
-		if config.Config.unreachable_code then List.iter check_unreachable g.g_unreachable.bb_dominated;
+		if config.Config.unreachable_code then List.iter check_unreachable [g.g_unreachable];
 		ctx
 		ctx
 
 
 	let rec block_to_texpr_el ctx bb =
 	let rec block_to_texpr_el ctx bb =
@@ -1620,7 +1614,7 @@ module TexprTransformer = struct
 		e
 		e
 
 
 	and func ctx i =
 	and func ctx i =
-		let bb,t,p,tf = IntMap.find i ctx.graph.g_functions in
+		let bb,t,p,tf = Hashtbl.find ctx.graph.g_functions i in
 		let e = block_to_texpr ctx bb in
 		let e = block_to_texpr ctx bb in
 		let rec loop e = match e.eexpr with
 		let rec loop e = match e.eexpr with
 			| TLocal v when not (is_unbound v) ->
 			| TLocal v when not (is_unbound v) ->
@@ -1693,14 +1687,14 @@ module Ssa = struct
 			if vi.vi_bb_declare == ctx.graph.g_unreachable then
 			if vi.vi_bb_declare == ctx.graph.g_unreachable then
 				()
 				()
 			else begin
 			else begin
-				let done_list = ref IntMap.empty in
+				let done_list = Hashtbl.create 0 in
 				let w = ref vi.vi_writes in
 				let w = ref vi.vi_writes in
 				while !w <> [] do
 				while !w <> [] do
 					let x = List.hd !w in
 					let x = List.hd !w in
 					w := List.tl !w;
 					w := List.tl !w;
 					List.iter (fun y ->
 					List.iter (fun y ->
-						if not (IntMap.mem y.bb_id !done_list) then begin
-							done_list := IntMap.add y.bb_id true !done_list;
+						if not (Hashtbl.mem done_list y.bb_id) then begin
+							Hashtbl.add done_list y.bb_id true;
 							if in_scope y vi.vi_bb_declare then begin
 							if in_scope y vi.vi_bb_declare then begin
 								add_phi ctx.graph y v;
 								add_phi ctx.graph y v;
 								if not (List.memq y vi.vi_writes) then
 								if not (List.memq y vi.vi_writes) then
@@ -1985,10 +1979,10 @@ module ConstPropagation = DataFlow(struct
 	let conditional = true
 	let conditional = true
 	let flag = FlagExecutable
 	let flag = FlagExecutable
 
 
-	let lattice = ref IntMap.empty
+	let lattice = Hashtbl.create 0
 
 
-	let get_cell i = try IntMap.find i !lattice with Not_found -> Top
-	let set_cell i ct = lattice := IntMap.add i ct !lattice
+	let get_cell i = try Hashtbl.find lattice i with Not_found -> Top
+	let set_cell i ct = Hashtbl.replace lattice i ct
 
 
 	let top = Top
 	let top = Top
 	let bottom = Bottom
 	let bottom = Bottom
@@ -2078,7 +2072,7 @@ module ConstPropagation = DataFlow(struct
 			Bottom
 			Bottom
 
 
 	let init ctx =
 	let init ctx =
-		lattice := IntMap.empty
+		Hashtbl.clear lattice
 
 
 	let commit ctx =
 	let commit ctx =
 		let inline e i = match get_cell i with
 		let inline e i = match get_cell i with
@@ -2136,10 +2130,10 @@ module CopyPropagation = DataFlow(struct
 
 
 	let conditional = false
 	let conditional = false
 	let flag = FlagCopyPropagation
 	let flag = FlagCopyPropagation
-	let lattice = ref IntMap.empty
+	let lattice = Hashtbl.create 0
 
 
-	let get_cell i = try IntMap.find i !lattice with Not_found -> Top
-	let set_cell i ct = lattice := IntMap.add i ct !lattice
+	let get_cell i = try Hashtbl.find lattice i with Not_found -> Top
+	let set_cell i ct = Hashtbl.replace lattice i ct
 
 
 	let top = Top
 	let top = Top
 	let bottom = Bottom
 	let bottom = Bottom
@@ -2162,7 +2156,7 @@ module CopyPropagation = DataFlow(struct
 		loop e
 		loop e
 
 
 	let init ctx =
 	let init ctx =
-		lattice := IntMap.empty
+		Hashtbl.clear lattice
 
 
 	let commit ctx =
 	let commit ctx =
 		let rec commit bb e = match e.eexpr with
 		let rec commit bb e = match e.eexpr with
@@ -2170,7 +2164,7 @@ module CopyPropagation = DataFlow(struct
 				begin try
 				begin try
 					let lat = get_cell v.v_id in
 					let lat = get_cell v.v_id in
 					let leave () =
 					let leave () =
-						lattice := IntMap.remove v.v_id !lattice;
+						Hashtbl.remove lattice v.v_id;
 						raise Not_found
 						raise Not_found
 					in
 					in
 					let v' = match lat with Local v -> v | _ -> leave() in
 					let v' = match lat with Local v -> v | _ -> leave() in
@@ -2230,10 +2224,10 @@ module CodeMotion = DataFlow(struct
 		| _ ->
 		| _ ->
 			false
 			false
 
 
-	let lattice = ref IntMap.empty
+	let lattice = Hashtbl.create 0
 
 
-	let get_cell i = try IntMap.find i !lattice with Not_found -> top
-	let set_cell i ct = lattice := IntMap.add i ct !lattice
+	let get_cell i = try Hashtbl.find lattice i with Not_found -> top
+	let set_cell i ct = Hashtbl.replace lattice i ct
 
 
 	let rec transfer ctx bb e =
 	let rec transfer ctx bb e =
 		let rec eval e = match e.eexpr with
 		let rec eval e = match e.eexpr with
@@ -2254,7 +2248,7 @@ module CodeMotion = DataFlow(struct
 			bottom
 			bottom
 
 
 	let init ctx =
 	let init ctx =
-		lattice := IntMap.empty
+		Hashtbl.clear lattice
 
 
 	let commit ctx =
 	let commit ctx =
 		let rec filter_loops lat loops = match lat with
 		let rec filter_loops lat loops = match lat with
@@ -2280,7 +2274,7 @@ module CodeMotion = DataFlow(struct
 			in
 			in
 			{ eexpr = def; etype = t; epos = p }
 			{ eexpr = def; etype = t; epos = p }
 		in
 		in
-		let cache = ref IntMap.empty in
+		let cache = Hashtbl.create 0 in
 		let replace decl bb v =
 		let replace decl bb v =
 			let lat,t,p = get_cell v.v_id in
 			let lat,t,p = get_cell v.v_id in
 			match lat with
 			match lat with
@@ -2291,7 +2285,7 @@ module CodeMotion = DataFlow(struct
 				let lat = ((Binop(op,lat1,lat2)),t,p) in
 				let lat = ((Binop(op,lat1,lat2)),t,p) in
 				let bb_loop_pre = IntMap.find (List.hd loops) ctx.graph.g_loops in
 				let bb_loop_pre = IntMap.find (List.hd loops) ctx.graph.g_loops in
 				let v' = try
 				let v' = try
-					let l = IntMap.find bb_loop_pre.bb_id !cache in
+					let l = Hashtbl.find cache bb_loop_pre.bb_id in
 					snd (List.find (fun (lat',e) -> equals lat lat') l)
 					snd (List.find (fun (lat',e) -> equals lat lat') l)
 				with Not_found ->
 				with Not_found ->
 					let v' = if decl then begin
 					let v' = if decl then begin
@@ -2306,7 +2300,7 @@ module CodeMotion = DataFlow(struct
 					let e = mk (TVar(v',Some e)) ctx.com.basic.tvoid p in
 					let e = mk (TVar(v',Some e)) ctx.com.basic.tvoid p in
 					add_texpr ctx.graph bb_loop_pre e;
 					add_texpr ctx.graph bb_loop_pre e;
 					set_var_value ctx.graph v' bb_loop_pre false (DynArray.length bb_loop_pre.bb_el - 1);
 					set_var_value ctx.graph v' bb_loop_pre false (DynArray.length bb_loop_pre.bb_el - 1);
-					cache := IntMap.add bb_loop_pre.bb_id ((lat,v') :: try IntMap.find bb_loop_pre.bb_id !cache with Not_found -> []) !cache;
+					Hashtbl.replace cache bb_loop_pre.bb_id ((lat,v') :: try Hashtbl.find cache bb_loop_pre.bb_id with Not_found -> []);
 					v'
 					v'
 				in
 				in
 				let ev' = mk (TLocal v') v'.v_type p in
 				let ev' = mk (TLocal v') v'.v_type p in
@@ -2596,6 +2590,42 @@ module Debug = struct
 		| SENone ->
 		| SENone ->
 			()
 			()
 
 
+	let htmlescape s =
+		let s = String.concat "&amp;" (ExtString.String.nsplit s "&") in
+		let s = String.concat "&lt;" (ExtString.String.nsplit s "<") in
+		let s = String.concat "&gt;" (ExtString.String.nsplit s ">") in
+		s
+
+	let generate_cfg_ssa ch g =
+		Printf.fprintf ch "\tnode [shape=plaintext];\n";
+		let expr_name b i = Printf.sprintf "e%s%i" (if b then "p" else "") i in
+		Hashtbl.iter (fun _ bb ->
+			Printf.fprintf ch "n%i[label=<<table BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n\t<tr><td port=\"in\" bgcolor=\"lightgray\">(%i) %s</td></tr>\n" bb.bb_id bb.bb_id (BasicBlock.s_block_kind bb.bb_kind);
+			let s_expr b i e =
+				Printf.fprintf ch "\t<tr><td port=\"%s\" align=\"left\">%s</td></tr>\n" (expr_name b i) (s_escape (htmlescape (s_expr_pretty e)))
+			in
+			DynArray.iteri (s_expr true) bb.bb_phi;
+			DynArray.iteri (s_expr false) bb.bb_el;
+			Printf.fprintf ch "\t<tr><td port=\"out\"></td></tr>\n</table>>];\n";
+		) g.g_nodes;
+		Graph.iter_edges g (fun edge ->
+			Printf.fprintf ch "n%i:out -> n%i:in[label=\"%s\"];\n" edge.cfg_from.bb_id edge.cfg_to.bb_id (BasicBlock.s_cfg_edge_kind edge.cfg_kind)
+		);
+		DynArray.iter (fun vi ->
+			begin try
+				let (bb,is_phi,i) = match vi.vi_value with None -> raise Not_found | Some i -> i in
+				let n1 = Printf.sprintf "n%i:%s" bb.bb_id (expr_name is_phi i) in
+				List.iter (fun (bb',is_phi',i') ->
+					if bb != bb' then begin (* intra-node edges look stupid in dot *)
+						let n2 = Printf.sprintf "n%i:%s" bb'.bb_id (expr_name is_phi' i') in
+						Printf.fprintf ch "%s -> %s[color=lightblue,constraint=false];\n" n1 n2;
+					end
+				) vi.vi_ssa_edges;
+			with Not_found ->
+				()
+			end
+		) g.g_var_infos
+
 	let dot_debug ctx c cf =
 	let dot_debug ctx c cf =
 		let g = ctx.graph in
 		let g = ctx.graph in
 		let start_graph ?(graph_config=[]) suffix =
 		let start_graph ?(graph_config=[]) suffix =
@@ -2608,11 +2638,14 @@ module Debug = struct
 			)
 			)
 		in
 		in
 		let ch,f = start_graph "-cfg.dot" in
 		let ch,f = start_graph "-cfg.dot" in
-		IntMap.iter (fun _ bb -> dot_debug_node g ch [NILoopGroups;NIScopes;NIPhi;NIExpr] bb) g.g_nodes;
-		List.iter (dot_debug_cfg_edge ch) g.g_cfg_edges;
+		Hashtbl.iter (fun _ bb -> dot_debug_node g ch [NILoopGroups;NIScopes;NIPhi;NIExpr] bb) g.g_nodes;
+		Graph.iter_edges g (dot_debug_cfg_edge ch);
+		f();
+		let ch,f = start_graph "-cfg-ssa.dot" in
+		generate_cfg_ssa ch g;
 		f();
 		f();
 		let ch,f = start_graph "-dj.dot" in
 		let ch,f = start_graph "-dj.dot" in
-		IntMap.iter (fun _ bb ->
+		Hashtbl.iter (fun _ bb ->
 			dot_debug_node g ch [] bb;
 			dot_debug_node g ch [] bb;
 			List.iter (fun einc ->
 			List.iter (fun einc ->
 				let bb' = einc.cfg_from in
 				let bb' = einc.cfg_from in
@@ -2622,19 +2655,19 @@ module Debug = struct
 		) g.g_nodes;
 		) g.g_nodes;
 		f();
 		f();
 		let ch,f = start_graph "-df.dot" in
 		let ch,f = start_graph "-df.dot" in
-		IntMap.iter (fun _ bb ->
+		Hashtbl.iter (fun _ bb ->
 			dot_debug_node g ch [NIVars] bb;
 			dot_debug_node g ch [NIVars] bb;
 			List.iter (fun bb' -> Printf.fprintf ch "n%i -> n%i;\n" bb.bb_id bb'.bb_id) bb.bb_df;
 			List.iter (fun bb' -> Printf.fprintf ch "n%i -> n%i;\n" bb.bb_id bb'.bb_id) bb.bb_df;
 		) g.g_nodes;
 		) g.g_nodes;
 		f();
 		f();
 		let ch,f = start_graph "-dom.dot" in
 		let ch,f = start_graph "-dom.dot" in
-		IntMap.iter (fun _ bb ->
+		Hashtbl.iter (fun _ bb ->
 			dot_debug_node g ch [NIVars] bb;
 			dot_debug_node g ch [NIVars] bb;
 			List.iter (fun bb' -> Printf.fprintf ch "n%i -> n%i;\n" bb.bb_id bb'.bb_id) bb.bb_dominated;
 			List.iter (fun bb' -> Printf.fprintf ch "n%i -> n%i;\n" bb.bb_id bb'.bb_id) bb.bb_dominated;
 		) g.g_nodes;
 		) g.g_nodes;
 		f();
 		f();
 		let ch,f = start_graph "-syntax.dot" in
 		let ch,f = start_graph "-syntax.dot" in
-		IntMap.iter (fun _ bb ->
+		Hashtbl.iter (fun _ bb ->
 			dot_debug_node g ch [NIExpr] bb;
 			dot_debug_node g ch [NIExpr] bb;
 			dot_debug_syntax_edge ch bb bb.bb_syntax_edge
 			dot_debug_syntax_edge ch bb bb.bb_syntax_edge
 		) g.g_nodes;
 		) g.g_nodes;
@@ -2659,7 +2692,7 @@ module Debug = struct
 				()
 				()
 			end
 			end
 		) g.g_var_infos;
 		) g.g_var_infos;
-		IntMap.iter (fun _ bb ->
+		Hashtbl.iter (fun _ bb ->
 			let f is_phi acc i e =
 			let f is_phi acc i e =
 				let n = node_name bb is_phi i in
 				let n = node_name bb is_phi i in
 				(i + 1),if PMap.mem n !nodes then
 				(i + 1),if PMap.mem n !nodes then