Sfoglia il codice sorgente

Merry Christmas! New analyzer

closes #3705
closes #3938
closes #3956
closes #4004
closes #4239
closes #4241
closes #4265
closes #4399
closes #4456
closes #4563
closes #4727
closes #4731
Simon Krajewski 9 anni fa
parent
commit
d57112a64a

File diff suppressed because it is too large
+ 1820 - 1516
analyzer.ml


+ 1 - 4
filters.ml

@@ -1218,7 +1218,6 @@ let run com tctx main =
 			check_local_vars_init;
 			Optimizer.inline_constructors tctx;
 			Optimizer.reduce_expression tctx;
-			blockify_ast;
 			captured_vars com;
 		] in
 		List.iter (run_expression_filters tctx filters) new_types;
@@ -1244,9 +1243,7 @@ let run com tctx main =
 				else
 					fun e ->
 						let save = save_locals tctx in
-						let timer = timer "analyzer-simplify-apply" in
-						let e = try snd (Analyzer.Simplifier.apply com e) with Exit -> e in
-						timer();
+						let e = try Analyzer.Run.roundtrip com (Analyzer.Config.get_base_config com) e with Exit -> e in
 						save();
 					e );
 			if com.foptimize then (fun e -> Optimizer.reduce_expression tctx e) else Optimizer.sanitize com;

+ 10 - 0
tests/misc/projects/Issue3956/Main.hx

@@ -0,0 +1,10 @@
+class Main {
+    static function main() {
+		var i = getInt();
+		call(i++, i > 0 ? { call(0, 0); 1; } : 1);
+    }
+
+	static function getInt() { return 0; }
+
+	static function call(a:Int, b:Int) { Sys.stderr().writeString(a + " " + b + "\n"); }
+}

+ 3 - 0
tests/misc/projects/Issue3956/compile.hxml

@@ -0,0 +1,3 @@
+-main Main
+-D analyzer
+-x neko.n

+ 2 - 0
tests/misc/projects/Issue3956/compile.hxml.stderr

@@ -0,0 +1,2 @@
+0 0
+0 1

+ 10 - 0
tests/misc/projects/Issue4265/Main.hx

@@ -0,0 +1,10 @@
+class Main {
+	static function main() {
+		var c = Std.int(Math.random() - 0.5); //0
+
+		Sys.stderr().writeString(switch (c) {
+			case 1: '1';
+			default: 'analyzer removed this ';
+		});
+	}
+}

+ 3 - 0
tests/misc/projects/Issue4265/compile.hxml

@@ -0,0 +1,3 @@
+-main Main
+-D analyzer
+-x neko.n

+ 1 - 0
tests/misc/projects/Issue4265/compile.hxml.stderr

@@ -0,0 +1 @@
+analyzer removed this

+ 19 - 0
tests/misc/projects/Issue4399/Main.hx

@@ -0,0 +1,19 @@
+class Main {
+	static function main() {
+		Sys.stderr().writeString("" + foo(2));
+	}
+
+	static var array:Array<Int> = [1,2,3,4,5];
+
+	static function foo(value:Int):Int {
+		var i:Int = 0;
+		var m:Int = 0;
+		while(i < array.length) {
+			if(array[i] == value) {
+				m = i;
+			}
+			++i;
+		}
+		return m;
+	}
+}

+ 3 - 0
tests/misc/projects/Issue4399/compile.hxml

@@ -0,0 +1,3 @@
+-main Main
+-D analyzer
+-x neko.n

+ 1 - 0
tests/misc/projects/Issue4399/compile.hxml.stderr

@@ -0,0 +1 @@
+1

+ 34 - 0
tests/misc/projects/Issue4456/Main.hx

@@ -0,0 +1,34 @@
+class A {
+	public function f():Array<A> {
+		return [];
+	}
+
+	public function f2():A {
+		return this;
+	}
+}
+
+@:generic
+class B<T:{function new():Void;}> {
+	var items:Map<Int,A>;
+
+	public function new() {
+		items = new Map();
+	}
+
+	public function f():Array<A> {
+		var a = [];
+		for (node in items)
+			a = a.concat(node.f());
+		return a;
+	}
+}
+
+class Main {
+	static function main() {
+		var b = new B<Main>();
+		Sys.stderr().writeString("" + b.f());
+	}
+
+	public function new() { }
+}

+ 3 - 0
tests/misc/projects/Issue4456/compile.hxml

@@ -0,0 +1,3 @@
+-main Main
+-D analyzer
+-x neko.n

