Browse Source

[analyzer] add bb_terminator

Simon Krajewski 4 years ago
parent
commit
dc6fc34024

+ 59 - 45
src/optimization/analyzer.ml

@@ -126,13 +126,13 @@ module Ssa = struct
 					else match e.eexpr with
 					else match e.eexpr with
 					| TLocal v ->
 					| TLocal v ->
 						let v' = local ctx e v edge.cfg_from in
 						let v' = local ctx e v edge.cfg_from in
-						add_ssa_edge ctx.graph v' bb true i;
+						add_ssa_edge ctx.graph v' bb (LUPhi i);
 						{e with eexpr = TLocal v'}
 						{e with eexpr = TLocal v'}
 					| _ ->
 					| _ ->
 						die "" __LOC__
 						die "" __LOC__
 				) el edge.cfg_to.bb_incoming in
 				) el edge.cfg_to.bb_incoming in
 				let ephi = {ecall with eexpr = TCall(ephi,el)} in
 				let ephi = {ecall with eexpr = TCall(ephi,el)} in
-				set_var_value ctx.graph v0 bb true i;
+				set_var_value ctx.graph v0 bb (LUPhi i);
 				{e with eexpr = TBinop(OpAssign,e1,ephi)}
 				{e with eexpr = TBinop(OpAssign,e1,ephi)}
 			| _ ->
 			| _ ->
 				Type.map_expr (loop i) e
 				Type.map_expr (loop i) e
@@ -140,7 +140,7 @@ module Ssa = struct
 		dynarray_mapi loop bb.bb_phi
 		dynarray_mapi loop bb.bb_phi
 
 
 	let rec rename_in_block ctx bb =
 	let rec rename_in_block ctx bb =
-		let write_var v is_phi i =
+		let write_var v luk =
 			update_reaching_def ctx v bb;
 			update_reaching_def ctx v bb;
 			let v' = alloc_var v.v_kind v.v_name v.v_type v.v_pos in
 			let v' = alloc_var v.v_kind v.v_name v.v_type v.v_pos in
 			declare_var ctx.graph v' bb;
 			declare_var ctx.graph v' bb;
