diff options
Diffstat (limited to 'tools/js-optimizer.js')
-rw-r--r-- | tools/js-optimizer.js | 77 |
1 files changed, 67 insertions, 10 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 5601f65c..32ed1cce 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -493,6 +493,7 @@ function simplifyExpressionsPre(ast) { node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' && node[2][2][0] == 'sub' && node[2][2][1][0] == 'name') { // collapse HEAPU?8[..] << 24 >> 24 etc. into HEAP8[..] | 0 + // TODO: run this before | 0 | 0 removal, because we generate | 0 var amount = node[3][1]; var name = node[2][2][1][1]; if (amount == node[2][3][1] && parseHeap(name)) { @@ -1391,7 +1392,12 @@ function normalizeAsm(func) { var name = v[0]; var value = v[1]; if (!(name in data.vars)) { - data.vars[name] = detectAsmCoercion(value); + if (value[0] != 'name') { + data.vars[name] = detectAsmCoercion(value); // detect by coercion + } else { + var origin = value[1]; + data.vars[name] = data.vars[origin] || ASM_INT; // detect by origin variable, or assume int for non-locals + } } } unVarify(node[1], node); @@ -1781,6 +1787,7 @@ function eliminate(ast, memSafe) { if (asm) var asmData = normalizeAsm(func); //printErr('eliminate in ' + func[1]); + // First, find the potentially eliminatable functions: that have one definition and one use var definitions = {}; var uses = {}; @@ -1796,6 +1803,7 @@ function eliminate(ast, memSafe) { } } // examine body and note locals + var hasSwitch = false; traverse(func, function(node, type) { if (type === 'var') { var node1 = node[1]; @@ -1827,31 +1835,79 @@ function eliminate(ast, memSafe) { uses[name]--; // because the name node will show up by itself in the previous case } } + } else if (type == 'switch') { + hasSwitch = true; } }); + + // 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; + } + var potentials = {}; // local variables with 1 definition and 1 use var sideEffectFree = {}; // whether a local variable has no side effects in its definition - for (var name in locals) { + + function unprocessVariable(name) { + if (name in potentials) delete potentials[name]; + if (name in varsToRemove) delete varsToRemove[name]; + if (name in sideEffectFree) delete sideEffectFree[name]; + if (name in varsToTryToRemove) delete varsToTryToRemove[name]; + } + function processVariable(name) { if (definitions[name] == 1 && uses[name] == 1) { potentials[name] = 1; } else if (uses[name] == 0 && (!definitions[name] || definitions[name] <= 1)) { // no uses, no def or 1 def (cannot operate on phis, and the llvm optimizer will remove unneeded phis anyhow) var hasSideEffects = false; - if (values[name]) { - traverse(values[name], function(node, type) { - if (!(type in NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS)) { - hasSideEffects = true; // cannot remove this unused variable, constructing it has side effects - return true; - } - }); + var value = values[name]; + if (value) { + // TODO: merge with other side effect code + // First, pattern-match + // (HEAP32[((tempDoublePtr)>>2)]=((HEAP32[(($_sroa_0_0__idx1)>>2)])|0),HEAP32[(((tempDoublePtr)+(4))>>2)]=((HEAP32[((($_sroa_0_0__idx1)+(4))>>2)])|0),(+(HEAPF64[(tempDoublePtr)>>3]))) + // which has no side effects and is the special form of converting double to i64. + if (!(value[0] == 'seq' && value[1][0] == 'assign' && value[1][2][0] == 'sub' && value[1][2][2][0] == 'binary' && value[1][2][2][1] == '>>' && + value[1][2][2][2][0] == 'name' && value[1][2][2][2][1] == 'tempDoublePtr')) { + // If not that, then traverse and scan normally. + traverse(value, function(node, type) { + if (!(type in NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS)) { + hasSideEffects = true; // cannot remove this unused variable, constructing it has side effects + return true; + } + }); + } } if (!hasSideEffects) { varsToRemove[name] = !definitions[name] ? 2 : 1; // remove it normally sideEffectFree[name] = true; + // Each time we remove a variable with 0 uses, if its value has no + // side effects and vanishes too, then we can remove a use from variables + // appearing in it, and possibly eliminate again + if (value) { + traverse(value, function(node, type) { + if (type == 'name') { + var name = node[1]; + node[1] = ''; // we can remove this - it will never be shown, and should not be left to confuse us as we traverse + if (name in locals) { + uses[name]--; // cannot be infinite recursion since we descend an energy function + assert(uses[name] >= 0); + unprocessVariable(name); + processVariable(name); + } + } + }); + } } else { varsToTryToRemove[name] = 1; // try to remove it later during scanning } } } + for (var name in locals) { + processVariable(name); + } + //printErr('defs: ' + JSON.stringify(definitions)); //printErr('uses: ' + JSON.stringify(uses)); //printErr('values: ' + JSON.stringify(values)); @@ -2352,7 +2408,8 @@ var passes = { compress: function() { compress = true }, noPrintMetadata: function() { printMetadata = false }, asm: function() { asm = true }, - last: function() { last = true } + last: function() { last = true }, + closure: function(){} // handled in python }; // Main |