Browse Source

[analyzer] remove redundant `continue` (closes #8952)

Aleksandr Kuzmenko 5 years ago
parent
commit
28dabbf346

+ 25 - 15
src/optimization/analyzerTexpr.ml

@@ -638,8 +638,10 @@ module Fusion = struct
 		let state = new fusion_state in
 		let state = new fusion_state in
 		state#infer_from_texpr e;
 		state#infer_from_texpr e;
 		(* Handles block-level expressions, e.g. by removing side-effect-free ones and recursing into compound constructs like
 		(* Handles block-level expressions, e.g. by removing side-effect-free ones and recursing into compound constructs like
-		   array or object declarations. The resulting element list is reversed. *)
-		let rec block_element acc el = match el with
+		   array or object declarations. The resulting element list is reversed.
+		   INFO: `el` is a reversed list of expressions in a block.
+		*)
+		let rec block_element ?(loop_bottom=false) acc el = match el with
 			| {eexpr = TBinop(OpAssign, { eexpr = TLocal v1 }, { eexpr = TLocal v2 })} :: el when v1 == v2 ->
 			| {eexpr = TBinop(OpAssign, { eexpr = TLocal v1 }, { eexpr = TLocal v2 })} :: el when v1 == v2 ->
 				block_element acc el
 				block_element acc el
 			| {eexpr = TBinop((OpAssign | OpAssignOp _),_,_) | TUnop((Increment | Decrement),_,_)} as e1 :: el ->
 			| {eexpr = TBinop((OpAssign | OpAssignOp _),_,_) | TUnop((Increment | Decrement),_,_)} as e1 :: el ->
@@ -686,6 +688,8 @@ module Fusion = struct
 				block_element acc (e1 :: el)
 				block_element acc (e1 :: el)
 			| {eexpr = TBlock []} :: el ->
 			| {eexpr = TBlock []} :: el ->
 				block_element acc el
 				block_element acc el
+			| { eexpr = TContinue } :: el when loop_bottom ->
+				block_element [] el
 			| e1 :: el ->
 			| e1 :: el ->
 				block_element (e1 :: acc) el
 				block_element (e1 :: acc) el
 			| [] ->
 			| [] ->
@@ -1044,24 +1048,30 @@ module Fusion = struct
 				acc
 				acc
 		in
 		in
 		let rec loop e = match e.eexpr with
 		let rec loop e = match e.eexpr with
+			| TWhile(condition,{ eexpr = TBlock el; etype = t; epos = p },flag) ->
+				let condition = loop condition
+				and body = block true el t p in
+				{ e with eexpr = TWhile(condition,body,flag) }
 			| TBlock el ->
 			| TBlock el ->
-				let el = List.rev_map loop el in
-				let el = block_element [] el in
-				(* fuse flips element order, but block_element doesn't care and flips it back *)
-				let el = fuse [] el in
-				let el = block_element [] el in
-				let rec fuse_loop el =
-					state#reset;
-					let el = fuse [] el in
-					let el = block_element [] el in
-					if state#did_change then fuse_loop el else el
-				in
-				let el = fuse_loop el in
-				{e with eexpr = TBlock el}
+				block false el e.etype e.epos
 			| TCall({eexpr = TIdent s},_) when is_really_unbound s ->
 			| TCall({eexpr = TIdent s},_) when is_really_unbound s ->
 				e
 				e
 			| _ ->
 			| _ ->
 				Type.map_expr loop e
 				Type.map_expr loop e
+		and block loop_body el t p =
+			let el = List.rev_map loop el in
+			let el = block_element ~loop_bottom:loop_body [] el in
+			(* fuse flips element order, but block_element doesn't care and flips it back *)
+			let el = fuse [] el in
+			let el = block_element [] el in
+			let rec fuse_loop el =
+				state#reset;
+				let el = fuse [] el in
+				let el = block_element [] el in
+				if state#did_change then fuse_loop el else el
+			in
+			let el = fuse_loop el in
+			mk (TBlock el) t p
 		in
 		in
 		loop e
 		loop e
 end
 end

+ 12 - 0
tests/optimization/src/TestJs.hx

@@ -573,6 +573,18 @@ class TestJs {
 
 
 		f(10);
 		f(10);
 	}
 	}
+
+	@:js('var f = function(x) {while(true) TestJs.use(x);};f(10);')
+	static inline function testNoRedundantContinue() {
+		inline function g() return true;
+		function f(x:Int) {
+			while (true) {
+				TestJs.use(x);
+				if (g()) continue;
+			}
+		}
+		f(10);
+	}
 }
 }
 
 
 extern class Extern {
 extern class Extern {

+ 0 - 1
tests/optimization/src/TestLocalDce.hx

@@ -161,7 +161,6 @@ class TestLocalDce {
 			var i = _g1[_g];
 			var i = _g1[_g];
 			++_g;
 			++_g;
 			s += i * 2;
 			s += i * 2;
-			continue;
 		}
 		}
 		TestJs.use(s);
 		TestJs.use(s);
 	')
 	')