diff options
-rwxr-xr-x | tests/runner.py | 4 | ||||
-rw-r--r-- | tools/eliminator/asm-eliminator-test-output.js | 70 | ||||
-rw-r--r-- | tools/eliminator/asm-eliminator-test.js | 79 | ||||
-rw-r--r-- | tools/js-optimizer.js | 85 |
4 files changed, 234 insertions, 4 deletions
diff --git a/tests/runner.py b/tests/runner.py index b3485657..53eb56fe 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -13095,7 +13095,7 @@ elif 'benchmark' in str(sys.argv): Building.COMPILER_TEST_OPTS = [] - TEST_REPS = 1 + TEST_REPS = 2 TOTAL_TESTS = 8 # standard arguments for timing: @@ -13160,7 +13160,7 @@ elif 'benchmark' in str(sys.argv): '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', '--llvm-lto', '1', '--memory-init-file', '0', '-s', 'TOTAL_MEMORY=128*1024*1024', - '--closure', '1', '-g', + '--closure', '1', '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 41a2c2b6..8cd11541 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -4961,4 +4961,74 @@ function _java_nio_charset_Charset_forNameInternal___java_lang_String($n1) { break; } } +function looop2() { + var i = 0; + while (1) { + do_it(); + i = i + 1 | 0; + if (condition(i)) { + break; + } + } +} +function looop3() { + var i = 0; + while (1) { + do_it(); + i = i + 1 | 0; + if (!condition(i)) { + break; + } + } +} +function looop4() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = i + 1 | 0; + f(i, helper); + if (condition()) { + i = helper; + } else { + break; + } + } +} +function looop4b() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = i + 1 | 0; + g(helper); + if (condition(i)) { + i = helper; + } else { + break; + } + } +} +function looop5() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = i + 1 | 0; + if (condition(helper)) { + i = helper; + } else { + break; + } + } + moar(i); +} +function looop6() { + var i = 0; + while (1) { + do_it(); + i = i + 1 | 0; + if (!condition(i)) { + break; + } + } + moar(i); +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index 9b9cd3f7..6f881654 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -6678,5 +6678,82 @@ function _java_nio_charset_Charset_forNameInternal___java_lang_String($n1) { __THREW__ = threwValue = 0; break; } -}// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String"] +} +function looop2() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = (i + 1)|0; + if (condition(helper)) { + break; + } else { + i = helper; + } + } +} +function looop3() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = (i + 1)|0; + if (condition(helper)) { + i = helper; + } else { + break; + } + } +} +function looop4() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = (i + 1)|0; + f(i, helper); // i is used, cannot optimize! + if (condition()) { + i = helper; + } else { + break; + } + } +} +function looop4b() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = (i + 1)|0; + g(helper); + if (condition(i)) { // i is used, cannot optimize! + i = helper; + } else { + break; + } + } +} +function looop5() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = (i + 1)|0; + if (condition(helper)) { + i = helper; + } else { + break; + } + } + moar(i); // i is still needed, cannot optimize! +} +function looop6() { + var i = 0, helper = 0; + while (1) { + do_it(); + helper = (i + 1)|0; + if (condition(helper)) { + i = helper; + } else { + break; + } + } + moar(helper); // this is cool +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6"] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index df71ab86..a3a58f2b 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -1972,7 +1972,7 @@ function eliminate(ast, memSafe) { //printErr('locals: ' + JSON.stringify(locals)); //printErr('varsToRemove: ' + JSON.stringify(varsToRemove)); //printErr('varsToTryToRemove: ' + JSON.stringify(varsToTryToRemove)); - definitions = values = null; + values = null; //printErr('potentials: ' + JSON.stringify(potentials)); // We can now proceed through the function. In each list of statements, we try to eliminate var tracked = {}; @@ -2327,6 +2327,8 @@ function eliminate(ast, memSafe) { //printErr('delete StatBlock'); }); + var seenUses = {}, helperReplacements = {}; // for looper-helper optimization + // clean up vars //printErr('cleaning up ' + JSON.stringify(varsToRemove)); traverse(func, function(node, type) { @@ -2338,6 +2340,87 @@ function eliminate(ast, memSafe) { node[1] = []; } } + }, function(node, type) { + if (type == 'name') { + var name = node[1]; + if (name in helperReplacements) { + node[1] = helperReplacements[name]; + return; // no need to track this anymore, we can't loop-optimize more than once + } + // track how many uses we saw. we need to know when a variable is no longer used (hence we run this in the post) + if (!(name in seenUses)) { + seenUses[name] = 1; + } else { + seenUses[name]++; + } + } else if (type == 'while') { + // try to remove loop helper variables specifically + var stats = node[2][1]; + var last = stats[stats.length-1]; + if (last[0] == 'if' && last[2][0] == 'block' && last[3] && last[3][0] == 'block') { + var ifTrue = last[2]; + var ifFalse = last[3]; + var flip = false; + if (ifFalse[1][0][0] == 'break') { // canonicalize break in the if + var temp = ifFalse; + ifFalse = ifTrue; + ifTrue = temp; + flip = true; + } + if (ifTrue[1][0][0] == 'break' && !ifTrue[1][1] && ifFalse[1].length == 1 && ifFalse[1][0][0] == 'stat' && ifFalse[1][0][1][0] == 'assign') { + var assign = ifFalse[1][0][1]; + if (assign[1] === true && assign[2][0] == 'name' && assign[3][0] == 'name') { + var looper = assign[2][1]; + var helper = assign[3][1]; + if (definitions[helper] == 1 && seenUses[looper] == uses[looper] + 1 && // +1, because uses does not count the definition + !helperReplacements[helper] && !helperReplacements[looper]) { + // the remaining issue is whether looper is used after the assignment to helper and before the last line (where we assign to it) + var found = -1; + for (var i = stats.length-2; i >= 0; i--) { + var curr = stats[i]; + if (curr[0] == 'stat' && curr[1][0] == 'assign') { + var currAssign = curr[1]; + if (currAssign[1] === true && currAssign[2][0] == 'name') { + var to = currAssign[2][1]; + if (to == helper) { + found = i; + break; + } + } + } + } + if (found >= 0) { + var looperUsed = false; + for (var i = found+1; i < stats.length && !looperUsed; i++) { + var curr = i < stats.length-1 ? stats[i] : last[1]; // on the last line, just look in the condition + traverse(curr, function(node, type) { + if (type == 'name' && node[1] == looper) { + looperUsed = true; + return true; + } + }); + } + if (!looperUsed) { + // hurrah! this is safe to do + varsToRemove[helper] = 2; + traverse(node, function(node, type) { // replace all appearances of helper with looper + if (type == 'name' && node[1] == helper) node[1] = looper; + }); + helperReplacements[helper] = looper; // replace all future appearances of helper with looper + helperReplacements[looper] = looper; // avoid any further attempts to optimize looper in this manner (seenUses is wrong anyhow, too) + // simplify the if. we remove the if branch, leaving only the else + if (flip) { + last[1] = simplifyNotComps(['unary-prefix', '!', last[1]]); + last[2] = last[3]; + } + last.pop(); + } + } + } + } + } + } + } }); if (asm) { |