diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-05-25 11:35:34 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-05-25 15:04:42 -0700 |
commit | 2275f51a55a91b4a989a7f044f70144dbee8bab6 (patch) | |
tree | e5bb4dc96472bc9dd2c37c1927d314a3ef680078 | |
parent | 52eda533fa475ae4add8977b5a679d010b38a104 (diff) |
eliminate into switch cases
-rw-r--r-- | tools/eliminator/asm-eliminator-test-output.js | 5 | ||||
-rw-r--r-- | tools/js-optimizer.js | 38 |
2 files changed, 30 insertions, 13 deletions
diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 8da7a5bc..e3fc4db5 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -107,10 +107,9 @@ function label() { } } function switchy() { - var no = 0, yes = 0, a = 0, b = 0; + var yes = 0; while (1) switch (label | 0) { case 1: - no = 100; break; case 2: yes = 111; @@ -120,8 +119,6 @@ function switchy() { print(yes / 2); continue; case 3: - a = 5; - b = a; break; } } diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 5e7a2448..4b0938c2 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -1794,10 +1794,10 @@ function registerize(ast) { // In memSafe mode, we are more careful and assume functions can replace HEAP and FUNCTION_TABLE, which // can happen in ALLOW_MEMORY_GROWTH mode -var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label'); // do is checked carefully, however +var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch'); // do is checked carefully, however var NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS = set('name', 'num', 'string', 'binary', 'sub', 'unary-prefix'); var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break', 'continue', 'dot'); // dot can only be STRING_TABLE.* -var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'switch', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body) +var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body) function eliminate(ast, memSafe) { // Find variables that have a single use, and if they can be eliminated, do so @@ -1859,12 +1859,7 @@ function eliminate(ast, memSafe) { }); // we cannot eliminate variables if there is a switch - if (traverse(func, function(node, type) { - if (type == 'switch') return true; - })) { - if (asm) denormalizeAsm(func, asmData); - return; - } + if (hasSwitch && !asm) return; var potentials = {}; // local variables with 1 definition and 1 use var sideEffectFree = {}; // whether a local variable has no side effects in its definition @@ -2171,10 +2166,18 @@ function eliminate(ast, memSafe) { invalidateCalls(); callsInvalidated = true; } + allowTracking = false; + + var lastAbort = abort; // do not let an abort in 2 cause 3 to be skipped traverseInOrder(node[2]); // 2 and 3 could be 'parallel', really.. + var midAbort = abort; + abort = lastAbort; if (node[3]) traverseInOrder(node[3]); + abort = midAbort || lastAbort; + allowTracking = true; + } else { tracked = {}; abort = true; @@ -2206,6 +2209,22 @@ function eliminate(ast, memSafe) { traverseInOrder(node[1]); traverseInOrder(node[2]); traverseInOrder(node[3]); + } else if (type == 'switch') { + traverseInOrder(node[1]); + var cases = node[2]; + var lastAbort = abort; + var finalAbort = abort; + for (var i = 0; i < cases.length; i++) { + var c = cases[i]; + assert(c[0] === null || c[0][0] == 'num' || (c[0][0] == 'unary-prefix' && c[0][2][0] == 'num')); + var stats = c[1]; + abort = lastAbort; + for (var j = 0; j < stats.length; j++) { + traverseInOrder(stats[j]); + } + finalAbort = finalAbort || abort; + } + abort = finalAbort; } else { if (!(type in ABORTING_ELIMINATOR_SCAN_NODES)) { printErr('unfamiliar eliminator scan node: ' + JSON.stringify(node)); @@ -2252,7 +2271,8 @@ function eliminate(ast, memSafe) { } } traverse(func, function(block) { - var stats = getStatements(block); + // Look for statements, including while-switch pattern + var stats = getStatements(block) || (block[0] == 'while' && block[2][0] == 'switch' ? [block[2]] : stats); if (!stats) return; tracked = {}; //printErr('new StatBlock'); |