@@ -149,30 +149,31 @@ module Ssa = struct
 			add_var_def ctx.graph bb v';
 			add_var_def ctx.graph bb v';
 			set_reaching_def ctx.graph v' (get_reaching_def ctx.graph v);
 			set_reaching_def ctx.graph v' (get_reaching_def ctx.graph v);
 			set_reaching_def ctx.graph v (Some v');
 			set_reaching_def ctx.graph v (Some v');
-			set_var_value ctx.graph v' bb is_phi i;
+			set_var_value ctx.graph v' bb luk;
 			add_var_origin ctx.graph v' v;
 			add_var_origin ctx.graph v' v;
 			v'
 			v'
 		in
 		in
-		let rec loop is_phi i e = match e.eexpr with
+		let rec loop luk e = match e.eexpr with
 			| TLocal v ->
 			| TLocal v ->
 				let v' = local ctx e v bb in
 				let v' = local ctx e v bb in
-				add_ssa_edge ctx.graph v' bb is_phi i;
+				add_ssa_edge ctx.graph v' bb luk;
 				{e with eexpr = TLocal v'}
 				{e with eexpr = TLocal v'}
 			| TVar(v,Some e1) ->
 			| TVar(v,Some e1) ->
-				let e1 = (loop is_phi i) e1 in
-				let v' = write_var v is_phi i in
+				let e1 = (loop luk) e1 in
+				let v' = write_var v luk in
 				{e with eexpr = TVar(v',Some e1)}
 				{e with eexpr = TVar(v',Some e1)}
 			| TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
 			| TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
-				let e2 = (loop is_phi i) e2 in
-				let v' = write_var v is_phi i in
+				let e2 = (loop luk) e2 in
+				let v' = write_var v luk in
 				{e with eexpr = TBinop(OpAssign,{e1 with eexpr = TLocal v'},e2)};
 				{e with eexpr = TBinop(OpAssign,{e1 with eexpr = TLocal v'},e2)};
 			| TCall({eexpr = TConst (TString "phi")},_) ->
 			| TCall({eexpr = TConst (TString "phi")},_) ->
 				e
 				e
 			| _ ->
 			| _ ->
-				Type.map_expr (loop is_phi i) e
+				Type.map_expr (loop luk) e
 		in
 		in
-		dynarray_mapi (loop true) bb.bb_phi;
-		dynarray_mapi (loop false) bb.bb_el;
+		dynarray_mapi (fun i e -> loop (LUPhi i) e) bb.bb_phi;
+		dynarray_mapi (fun i e -> loop (LUEl i) e) bb.bb_el;
+		bb.bb_terminator <- BasicBlock.terminator_map (loop LUTerm) bb.bb_terminator;
 		List.iter (update_phi ctx) bb.bb_outgoing;
 		List.iter (update_phi ctx) bb.bb_outgoing;
 		List.iter (rename_in_block ctx) bb.bb_dominated
 		List.iter (rename_in_block ctx) bb.bb_dominated
 
 
@@ -253,13 +254,13 @@ module DataFlow (M : DataFlowApi) = struct
 				if List.exists (fun edge -> has_flag edge M.flag) bb.bb_incoming then
 				if List.exists (fun edge -> has_flag edge M.flag) bb.bb_incoming then
 					set_lattice_cell v (M.transfer ctx bb e)
 					set_lattice_cell v (M.transfer ctx bb e)
 		in
 		in
-		let visit_expression bb e =
+		let visit_expression bb cond_branch e =
 			match e.eexpr with
 			match e.eexpr with
 			| TBinop(OpAssign,{eexpr = TLocal v},e2) | TVar(v,Some e2) ->
 			| TBinop(OpAssign,{eexpr = TLocal v},e2) | TVar(v,Some e2) ->
 				visit_assignment bb v e2;
 				visit_assignment bb v e2;
 				false
 				false
-			| TMeta((Meta.Custom ":cond-branch",_,_),e1) when M.conditional ->
-				let e1 = M.transfer ctx bb e1 in
+			| _ when M.conditional && cond_branch ->
+				let e1 = M.transfer ctx bb e in
 				let edges = if e1 == M.bottom || e1 == M.top then
 				let edges = if e1 == M.bottom || e1 == M.top then
 					bb.bb_outgoing
 					bb.bb_outgoing
 				else begin
 				else begin
@@ -293,8 +294,17 @@ module DataFlow (M : DataFlowApi) = struct
 		in
 		in
 		let visit_expressions bb =
 		let visit_expressions bb =
 			let b = DynArray.fold_left (fun b e ->
 			let b = DynArray.fold_left (fun b e ->
-				visit_expression bb e || b
+				visit_expression bb false e || b
 			) false bb.bb_el in
 			) false bb.bb_el in
+			let b = match bb.bb_terminator with
+			| TermCondBranch e1 ->
+				visit_expression bb true e1 || b
+			| TermReturnValue(e1,_)
+			| TermThrow(e1,_) ->
+				visit_expression bb false e1
+			| _ ->
+				b
+			in
 			if not b then List.iter add_cfg_edge bb.bb_outgoing
 			if not b then List.iter add_cfg_edge bb.bb_outgoing
 		in
 		in
 		let visit_phis bb =
 		let visit_phis bb =
@@ -320,10 +330,10 @@ module DataFlow (M : DataFlowApi) = struct
 					end
 					end
 				end;
 				end;
 				loop();
 				loop();
-			| [],((bb,is_phi,i) :: edges) ->
+			| [],((bb,luk) :: edges) ->
 				ssa_work_list := edges;
 				ssa_work_list := edges;
-				let e = get_texpr bb is_phi i in
-				ignore(visit_expression bb e);
+				let e = get_texpr bb luk in
+				ignore(visit_expression bb (match luk with LUTerm -> true | _ -> false) e);
 				loop()
 				loop()
 			| [],[] ->
 			| [],[] ->
 				()
 				()
@@ -510,7 +520,8 @@ module ConstPropagation = DataFlow(struct
 		in
 		in
 		Graph.iter_dom_tree ctx.graph (fun bb ->
 		Graph.iter_dom_tree ctx.graph (fun bb ->
 			if not (List.exists (fun edge -> has_flag edge FlagExecutable) bb.bb_incoming) then bb.bb_dominator <- ctx.graph.Graph.g_unreachable;
 			if not (List.exists (fun edge -> has_flag edge FlagExecutable) bb.bb_incoming) then bb.bb_dominator <- ctx.graph.Graph.g_unreachable;
-			dynarray_map commit bb.bb_el
+			dynarray_map commit bb.bb_el;
+			bb.bb_terminator <- terminator_map commit bb.bb_terminator;
 		);
 		);
 end)
 end)
 
 
@@ -606,7 +617,8 @@ module CopyPropagation = DataFlow(struct
 				Type.map_expr (commit bb) e
 				Type.map_expr (commit bb) e
 		in
 		in
 		Graph.iter_dom_tree ctx.graph (fun bb ->
 		Graph.iter_dom_tree ctx.graph (fun bb ->
-			dynarray_map (commit bb) bb.bb_el
+			dynarray_map (commit bb) bb.bb_el;
+			bb.bb_terminator <- terminator_map (commit bb) bb.bb_terminator;
 		);
 		);
 end)
 end)
 
 
@@ -677,6 +689,7 @@ module LocalDce = struct
 			bb_marked := bb :: !bb_marked;
 			bb_marked := bb :: !bb_marked;
 			DynArray.iter expr bb.bb_el;
 			DynArray.iter expr bb.bb_el;
 			DynArray.iter expr bb.bb_phi;
 			DynArray.iter expr bb.bb_phi;
+			terminator_iter expr bb.bb_terminator;
 			List.iter (fun edge ->
 			List.iter (fun edge ->
 				if not (has_flag edge FlagDce) then begin
 				if not (has_flag edge FlagDce) then begin
 					edge.cfg_flags <- FlagDce :: edge.cfg_flags;
 					edge.cfg_flags <- FlagDce :: edge.cfg_flags;
@@ -698,7 +711,8 @@ module LocalDce = struct
 				Type.map_expr sweep e
 				Type.map_expr sweep e
 		in
 		in
 		List.iter (fun bb ->
 		List.iter (fun bb ->
-			dynarray_map sweep bb.bb_el
+			dynarray_map sweep bb.bb_el;
+			bb.bb_terminator <- terminator_map sweep bb.bb_terminator;
 		) !bb_marked;
 		) !bb_marked;
 end
 end
 
 
@@ -767,7 +781,7 @@ module Debug = struct
 			edge bb_then "then";
 			edge bb_then "then";
 			edge bb_else "else";
 			edge bb_else "else";
 			edge bb_next "next";
 			edge bb_next "next";
-		| SEWhile(bb_head,bb_body,bb_next) ->
+		| SEWhile(bb_head,bb_body,bb_next,_) ->
 			edge bb_head "loop-head";
 			edge bb_head "loop-head";
 			edge bb_body "loop-body";
 			edge bb_body "loop-body";
 			edge bb_next "next";
 			edge bb_next "next";
@@ -792,14 +806,14 @@ module Debug = struct
 
 
 	let generate_cfg_ssa ch g =
 	let generate_cfg_ssa ch g =
 		Printf.fprintf ch "\tnode [shape=plaintext];\n";
 		Printf.fprintf ch "\tnode [shape=plaintext];\n";
-		let expr_name b i = Printf.sprintf "e%s%i" (if b then "p" else "") i in
+		let expr_name luk = Printf.sprintf "e%s" (match luk with | LUPhi i -> Printf.sprintf "p%i" i | LUEl i -> Printf.sprintf "%i" i | LUTerm -> "t") in
 		List.iter (fun bb ->
 		List.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);
 			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)))
+			let s_expr luk e =
+				Printf.fprintf ch "\t<tr><td port=\"%s\" align=\"left\">%s</td></tr>\n" (expr_name luk) (s_escape (htmlescape (s_expr_pretty e)))
 			in
 			in
-			DynArray.iteri (s_expr true) bb.bb_phi;
-			DynArray.iteri (s_expr false) bb.bb_el;
+			DynArray.iteri (fun i e -> s_expr (LUPhi i) e) bb.bb_phi;
+			DynArray.iteri (fun i e -> s_expr (LUEl i) e) bb.bb_el;
 			Printf.fprintf ch "\t<tr><td port=\"out\"></td></tr>\n</table>>];\n";
 			Printf.fprintf ch "\t<tr><td port=\"out\"></td></tr>\n</table>>];\n";
 		) g.g_nodes;
 		) g.g_nodes;
 		Graph.iter_edges g (fun edge ->
 		Graph.iter_edges g (fun edge ->
@@ -807,11 +821,11 @@ module Debug = struct
 		);
 		);
 		DynArray.iter (fun vi ->
 		DynArray.iter (fun vi ->
 			begin try
 			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') ->
+				let (bb,luk) = 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 luk) in
+				List.iter (fun (bb',luk') ->
 					if bb != bb' then begin (* intra-node edges look stupid in dot *)
 					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
+						let n2 = Printf.sprintf "n%i:%s" bb'.bb_id (expr_name luk') in
 						Printf.fprintf ch "%s -> %s[color=lightblue,constraint=false];\n" n1 n2;
 						Printf.fprintf ch "%s -> %s[color=lightblue,constraint=false];\n" n1 n2;
 					end
 					end
 				) vi.vi_ssa_edges;
 				) vi.vi_ssa_edges;
@@ -871,18 +885,18 @@ module Debug = struct
 		f();
 		f();
 		let ch,f = start_graph "-ssa-edges.dot" in
 		let ch,f = start_graph "-ssa-edges.dot" in
 		let nodes = ref PMap.empty in
 		let nodes = ref PMap.empty in
-		let node_name bb is_phi i = Printf.sprintf "e%i_%b_%i" bb.bb_id is_phi i in
-		let node_name2 bb is_phi i =
-			let n = node_name bb is_phi i in
+		let node_name bb luk = Printf.sprintf "e%i_%s" bb.bb_id (match luk with LUPhi i -> Printf.sprintf "phi_%i" i | LUEl i -> Printf.sprintf "el%i" i | LUTerm -> "term") in
+		let node_name2 bb luk =
+			let n = node_name bb luk in
 			nodes := PMap.add n true !nodes;
 			nodes := PMap.add n true !nodes;
 			n
 			n
 		in
 		in
 		DynArray.iter (fun vi ->
 		DynArray.iter (fun vi ->
 			begin try
 			begin try
-				let (bb,is_phi,i) = match vi.vi_value with None -> raise Not_found | Some i -> i in
-				let n1 = node_name2 bb is_phi i in
-				List.iter (fun (bb',is_phi',i') ->
-					let n2 = node_name2 bb' is_phi' i' in
+				let (bb,luk) = match vi.vi_value with None -> raise Not_found | Some i -> i in
+				let n1 = node_name2 bb luk in
+				List.iter (fun (bb',luk') ->
+					let n2 = node_name2 bb' luk' in
 					Printf.fprintf ch "%s -> %s;\n" n1 n2
 					Printf.fprintf ch "%s -> %s;\n" n1 n2
 				) vi.vi_ssa_edges
 				) vi.vi_ssa_edges
 			with Not_found ->
 			with Not_found ->
@@ -890,15 +904,15 @@ module Debug = struct
 			end
 			end
 		) g.g_var_infos;
 		) g.g_var_infos;
 		List.iter (fun bb ->
 		List.iter (fun bb ->
-			let f is_phi acc i e =
-				let n = node_name bb is_phi i in
-				(i + 1),if PMap.mem n !nodes then
+			let f luk acc e =
+				let n = node_name bb luk in
+				if PMap.mem n !nodes then
 					(n,s_expr_pretty e) :: acc
 					(n,s_expr_pretty e) :: acc
 				else
 				else
 					acc
 					acc
 			in
 			in
-			let _,active_nodes = DynArray.fold_left (fun (i,acc) -> f true acc i) (0,[]) bb.bb_phi in
-			let _,active_nodes = DynArray.fold_left (fun (i,acc) -> f false acc i) (0,active_nodes) bb.bb_el in
+			let _,active_nodes = DynArray.fold_left (fun (i,acc) e -> (i + 1),f (LUPhi i) acc e) (0,[]) bb.bb_phi in
+			let _,active_nodes = DynArray.fold_left (fun (i,acc) e -> (i + 1),f (LUEl i) acc e) (0,active_nodes) bb.bb_el in
 			if active_nodes <> [] then begin
 			if active_nodes <> [] then begin
 				Printf.fprintf ch "subgraph cluster_%i {\n" bb.bb_id;
 				Printf.fprintf ch "subgraph cluster_%i {\n" bb.bb_id;
 				Printf.fprintf ch "label=%i;\n" bb.bb_id;
 				Printf.fprintf ch "label=%i;\n" bb.bb_id;

+ 72 - 62
src/optimization/analyzerTexprTransformer.ml

@@ -46,10 +46,6 @@ let rec func ctx bb tf t p =
 	let bb_exit = create_node BKFunctionEnd tf.tf_expr.etype tf.tf_expr.epos in
 	let bb_exit = create_node BKFunctionEnd tf.tf_expr.etype tf.tf_expr.epos in
 	add_function g tf t p bb_root;
 	add_function g tf t p bb_root;
 	add_cfg_edge bb bb_root CFGFunction;
 	add_cfg_edge bb bb_root CFGFunction;
-	let make_block_meta b =
-		let e = mk (TConst (TInt (Int32.of_int b.bb_id))) ctx.com.basic.tint b.bb_pos in
-		wrap_meta ":block" e
-	in
 	let bb_breaks = ref [] in
 	let bb_breaks = ref [] in
 	let bb_continue = ref None in
 	let bb_continue = ref None in
 	let b_try_stack = ref [] in
 	let b_try_stack = ref [] in
@@ -76,9 +72,9 @@ let rec func ctx bb tf t p =
 			b_try_stack := List.tl !b_try_stack
 			b_try_stack := List.tl !b_try_stack
 		)
 		)
 	in
 	in
-	let add_terminator bb e =
-		add_texpr bb e;
-		close_node g bb;
+	let add_terminator bb term =
+		bb.bb_terminator <- term;
+		close_node bb;
 		g.g_unreachable
 		g.g_unreachable
 	in
 	in
 	let check_unbound_call s el =
 	let check_unbound_call s el =
@@ -170,7 +166,7 @@ let rec func ctx bb tf t p =
 			let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 			let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 			add_cfg_edge bb bb_next CFGGoto;
 			add_cfg_edge bb bb_next CFGGoto;
 			set_syntax_edge bb (SEMerge bb_next);
 			set_syntax_edge bb (SEMerge bb_next);
-			close_node g bb;
+			close_node bb;
 			add_cfg_edge bb_func_end bb_next CFGGoto;
 			add_cfg_edge bb_func_end bb_next CFGGoto;
 			bb_next,ec
 			bb_next,ec
 		| TConst _ | TTypeExpr _ ->
 		| TConst _ | TTypeExpr _ ->
@@ -371,17 +367,17 @@ let rec func ctx bb tf t p =
 		| TBlock el ->
 		| TBlock el ->
 			let bb_sub = create_node BKSub e.etype e.epos in
 			let bb_sub = create_node BKSub e.etype e.epos in
 			add_cfg_edge bb bb_sub CFGGoto;
 			add_cfg_edge bb bb_sub CFGGoto;
-			close_node g bb;
+			close_node bb;
 			let bb_sub_next = block_el bb_sub el in
 			let bb_sub_next = block_el bb_sub el in
 			if bb_sub_next != g.g_unreachable then begin
 			if bb_sub_next != g.g_unreachable then begin
 				let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 				let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 				set_syntax_edge bb (SESubBlock(bb_sub,bb_next));
 				set_syntax_edge bb (SESubBlock(bb_sub,bb_next));
 				add_cfg_edge bb_sub_next bb_next CFGGoto;
 				add_cfg_edge bb_sub_next bb_next CFGGoto;
-				close_node g bb_sub_next;
+				close_node bb_sub_next;
 				bb_next;
 				bb_next;
 			end else begin
 			end else begin
 				set_syntax_edge bb (SEMerge bb_sub);
 				set_syntax_edge bb (SEMerge bb_sub);
-				close_node g bb_sub_next;
+				close_node bb_sub_next;
 				bb_sub_next
 				bb_sub_next
 			end
 			end
 		| TIf(e1,e2,None) ->
 		| TIf(e1,e2,None) ->
@@ -390,15 +386,15 @@ let rec func ctx bb tf t p =
 				bb
 				bb
 			else begin
 			else begin
 				let bb_then = create_node BKConditional e2.etype e2.epos in
 				let bb_then = create_node BKConditional e2.etype e2.epos in
-				add_texpr bb (wrap_meta ":cond-branch" e1);
+				bb.bb_terminator <- TermCondBranch e1;
 				add_cfg_edge bb bb_then (CFGCondBranch (mk (TConst (TBool true)) ctx.com.basic.tbool e2.epos));
 				add_cfg_edge bb bb_then (CFGCondBranch (mk (TConst (TBool true)) ctx.com.basic.tbool e2.epos));
 				let bb_then_next = block bb_then e2 in
 				let bb_then_next = block bb_then e2 in
 				let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 				let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 				set_syntax_edge bb (SEIfThen(bb_then,bb_next,e.epos));
 				set_syntax_edge bb (SEIfThen(bb_then,bb_next,e.epos));
 				add_cfg_edge bb bb_next CFGCondElse;
 				add_cfg_edge bb bb_next CFGCondElse;
-				close_node g bb;
+				close_node bb;
 				add_cfg_edge bb_then_next bb_next CFGGoto;
 				add_cfg_edge bb_then_next bb_next CFGGoto;
-				close_node g bb_then_next;
+				close_node bb_then_next;
 				bb_next
 				bb_next
 			end
 			end
 		| TIf(e1,e2,Some e3) ->
 		| TIf(e1,e2,Some e3) ->
@@ -408,10 +404,10 @@ let rec func ctx bb tf t p =
 			else begin
 			else begin
 				let bb_then = create_node BKConditional e2.etype e2.epos in
 				let bb_then = create_node BKConditional e2.etype e2.epos in
 				let bb_else = create_node BKConditional e3.etype e3.epos in
 				let bb_else = create_node BKConditional e3.etype e3.epos in
-				add_texpr bb (wrap_meta ":cond-branch" e1);
+				bb.bb_terminator <- TermCondBranch e1;
 				add_cfg_edge bb bb_then (CFGCondBranch (mk (TConst (TBool true)) ctx.com.basic.tbool e2.epos));
 				add_cfg_edge bb bb_then (CFGCondBranch (mk (TConst (TBool true)) ctx.com.basic.tbool e2.epos));
 				add_cfg_edge bb bb_else CFGCondElse;
 				add_cfg_edge bb bb_else CFGCondElse;
-				close_node g bb;
+				close_node bb;
 				let bb_then_next = block bb_then e2 in
 				let bb_then_next = block bb_then e2 in
 				let bb_else_next = block bb_else e3 in
 				let bb_else_next = block bb_else e3 in
 				if bb_then_next == g.g_unreachable && bb_else_next == g.g_unreachable then begin
 				if bb_then_next == g.g_unreachable && bb_else_next == g.g_unreachable then begin
@@ -422,22 +418,22 @@ let rec func ctx bb tf t p =
 					set_syntax_edge bb (SEIfThenElse(bb_then,bb_else,bb_next,e.etype,e.epos));
 					set_syntax_edge bb (SEIfThenElse(bb_then,bb_else,bb_next,e.etype,e.epos));
 					add_cfg_edge bb_then_next bb_next CFGGoto;
 					add_cfg_edge bb_then_next bb_next CFGGoto;
 					add_cfg_edge bb_else_next bb_next CFGGoto;
 					add_cfg_edge bb_else_next bb_next CFGGoto;
-					close_node g bb_then_next;
-					close_node g bb_else_next;
+					close_node bb_then_next;
+					close_node bb_else_next;
 					bb_next
 					bb_next
 				end
 				end
 			end
 			end
 		| TSwitch(e1,cases,edef) ->
 		| TSwitch(e1,cases,edef) ->
 			let is_exhaustive = edef <> None || is_exhaustive e1 in
 			let is_exhaustive = edef <> None || is_exhaustive e1 in
 			let bb,e1 = bind_to_temp bb false e1 in
 			let bb,e1 = bind_to_temp bb false e1 in
-			add_texpr bb (wrap_meta ":cond-branch" e1);
+			bb.bb_terminator <- TermCondBranch e1;
 			let reachable = ref [] in
 			let reachable = ref [] in
 			let make_case e =
 			let make_case e =
 				let bb_case = create_node BKConditional e.etype e.epos in
 				let bb_case = create_node BKConditional e.etype e.epos in
 				let bb_case_next = block bb_case e in
 				let bb_case_next = block bb_case e in
 				if bb_case_next != g.g_unreachable then
 				if bb_case_next != g.g_unreachable then
 					reachable := bb_case_next :: !reachable;
 					reachable := bb_case_next :: !reachable;
-				close_node g bb_case_next;
+				close_node bb_case_next;
 				bb_case
 				bb_case
 			in
 			in
 			let cases = List.map (fun (el,e) ->
 			let cases = List.map (fun (el,e) ->
@@ -455,21 +451,21 @@ let rec func ctx bb tf t p =
 			in
 			in
 			if is_exhaustive && !reachable = [] then begin
 			if is_exhaustive && !reachable = [] then begin
 				set_syntax_edge bb (SESwitch(cases,def,g.g_unreachable,e.epos));
 				set_syntax_edge bb (SESwitch(cases,def,g.g_unreachable,e.epos));
-				close_node g bb;
+				close_node bb;
 				g.g_unreachable;
 				g.g_unreachable;
 			end else begin
 			end else begin
 				let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 				let bb_next = create_node BKNormal bb.bb_type bb.bb_pos in
 				if not is_exhaustive then add_cfg_edge bb bb_next CFGGoto;
 				if not is_exhaustive then add_cfg_edge bb bb_next CFGGoto;
 				List.iter (fun bb -> add_cfg_edge bb bb_next CFGGoto) !reachable;
 				List.iter (fun bb -> add_cfg_edge bb bb_next CFGGoto) !reachable;
 				set_syntax_edge bb (SESwitch(cases,def,bb_next,e.epos));
 				set_syntax_edge bb (SESwitch(cases,def,bb_next,e.epos));
-				close_node g bb;
+				close_node bb;
 				bb_next
 				bb_next
 			end
 			end
 		| TWhile(e1,e2,NormalWhile) ->
 		| TWhile(e1,e2,NormalWhile) ->
 			let bb_loop_pre = create_node BKNormal e1.etype e1.epos in
 			let bb_loop_pre = create_node BKNormal e1.etype e1.epos in
 			add_cfg_edge bb bb_loop_pre CFGGoto;
 			add_cfg_edge bb bb_loop_pre CFGGoto;
 			set_syntax_edge bb (SEMerge bb_loop_pre);
 			set_syntax_edge bb (SEMerge bb_loop_pre);
-			close_node g bb;
+			close_node bb;
 			let bb_loop_head = create_node BKLoopHead e1.etype e1.epos in
 			let bb_loop_head = create_node BKLoopHead e1.etype e1.epos in
 			add_cfg_edge bb_loop_pre bb_loop_head CFGGoto;
 			add_cfg_edge bb_loop_pre bb_loop_head CFGGoto;
 			let close = begin_loop bb bb_loop_head in
 			let close = begin_loop bb bb_loop_head in
@@ -485,13 +481,13 @@ let rec func ctx bb tf t p =
 				create_node BKNormal bb.bb_type bb.bb_pos
 				create_node BKNormal bb.bb_type bb.bb_pos
 			in
 			in
 			List.iter (fun bb -> add_cfg_edge bb bb_next CFGGoto) bb_breaks;
 			List.iter (fun bb -> add_cfg_edge bb bb_next CFGGoto) bb_breaks;
-			set_syntax_edge bb_loop_pre (SEWhile(bb_loop_head,bb_loop_body,bb_next));
-			close_node g bb_loop_pre;
-			add_texpr bb_loop_pre {e with eexpr = TWhile(e1,make_block_meta bb_loop_body,NormalWhile)};
+			set_syntax_edge bb_loop_pre (SEWhile(bb_loop_head,bb_loop_body,bb_next,e.epos));
+			close_node bb_loop_pre;
+			bb_loop_pre.bb_terminator <- TermCondBranch e1;
 			if bb_loop_body_next != g.g_unreachable then add_cfg_edge bb_loop_body_next bb_loop_head CFGGoto;
 			if bb_loop_body_next != g.g_unreachable then add_cfg_edge bb_loop_body_next bb_loop_head CFGGoto;
 			add_cfg_edge bb_loop_head bb_loop_body CFGGoto;
 			add_cfg_edge bb_loop_head bb_loop_body CFGGoto;
-			close_node g bb_loop_body_next;
-			close_node g bb_loop_head;
+			close_node bb_loop_body_next;
+			close_node bb_loop_head;
 			bb_next;
 			bb_next;
 		| TTry(e1,catches) ->
 		| TTry(e1,catches) ->
 			let bb_try = create_node BKNormal e1.etype e1.epos in
 			let bb_try = create_node BKNormal e1.etype e1.epos in
@@ -513,19 +509,19 @@ let rec func ctx bb tf t p =
 			let bb_next = if !is_reachable then create_node BKNormal bb.bb_type bb.bb_pos else g.g_unreachable in
 			let bb_next = if !is_reachable then create_node BKNormal bb.bb_type bb.bb_pos else g.g_unreachable in
 			let catches = List.map (fun (v,bb_catch,bb_catch_next) ->
 			let catches = List.map (fun (v,bb_catch,bb_catch_next) ->
 				if bb_catch_next != g.g_unreachable then add_cfg_edge bb_catch_next bb_next CFGGoto;
 				if bb_catch_next != g.g_unreachable then add_cfg_edge bb_catch_next bb_next CFGGoto;
-				close_node g bb_catch_next;
+				close_node bb_catch_next;
 				v,bb_catch
 				v,bb_catch
 			) catches in
 			) catches in
 			set_syntax_edge bb (SETry(bb_try,bb_exc,catches,bb_next,e.epos));
 			set_syntax_edge bb (SETry(bb_try,bb_exc,catches,bb_next,e.epos));
 			if bb_try_next != g.g_unreachable then add_cfg_edge bb_try_next bb_next CFGGoto;
 			if bb_try_next != g.g_unreachable then add_cfg_edge bb_try_next bb_next CFGGoto;
-			close_node g bb_try_next;
-			close_node g bb_exc;
-			close_node g bb;
+			close_node bb_try_next;
+			close_node bb_exc;
+			close_node bb;
 			bb_next
 			bb_next
 		(* control flow *)
 		(* control flow *)
 		| TReturn None ->
 		| TReturn None ->
 			add_cfg_edge bb bb_exit CFGGoto;
 			add_cfg_edge bb bb_exit CFGGoto;
-			add_terminator bb e
+			add_terminator bb (TermReturn e.epos)
 		| TReturn (Some e1) when ExtType.is_void (follow e1.etype) ->
 		| TReturn (Some e1) when ExtType.is_void (follow e1.etype) ->
 			let bb = block_element bb e1 in
 			let bb = block_element bb e1 in
 			block_element bb (mk (TReturn None) t_dynamic e.epos)
 			block_element bb (mk (TReturn None) t_dynamic e.epos)
@@ -536,17 +532,17 @@ let rec func ctx bb tf t p =
 			with Exit ->
 			with Exit ->
 				let bb,e1 = value bb e1 in
 				let bb,e1 = value bb e1 in
 				add_cfg_edge bb bb_exit CFGGoto;
 				add_cfg_edge bb bb_exit CFGGoto;
-				add_terminator bb {e with eexpr = TReturn(Some e1)};
+				add_terminator bb (TermReturnValue(e1,e.epos))
 			end
 			end
 		| TBreak ->
 		| TBreak ->
 			bb_breaks := bb :: !bb_breaks;
 			bb_breaks := bb :: !bb_breaks;
-			add_terminator bb e
+			add_terminator bb (TermBreak e.epos)
 		| TContinue ->
 		| TContinue ->
 			begin match !bb_continue with
 			begin match !bb_continue with
 				| Some bb_continue -> add_cfg_edge bb bb_continue CFGGoto
 				| Some bb_continue -> add_cfg_edge bb bb_continue CFGGoto
 				| _ -> die "" __LOC__
 				| _ -> die "" __LOC__
 			end;
 			end;
-			add_terminator bb e
+			add_terminator bb (TermContinue e.epos)
 		| TThrow e1 ->
 		| TThrow e1 ->
 			begin try
 			begin try
 				let mk_throw e1 =
 				let mk_throw e1 =
@@ -559,7 +555,7 @@ let rec func ctx bb tf t p =
 					| [] -> add_cfg_edge bb bb_exit CFGGoto
 					| [] -> add_cfg_edge bb bb_exit CFGGoto
 					| _ -> List.iter (fun bb_exc -> add_cfg_edge bb bb_exc CFGGoto) !b_try_stack;
 					| _ -> List.iter (fun bb_exc -> add_cfg_edge bb bb_exc CFGGoto) !b_try_stack;
 				end;
 				end;
-				add_terminator bb {e with eexpr = TThrow e1};
+				add_terminator bb (TermThrow(e1,e.epos))
 			end
 			end
 		(* side_effects *)
 		(* side_effects *)
 		| TCall({eexpr = TIdent s},el) when is_really_unbound s ->
 		| TCall({eexpr = TIdent s},el) when is_really_unbound s ->
@@ -643,7 +639,7 @@ let rec func ctx bb tf t p =
 						add_cfg_edge bb bb' CFGGoto;
 						add_cfg_edge bb bb' CFGGoto;
 						List.iter (fun bb_exc -> add_cfg_edge bb bb_exc CFGMaybeThrow) bbl;
 						List.iter (fun bb_exc -> add_cfg_edge bb bb_exc CFGMaybeThrow) bbl;
 						set_syntax_edge bb (SEMerge bb');
 						set_syntax_edge bb (SEMerge bb');
-						close_node g bb;
+						close_node bb;
 						block_element bb' e
 						block_element bb' e
 					end in
 					end in
 					if bb == g.g_unreachable then bb else loop bb el
 					if bb == g.g_unreachable then bb else loop bb el
@@ -657,53 +653,67 @@ let rec func ctx bb tf t p =
 		block_el bb el
 		block_el bb el
 	in
 	in
 	let bb_last = block bb_root tf.tf_expr in
 	let bb_last = block bb_root tf.tf_expr in
-	close_node g bb_last;
+	close_node bb_last;
 	add_cfg_edge bb_last bb_exit CFGGoto; (* implied return *)
 	add_cfg_edge bb_last bb_exit CFGGoto; (* implied return *)
-	close_node g bb_exit;
+	close_node bb_exit;
 	bb_root,bb_exit
 	bb_root,bb_exit
 
 
 let from_tfunction ctx tf t p =
 let from_tfunction ctx tf t p =
 	let g = ctx.graph in
 	let g = ctx.graph in
 	let bb_func,bb_exit = func ctx g.g_root tf t p in
 	let bb_func,bb_exit = func ctx g.g_root tf t p in
 	ctx.entry <- bb_func;
 	ctx.entry <- bb_func;
-	close_node g g.g_root;
+	close_node g.g_root;
 	g.g_exit <- bb_exit
 	g.g_exit <- bb_exit
 
 
+let terminator_to_texpr_maybe = function
+	| TermReturn p -> Some (mk (TReturn None) t_dynamic p)
+	| TermBreak p -> Some (mk TBreak t_dynamic p)
+	| TermContinue p -> Some (mk TContinue t_dynamic p)
+	| TermReturnValue(e1,p) -> Some (mk (TReturn (Some e1)) t_dynamic p)
+	| TermThrow(e1,p) -> Some (mk (TThrow e1) t_dynamic p)
+	| TermCondBranch e1 -> Some e1 (* TODO: this shouldn't be here *)
+	| _ -> None
+
 let rec block_to_texpr_el ctx bb =
 let rec block_to_texpr_el ctx bb =
 	if bb.bb_dominator == ctx.graph.g_unreachable then
 	if bb.bb_dominator == ctx.graph.g_unreachable then
 		[]
 		[]
 	else begin
 	else begin
 		let block bb = block_to_texpr ctx bb in
 		let block bb = block_to_texpr ctx bb in
 		let rec loop bb se =
 		let rec loop bb se =
-			let el = List.rev (DynArray.to_list bb.bb_el) in
-			match el,se with
-			| el,SESubBlock(bb_sub,bb_next) ->
-				Some bb_next,(block bb_sub) :: el
-			| el,SEMerge bb_next ->
-				Some bb_next,el
-			| el,SENone ->
-				None,el
-			| {eexpr = TWhile(e1,_,flag)} as e :: el,(SEWhile(_,bb_body,bb_next)) ->
-				let e2 = block bb_body in
-				Some bb_next,{e with eexpr = TWhile(e1,e2,flag)} :: el
-			| el,SETry(bb_try,_,bbl,bb_next,p) ->
-				Some bb_next,(mk (TTry(block bb_try,List.map (fun (v,bb) -> v,block bb) bbl)) ctx.com.basic.tvoid p) :: el
-			| e1 :: el,se ->
-				let e1 = Texpr.skip e1 in
+			match se with
+			| SESubBlock(bb_sub,bb_next) ->
+				Some bb_next,Some (block bb_sub)
+			| SEMerge bb_next ->
+				Some bb_next,None
+			| SENone ->
+				None,terminator_to_texpr_maybe bb.bb_terminator
+			| SETry(bb_try,_,bbl,bb_next,p) ->
+				Some bb_next,Some (mk (TTry(block bb_try,List.map (fun (v,bb) -> v,block bb) bbl)) ctx.com.basic.tvoid p)
+			| se ->
+				let e1 = match bb.bb_terminator with
+					| TermCondBranch e1 -> e1
+					| _ -> die "" __LOC__
+				in
 				let bb_next,e1_def,t,p = match se with
 				let bb_next,e1_def,t,p = match se with
 					| SEIfThen(bb_then,bb_next,p) -> Some bb_next,TIf(e1,block bb_then,None),ctx.com.basic.tvoid,p
 					| SEIfThen(bb_then,bb_next,p) -> Some bb_next,TIf(e1,block bb_then,None),ctx.com.basic.tvoid,p
 					| SEIfThenElse(bb_then,bb_else,bb_next,t,p) -> Some bb_next,TIf(e1,block bb_then,Some (block bb_else)),t,p
 					| SEIfThenElse(bb_then,bb_else,bb_next,t,p) -> Some bb_next,TIf(e1,block bb_then,Some (block bb_else)),t,p
 					| SESwitch(bbl,bo,bb_next,p) -> Some bb_next,TSwitch(e1,List.map (fun (el,bb) -> el,block bb) bbl,Option.map block bo),ctx.com.basic.tvoid,p
 					| SESwitch(bbl,bo,bb_next,p) -> Some bb_next,TSwitch(e1,List.map (fun (el,bb) -> el,block bb) bbl,Option.map block bo),ctx.com.basic.tvoid,p
+					| SEWhile(_,bb_body,bb_next,p) ->
+						let e2 = block bb_body in
+						Some bb_next,TWhile(e1,e2,NormalWhile),ctx.com.basic.tvoid,p
 					| _ -> abort (Printf.sprintf "Invalid node exit: %s" (s_expr_pretty e1)) bb.bb_pos
 					| _ -> abort (Printf.sprintf "Invalid node exit: %s" (s_expr_pretty e1)) bb.bb_pos
 				in
 				in
-				bb_next,(mk e1_def t p) :: el
-			| [],_ ->
-				None,[]
+				bb_next,Some (mk e1_def t p)
+		in
+		let bb_next,e_term = loop bb bb.bb_syntax_edge in
+		let el = DynArray.to_list bb.bb_el in
+		let el = match e_term with
+			| None -> el
+			| Some e -> el @ [e]
 		in
 		in
-		let bb_next,el = loop bb bb.bb_syntax_edge in
 		let el = match bb_next with
 		let el = match bb_next with
 			| None -> el
 			| None -> el
-			| Some bb -> (block_to_texpr_el ctx bb) @ el
+			| Some bb -> el @ (block_to_texpr_el ctx bb)
 		in
 		in
 		el
 		el
 	end
 	end
@@ -711,7 +721,7 @@ let rec block_to_texpr_el ctx bb =
 and block_to_texpr ctx bb =
 and block_to_texpr ctx bb =
 	assert(bb.bb_closed);
 	assert(bb.bb_closed);
 	let el = block_to_texpr_el ctx bb in
 	let el = block_to_texpr_el ctx bb in
-	let e = mk (TBlock (List.rev el)) bb.bb_type bb.bb_pos in
+	let e = mk (TBlock el) bb.bb_type bb.bb_pos in
 	e
 	e
 
 
 and func ctx i =
 and func ctx i =

+ 82 - 21
src/optimization/analyzerTypes.ml

@@ -67,11 +67,26 @@ module BasicBlock = struct
 		| SEIfThenElse of t * t * t * Type.t * pos               (* `if` with "then", "else" and "next" *)
 		| SEIfThenElse of t * t * t * Type.t * pos               (* `if` with "then", "else" and "next" *)
 		| SESwitch of (texpr list * t) list * t option * t * pos (* `switch` with cases, "default" and "next" *)
 		| SESwitch of (texpr list * t) list * t option * t * pos (* `switch` with cases, "default" and "next" *)
 		| SETry of t * t * (tvar * t) list * t *  pos            (* `try` with "exc", catches and "next" *)
 		| SETry of t * t * (tvar * t) list * t *  pos            (* `try` with "exc", catches and "next" *)
-		| SEWhile of t * t * t                                   (* `while` with "head", "body" and "next" *)
+		| SEWhile of t * t * t * pos                             (* `while` with "head", "body" and "next" *)
 		| SESubBlock of t * t                                    (* "sub" with "next" *)
 		| SESubBlock of t * t                                    (* "sub" with "next" *)
 		| SEMerge of t                                           (* Merge to same block *)
 		| SEMerge of t                                           (* Merge to same block *)
 		| SENone                                                 (* No syntax exit *)
 		| SENone                                                 (* No syntax exit *)
 
 
+	and suspend_call = {
+		efun : texpr;      (* coroutine function expression *)
+		args : texpr list; (* call arguments without the continuation *)
+		pos : pos;         (* call position *)
+	}
+
+	and terminator_kind =
+	| TermNone
+	| TermCondBranch of texpr
+	| TermReturn of pos
+	| TermReturnValue of texpr * pos
+	| TermBreak of pos
+	| TermContinue of pos
+	| TermThrow of texpr * pos
+
 	and t = {
 	and t = {
 		bb_id : int;                          (* The unique ID of the block *)
 		bb_id : int;                          (* The unique ID of the block *)
 		bb_type : Type.t;                     (* The block type *)
 		bb_type : Type.t;                     (* The block type *)
@@ -81,6 +96,7 @@ module BasicBlock = struct
 		(* elements *)
 		(* elements *)
 		bb_el : texpr DynArray.t;             (* The block expressions *)
 		bb_el : texpr DynArray.t;             (* The block expressions *)
 		bb_phi : texpr DynArray.t;            (* SSA-phi expressions *)
 		bb_phi : texpr DynArray.t;            (* SSA-phi expressions *)
+		mutable bb_terminator : terminator_kind;
 		(* relations *)
 		(* relations *)
 		mutable bb_outgoing : cfg_edge list;  (* Outgoing edges *)
 		mutable bb_outgoing : cfg_edge list;  (* Outgoing edges *)
 		mutable bb_incoming : cfg_edge list;  (* Incoming edges *)
 		mutable bb_incoming : cfg_edge list;  (* Incoming edges *)
@@ -94,6 +110,11 @@ module BasicBlock = struct
 		mutable bb_var_writes : tvar list;    (* List of assigned variables *)
 		mutable bb_var_writes : tvar list;    (* List of assigned variables *)
 	}
 	}
 
 
+	type texpr_lookup_target =
+		| LUPhi of int
+		| LUEl of int
+		| LUTerm
+
 	let s_block_kind = function
 	let s_block_kind = function
 		| BKRoot -> "BKRoot"
 		| BKRoot -> "BKRoot"
 		| BKNormal -> "BKNormal"
 		| BKNormal -> "BKNormal"
@@ -121,8 +142,21 @@ module BasicBlock = struct
 	let add_texpr bb e =
 	let add_texpr bb e =
 		DynArray.add bb.bb_el e
 		DynArray.add bb.bb_el e
 
 
-	let get_texpr bb is_phi i =
-		DynArray.get (if is_phi then bb.bb_phi else bb.bb_el) i
+	let get_texpr bb luk = match luk with
+		| LUPhi i ->
+			DynArray.get bb.bb_phi i
+		| LUEl i ->
+			DynArray.get bb.bb_el i
+		| LUTerm -> match bb.bb_terminator with
+			| TermCondBranch e1
+			| TermReturnValue(e1,_)
+			| TermThrow(e1,_) ->
+					e1
+			| TermNone
+			| TermReturn _
+			| TermBreak _
+			| TermContinue _ ->
+				die "" __LOC__
 
 
 	(* edges *)
 	(* edges *)
 
 
@@ -145,6 +179,7 @@ module BasicBlock = struct
 			bb_closed = false;
 			bb_closed = false;
 			bb_el = DynArray.create();
 			bb_el = DynArray.create();
 			bb_phi = DynArray.create();
 			bb_phi = DynArray.create();
+			bb_terminator = TermNone;
 			bb_outgoing = [];
 			bb_outgoing = [];
 			bb_incoming = [];
 			bb_incoming = [];
 			bb_dominator = bb;
 			bb_dominator = bb;
@@ -160,6 +195,30 @@ module BasicBlock = struct
 	let in_scope bb bb' = match bb'.bb_scopes with
 	let in_scope bb bb' = match bb'.bb_scopes with
 		| [] -> abort (Printf.sprintf "Scope-less block (kind: %s)" (s_block_kind bb'.bb_kind)) bb'.bb_pos
 		| [] -> abort (Printf.sprintf "Scope-less block (kind: %s)" (s_block_kind bb'.bb_kind)) bb'.bb_pos
 		| scope :: _ -> List.mem scope bb.bb_scopes
 		| scope :: _ -> List.mem scope bb.bb_scopes
+
+	let terminator_map f term = match term with
+		| TermCondBranch e1 ->
+			TermCondBranch (f e1)
+		| TermReturnValue(e1,p) ->
+			TermReturnValue (f e1,p)
+		| TermThrow(e1,p) ->
+			TermThrow (f e1,p)
+		| TermNone
+		| TermReturn _
+		| TermBreak _
+		| TermContinue _ ->
+			term
+
+	let terminator_iter f term = match term with
+			| TermCondBranch e1
+			| TermReturnValue(e1,_)
+			| TermThrow(e1,_) ->
+				f e1
+			| TermNone
+			| TermReturn _
+			| TermBreak _
+			| TermContinue _ ->
+				()
 end
 end
 
 
 (*
 (*
@@ -169,8 +228,8 @@ end
 module Graph = struct
 module Graph = struct
 	open BasicBlock
 	open BasicBlock
 
 
-	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 texpr_lookup = BasicBlock.t * texpr_lookup_target
 	type var_write = BasicBlock.t list
 	type var_write = BasicBlock.t list
 	type 'a itbl = (int,'a) Hashtbl.t
 	type 'a itbl = (int,'a) Hashtbl.t
 
 
@@ -230,16 +289,16 @@ module Graph = struct
 			vi.vi_writes <- bb :: vi.vi_writes;
 			vi.vi_writes <- bb :: vi.vi_writes;
 		end
 		end
 
 
-	let set_var_value g v bb is_phi i =
-		(get_var_info g v).vi_value <- Some (bb,is_phi,i)
+	let set_var_value g v bb luk =
+		(get_var_info g v).vi_value <- Some (bb,luk)
 
 
 	let get_var_value g v =
 	let get_var_value g v =
 		let value = (get_var_info g v).vi_value in
 		let value = (get_var_info g v).vi_value in
-		let bb,is_phi,i = match value with
+		let bb,luk = match value with
 			| None -> raise Not_found
 			| None -> raise Not_found
 			| Some l -> l
 			| Some l -> l
 		in
 		in
-		match (get_texpr bb is_phi i).eexpr with
+		match (get_texpr bb luk).eexpr with
 		| TVar(_,Some e) | TBinop(OpAssign,_,e) -> e
 		| TVar(_,Some e) | TBinop(OpAssign,_,e) -> e
 		| _ -> die "" __LOC__
 		| _ -> die "" __LOC__
 
 
@@ -249,9 +308,9 @@ module Graph = struct
 	let get_var_origin g v =
 	let get_var_origin g v =
 		(get_var_info g v).vi_origin
 		(get_var_info g v).vi_origin
 
 
-	let add_ssa_edge g v bb is_phi i =
+	let add_ssa_edge g v bb luk =
 		let vi = get_var_info g v in
 		let vi = get_var_info g v in
-		vi.vi_ssa_edges <- (bb,is_phi,i) :: vi.vi_ssa_edges
+		vi.vi_ssa_edges <- (bb,luk) :: vi.vi_ssa_edges
 
 
 	(* nodes *)
 	(* nodes *)
 
 
@@ -270,7 +329,7 @@ module Graph = struct
 		g.g_nodes <- bb :: g.g_nodes;
 		g.g_nodes <- bb :: g.g_nodes;
 		bb
 		bb
 
 
-	let close_node g bb =
+	let close_node bb =
 		if bb.bb_id > 0 then begin
 		if bb.bb_id > 0 then begin
 			assert(not bb.bb_closed);
 			assert(not bb.bb_closed);
 			bb.bb_closed <- true
 			bb.bb_closed <- true
@@ -456,15 +515,17 @@ module Graph = struct
 				| _ ->
 				| _ ->
 					()
 					()
 			end;
 			end;
-			DynArray.iter (fun e -> match e.eexpr with
-				| TVar(v,eo) ->
-					declare_var g v bb;
-					if eo <> None then add_var_def g bb v;
-				| TBinop(OpAssign,{eexpr = TLocal v},_) ->
-					add_var_def g bb v
-				| _ ->
-					()
-			) bb.bb_el
+			let infer e = match e.eexpr with
+			| TVar(v,eo) ->
+				declare_var g v bb;
+				if eo <> None then add_var_def g bb v;
+			| TBinop(OpAssign,{eexpr = TLocal v},_) ->
+				add_var_def g bb v
+			| _ ->
+				()
+			in
+			DynArray.iter infer bb.bb_el;
+			terminator_iter infer bb.bb_terminator;
 		)
 		)
 
 
 	(* Infers the scopes of all reachable blocks. This function can be run multiple times
 	(* Infers the scopes of all reachable blocks. This function can be run multiple times
@@ -495,7 +556,7 @@ module Graph = struct
 					loop scopes' bb_exc;
 					loop scopes' bb_exc;
 					List.iter (fun (_,bb_catch) -> loop (next_scope scopes) bb_catch) catches;
 					List.iter (fun (_,bb_catch) -> loop (next_scope scopes) bb_catch) catches;
 					loop scopes bb_next
 					loop scopes bb_next
-				| SEWhile(bb_head,bb_body,bb_next) ->
+				| SEWhile(bb_head,bb_body,bb_next,_) ->
 					let scopes' = next_scope scopes in
 					let scopes' = next_scope scopes in
 					loop scopes' bb_head;
 					loop scopes' bb_head;
 					loop scopes' bb_body;
 					loop scopes' bb_body;