+ 1 - 0
tests/misc/projects/Issue4456/compile.hxml.stderr

@@ -0,0 +1 @@
+[]

+ 15 - 0
tests/misc/projects/Issue4563/Main.hx

@@ -0,0 +1,15 @@
+class Main {
+	static function main() {
+		Sys.stderr().writeString("" + test(get(true)));
+		Sys.stderr().writeString("" + test(get(false)));
+	}
+
+	static function get(b:Bool) return b;
+
+	static inline function test(a:Bool):Int {
+		if (a)
+			return 42;
+		else
+			return 43;
+	}
+}

+ 3 - 0
tests/misc/projects/Issue4563/compile.hxml

@@ -0,0 +1,3 @@
+-main Main
+-D analyzer
+-x neko.n

+ 1 - 0
tests/misc/projects/Issue4563/compile.hxml.stderr

@@ -0,0 +1 @@
+4243

+ 5 - 8
tests/optimization/src/Test.hx

@@ -15,7 +15,7 @@ class InlineCtor {
 @:analyzer(no_local_dce)
 @:analyzer(no_check_has_effect)
 class Test {
-	@:js('3;')
+	@:js('')
 	static function testNoOpRemoval() {
 		1;
 		2;
@@ -119,20 +119,20 @@ class Test {
 
 	@:js('
 		var a = [1,2];
-		a[-1];
+		var b = a[-1];
 	')
 	static function testArrayInlineCancelNegative() {
 		var a = [1, 2];
-		a[-1];
+		var b = a[-1];
 	}
 
 	@:js('
 		var a = [1,2];
-		a[2];
+		var b = a[2];
 	')
 	static function testArrayInlineCancelExceeds() {
 		var a = [1, 2];
-		a[2];
+		var b = a[2];
 	}
 
 	@:js('
@@ -146,7 +146,6 @@ class Test {
 		var a = true;
 		var b = 0;
 		b = 1;
-		b;
 	')
 	static function testSwitch1() {
 		var a = true;
@@ -155,14 +154,12 @@ class Test {
 			case true: b = 1;
 			case false: b = 2;
 		}
-		b; // TODO: this should become 1
 	}
 
 	@:js('
 		var a = true;
 		var b = 0;
 		a = true;
-		a;
 	')
 	static function testSwitch2() {
 		var a = true;

+ 141 - 36
tests/optimization/src/TestAnalyzer.hx

@@ -104,38 +104,51 @@ class TestAnalyzer extends TestBase {
 		assertEqualsConst(1, a);
 	}
 
-	//function testUnop() {
-		//var a = 0;
-		//assertEqualsConst(0, a++);
-		//assertEqualsConst(1, a);
-		//assertEqualsConst(2, ++a);
-		//assertEqualsConst(2, a);
-		//if (cond1()) {
-			//a++;
-		//}
-		//assertEquals(3, a);
-	//}
-
-	//function testMultiAssign() {
-		//var a;
-		//var b;
-		//var c = a = b = 1;
-		//assertEqualsConst(1, a);
-		//assertEqualsConst(1, b);
-		//assertEqualsConst(1, c);
-		//c = a = b = 2;
-		//assertEqualsConst(2, a);
-		//assertEqualsConst(2, b);
-		//assertEqualsConst(2, c);
-	//}
+	function testUnop() {
+		var a = 0;
+		assertEqualsConst(0, a++);
+		assertEqualsConst(1, a);
+		assertEqualsConst(2, ++a);
+		assertEqualsConst(2, a);
+		if (cond1()) {
+			a++;
+		}
+		assertEquals(3, a);
+	}
+
+	function testOpAssignOp() {
+		var a = 0;
+		assertEqualsConst(0, a += a);
+		assertEqualsConst(0, a);
+		a += 3;
+		assertEqualsConst(6, a += a);
+		assertEqualsConst(6, a);
+		if (cond1()) {
+			a += 1;
+		}
+		assertEquals(7, a);
+	}
+
+	function testMultiAssign() {
+		var a;
+		var b;
+		var c = a = b = 1;
+		assertEqualsConst(1, a);
+		assertEqualsConst(1, b);
+		assertEqualsConst(1, c);
+		c = a = b = 2;
+		assertEqualsConst(2, a);
+		assertEqualsConst(2, b);
+		assertEqualsConst(2, c);
+	}
 
 	function testConst1() {
 		var a = 1;
 		a = 2;
 		var b = a;
 		assertEqualsConst(2, b);
-		//b++;
-		//assertEqualsConst(3, b);
+		b++;
+		assertEqualsConst(3, b);
 	}
 
 	function testConst2() {
@@ -444,8 +457,7 @@ class TestAnalyzer extends TestBase {
 			a = 2;
 			assertEqualsConst(2, a);
 		}
-		// we do not check for unreachable catch cases at the moment
-		assertEquals(1, a);
+		assertEqualsConst(1, a);
 	}
 
 	function testTry2() {
@@ -655,13 +667,13 @@ class TestAnalyzer extends TestBase {
 		assertEquals(4, a);
 	}
 
-	//function testMisc() {
-		//var a = 1;
-		//function call(a, b, c) { return a + b + c; }
-		//assertEquals(5, call(assertEqualsConst(1, a), assertEqualsConst(2, a = a + 1), assertEqualsConst(2, a)));
-		//assertEquals(22, call(assertEqualsConst(2, a++), assertEqualsConst(4, ++a), assertEqualsConst(16, a *= a)));
-		//assertEquals(50, call(a, a = a + 1, a));
-	//}
+	function testMisc() {
+		var a = 1;
+		function call(a, b, c) { return a + b + c; }
+		assertEquals(5, call(assertEqualsConst(1, a), assertEqualsConst(2, a = a + 1), assertEqualsConst(2, a)));
+		assertEquals(23, call(assertEqualsConst(3, a = a + 1), assertEqualsConst(4, a = a + 1), assertEqualsConst(16, a = a * a)));
+		assertEquals(50, call(a, a = a + 1, a));
+	}
 
 	function testEnumValues() {
 		var array = [1];
@@ -677,7 +689,7 @@ class TestAnalyzer extends TestBase {
 		var b = B(0);
 		switch (b) {
 			case B(i):
-				assertEquals(0, i);
+				assertEqualsConst(0, i);
 			case A(_):
 		}
 	}
@@ -727,6 +739,99 @@ class TestAnalyzer extends TestBase {
 		assertEqualsConst(20, enumIndex);
 	}
 
+	function testWhilePrune1() {
+		var a = 0;
+		while (a == 1) {
+			a = 1;
+			break;
+		}
+		assertEqualsConst(0, a);
+	}
+
+	function testWhilePrune2() {
+		var a = 0;
+		while (a == 0) {
+			a = 1;
+			break;
+		}
+		assertEqualsConst(1, a);
+	}
+
+	function testIfPrune() {
+		var a = 0;
+		if (a == 1) {
+			a = 2;
+		}
+		assertEqualsConst(0, a);
+	}
+
+	function testElsePrune() {
+		var a = 1;
+		if (a == 1) {
+			a = 2;
+		} else {
+			a = 3;
+		}
+		assertEqualsConst(2, a);
+	}
+
+	function testThenPrune() {
+		var a = 2;
+		if (a == 1) {
+			a = 2;
+		} else {
+			a = 3;
+		}
+		assertEqualsConst(3, a);
+	}
+
+	function testComplexPrune1() {
+		var a = 0;
+		var b = 0;
+		while (b == 0) {
+			a = 1;
+			if (cond1()) {
+				break;
+			}
+			b = a - 1;
+		}
+		assertEqualsConst(1, a);
+		assertEqualsConst(0, b);
+	}
+
+	function testComplexPrune2() {
+		var a = 0;
+		var b = 0;
+		while (true) {
+			a = 1;
+			if (b == 1) {
+				break;
+			}
+			a = 2;
+			if (b == 2) {
+				break;
+			}
+			a = 3;
+			if (b == 0) {
+				break;
+			}
+			b = a * 0;
+		}
+		assertEqualsConst(3, a);
+		assertEqualsConst(0, b);
+	}
+
+	function testCapture1() {
+		var c = 0;
+		var a = [0, 1, 2];
+		var f = function() {
+			return a[c++];
+		}
+		assertEquals(0, f());
+		assertEquals(1, f());
+		assertEquals(2, f());
+	}
+
 	function cond1() {
 		append("cond1");
 		return true;

+ 83 - 6
tests/optimization/src/TestJs.hx

@@ -16,6 +16,12 @@ class Inl{
 	}
 }
 
+private enum EnumFlagTest {
+	EA;
+	EB;
+	EC;
+}
+
 class TestJs {
 	//@:js('var x = 10;"" + x;var x1 = 10;"" + x1;var x2 = 10.0;"" + x2;var x3 = "10";x3;var x4 = true;"" + x4;')
 	//static function testStdString() {
@@ -31,13 +37,13 @@ class TestJs {
 	//Std.string(x);
 	//}
 
-	@:js("var a = new List();var _g_head = a.h;var _g_val = null;while(_g_head != null) {var tmp;_g_val = _g_head.item;_g_head = _g_head.next;tmp = _g_val;}")
+	@:js("var a = new List();var _g_head = a.h;while(_g_head != null) _g_head = _g_head.next;")
 	static function testListIteratorInline() {
 		var a = new List();
 		for (v in a) { }
 	}
 
-	@:js("var a = 1;var tmp;var v2 = a;tmp = a + v2;if(tmp > 0) {}")
+	@:js("var a = 1;var tmp;var v2 = a;tmp = a + v2;tmp;")
 	@:analyzer(no_const_propagation)
 	@:analyzer(no_check_has_effect)
 	@:analyzer(no_local_dce)
@@ -51,7 +57,7 @@ class TestJs {
 		return v + v2;
 	}
 
-	@:js("var a = [];var tmp;try {tmp = a[0];} catch( e ) {tmp = null;}if(tmp) {}")
+	@:js("var a = [];a;")
 	@:analyzer(no_check_has_effect)
 	@:analyzer(no_local_dce)
 	static function testInlineWithComplexExpr() {
@@ -63,7 +69,7 @@ class TestJs {
 		return try a[i] catch (e:Dynamic) null;
 	}
 
-	@:js("var a = { v : [{ b : 1}]};a;var tmp;switch(a.v.length) {case 1:switch(a.v[0].b) {case 1:tmp = true;break;default:tmp = false;}break;default:tmp = false;}if(tmp) {}")
+	@:js("var a = { v : [{ b : 1}]};a;var tmp;switch(a.v.length) {case 1:switch(a.v[0].b) {case 1:tmp = true;break;default:tmp = false;}break;default:tmp = false;}tmp;")
 	@:analyzer(no_const_propagation, no_local_dce, no_check_has_effect)
 	static function testDeepMatchingWithoutClosures() {
 		var a = {v: [{b: 1}]};
@@ -81,7 +87,7 @@ class TestJs {
 		forEach(function(x) trace(x + 2));
 	}
 
-	@:js('var a = "";var tmp;var __ex0 = a;var _g = __ex0.toLowerCase();switch(_g) {case "e":tmp = 0;break;default:throw new Error();}var e = tmp;')
+	@:js('var a = "";var e;var __ex0 = a;var _g = __ex0.toLowerCase();switch(_g) {case "e":e = 0;break;default:throw new Error();}')
 	@:analyzer(no_const_propagation, no_local_dce)
 	static function testRValueSwitchWithExtractors() {
 		var a = "";
@@ -101,7 +107,7 @@ class TestJs {
 		}
 	}
 
-	@:js('false;')
+	@:js('')
 	static function testEnumValuePropagation2() {
 		var v = pair("foo", "bar");
 		var x = switch (v) {
@@ -161,5 +167,76 @@ class TestJs {
 		try throw false catch (e:Bool) {};
 	}
 
+
+	@:js('TestJs["use"](2);')
+	static function testIssue3938() {
+		var a = 1;
+		if (a == 1) {
+			a = 2;
+		} else {
+			a = 3;
+		}
+		use(a);
+	}
+
+	@:js('
+		TestJs["use"](3);
+	')
+	static function testBinop() {
+		var a = 1;
+		var b = 2;
+		use(a + b);
+	}
+
+	@:js('
+		TestJs["use"](false);
+		TestJs["use"](true);
+		TestJs["use"](true);
+		TestJs["use"](true);
+		TestJs["use"](false);
+		TestJs["use"](true);
+		TestJs["use"](true);
+		TestJs["use"](false);
+		TestJs["use"](false);
+		TestJs["use"](true);
+		TestJs["use"](false);
+	')
+	static function testEnumValueFlags() {
+		var flags = new haxe.EnumFlags();
+		use(flags.has(EA));
+		flags = new haxe.EnumFlags(1);
+		use(flags.has(EA));
+
+		// set
+		flags.set(EB);
+		use(flags.has(EA));
+		use(flags.has(EB));
+		use(flags.has(EC));
+
+		// unset
+		flags.unset(EC);
+		use(flags.has(EA));
+		use(flags.has(EB));
+		use(flags.has(EC));
+		flags.unset(EA);
+		use(flags.has(EA));
+		use(flags.has(EB));
+		use(flags.has(EC));
+	}
+
+	@:js('
+		var map = new haxe_ds_StringMap();
+		var tmp;
+		if(__map_reserved.some != null) map.setReserved("some",2); else map.h["some"] = 2;
+		tmp = 2;
+		var i = tmp;
+		TestJs["use"](i);
+	')
+	static function testIssue4731() {
+        var map = new Map();
+        var i = map["some"] = 2;
+		use(i);
+		// This is not const-propagated because StringMap introduced unbound variables
+	}
 	static function use<T>(t:T) { }
 }

+ 1 - 3
tests/optimization/src/issues/Issue2236.hx

@@ -36,9 +36,7 @@ class Issue2236 {
 		var a = [0];
 		var _g_a = a;
 		var _g_pos = 0;
-		while(_g_pos < _g_a.length) {
-			var x = _g_a[_g_pos++];
-		}
+		while(_g_pos < _g_a.length) ++_g_pos;
 	')
 	static function test() {
 		var a = new ArrayRead([0]);

+ 20 - 20
tests/optimization/src/issues/Issue4223.hx

@@ -2,54 +2,54 @@ package issues;
 
 @:analyzer(no_local_dce)
 class Issue4223 {
-	@:js('4;')
+	@:js('var a = 4;')
 	static function testCeilPos() {
-		Math.ceil(3.6);
+		var a = Math.ceil(3.6);
 	}
 
-	@:js('-3;')
+	@:js('var a = -3;')
 	static function testCeilNeg() {
-		Math.ceil(-3.6);
+		var a = Math.ceil(-3.6);
 	}
 
-	@:js('2147483647;')
+	@:js('var a = 2147483647;')
 	static function testCeilMax() {
-		Math.ceil(2147483646.5);
+		var a = Math.ceil(2147483646.5);
 	}
 
-	@:js('-2147483648;')
+	@:js('var a = -2147483648;')
 	static function testCeilMin() {
-		Math.ceil(-2147483648.5);
+		var a = Math.ceil(-2147483648.5);
 	}
 
-	@:js('Math.ceil(2147483647.5);')
+	@:js('var a = Math.ceil(2147483647.5);')
 	static function testCeilOver() {
-		Math.ceil(2147483647.5);
+		var a = Math.ceil(2147483647.5);
 	}
 
-	@:js('Math.ceil(-2147483649.5);')
+	@:js('var a = Math.ceil(-2147483649.5);')
 	static function testCeilUnder() {
-		Math.ceil(-2147483649.5);
+		var a = Math.ceil(-2147483649.5);
 	}
 
-	@:js('3;')
+	@:js('var a = 3;')
 	static function testFloorPos() {
-		Math.floor(3.6);
+		var a = Math.floor(3.6);
 	}
 
-	@:js('-4;')
+	@:js('var a = -4;')
 	static function testFloorNeg() {
-		Math.floor(-3.6);
+		var a = Math.floor(-3.6);
 	}
 
-	@:js('2147483647;')
+	@:js('var a = 2147483647;')
 	static function testFloorMax() {
-		Math.floor(2147483647.5);
+		var a = Math.floor(2147483647.5);
 	}
 
-	@:js('-2147483648;')
+	@:js('var a = -2147483648;')
 	static function testFloorMin() {
-		Math.floor(-2147483647.5);
+		var a = Math.floor(-2147483647.5);
 	}
 
 	@:js('Math.floor(2147483648.5);')

+ 1 - 1
tests/unit/compile-each.hxml

@@ -5,4 +5,4 @@
 -resource res1.txt@re/s?!%[]))("'1.txt
 -resource res2.bin@re/s?!%[]))("'1.bin
 -dce full
-#-D analyzer
+-D analyzer

+ 4 - 4
tests/unit/src/unit/TestDCE.hx

@@ -32,16 +32,16 @@ class DCEClass {
 	function get_memberPropUnused() return 0;
 	function set_memberPropUnused(i:Int) return 0;
 
-	static var c :Array<Dynamic> = [null, unit.UsedReferenced2];
+	static var c:Array<Dynamic> = [null, unit.UsedReferenced2];
 
 	public function new() {
 		staticUsed();
-		staticVarUsed;
+		staticVarUsed = "foo";
 		staticPropUsed = 1;
 		staticPropUsed;
 
 		memberUsed();
-		memberVarUsed;
+		memberVarUsed = 0;
 		memberPropUsed = 2;
 		memberPropUsed;
 
@@ -50,7 +50,7 @@ class DCEClass {
 		try cast (null, UsedReferenced) catch(e:Dynamic) { }
 
 		new UsedAsBaseChild();
-		c.length;
+		c.push(null);
 	}
 }
 

Some files were not shown because too many files changed in this diff