diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-03-26 17:42:39 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-03-27 13:50:01 -0700 |
commit | 14d6b2cdab8e48deddb2b114c47406bcb1796b3a (patch) | |
tree | 0d3e45899feba230080399b83641d881c37555fd | |
parent | 9ce739dbabb00ce0391c3790253fa686edb0a006 (diff) |
remove stack parameter from js optimizer traverse(), to avoid overhead when not needed
-rw-r--r-- | tests/test_other.py | 9 | ||||
-rw-r--r-- | tools/js-optimizer.js | 447 | ||||
-rw-r--r-- | tools/test-js-optimizer-output.js | 78 | ||||
-rw-r--r-- | tools/test-js-optimizer-t2-output.js | 91 | ||||
-rw-r--r-- | tools/test-js-optimizer-t2.js | 92 | ||||
-rw-r--r-- | tools/test-js-optimizer-t2c-output.js | 17 | ||||
-rw-r--r-- | tools/test-js-optimizer-t2c.js | 18 | ||||
-rw-r--r-- | tools/test-js-optimizer-t3-output.js | 49 | ||||
-rw-r--r-- | tools/test-js-optimizer-t3.js | 50 |
9 files changed, 59 insertions, 792 deletions
diff --git a/tests/test_other.py b/tests/test_other.py index 60bdefe1..8c6a199c 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1774,16 +1774,9 @@ This pointer might make sense in another type signature: i: 0 def test_js_optimizer(self): for input, expected, passes in [ (path_from_root('tools', 'test-js-optimizer.js'), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(), - ['hoistMultiples', 'loopOptimizer', 'removeAssignsToUndefined', 'simplifyExpressions']), - (path_from_root('tools', 'test-js-optimizer-t2c.js'), open(path_from_root('tools', 'test-js-optimizer-t2c-output.js')).read(), - ['simplifyExpressions', 'optimizeShiftsConservative']), - (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(), - ['simplifyExpressions', 'optimizeShiftsAggressive']), + ['hoistMultiples', 'removeAssignsToUndefined', 'simplifyExpressions']), (path_from_root('tools', 'test-js-optimizer-si.js'), open(path_from_root('tools', 'test-js-optimizer-si-output.js')).read(), ['simplifyIfs']), - # Make sure that optimizeShifts handles functions with shift statements. - (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(), - ['optimizeShiftsAggressive']), (path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(), ['registerize']), (path_from_root('tools', 'eliminator', 'eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read(), diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index a4c05b70..086ed30e 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -169,11 +169,11 @@ function astToSrc(ast, minifyWhitespace) { // Traverses the children of a node. If the traverse function returns an object, // replaces the child. If it returns true, stop the traversal and return true. -function traverseChildren(node, traverse, pre, post, stack) { +function traverseChildren(node, traverse, pre, post) { for (var i = 0; i < node.length; i++) { var subnode = node[i]; if (Array.isArray(subnode)) { - var subresult = traverse(subnode, pre, post, stack); + var subresult = traverse(subnode, pre, post); if (subresult === true) return true; if (subresult !== null && typeof subresult === 'object') node[i] = subresult; } @@ -189,30 +189,24 @@ function traverseChildren(node, traverse, pre, post, stack) { // it replaces the passed node in the tree. If null is returned, we stop // traversing the subelements (but continue otherwise). // @arg post: A callback to call after traversing all children. -// @arg stack: If true, a stack will be implemented: If pre does not push on -// the stack, we push a 0. We pop when we leave the node. The -// stack is passed as a third parameter to the callbacks. // @returns: If the root node was replaced, the new root node. If the traversal // was stopped, true. Otherwise undefined. -function traverse(node, pre, post, stack) { +function traverse(node, pre, post) { var type = node[0], result, len; var relevant = typeof type === 'string'; if (relevant) { - if (stack) len = stack.length; - var result = pre(node, type, stack); + var result = pre(node, type); if (result === true) return true; if (result && result !== null) node = result; // Continue processing on this node - if (stack && len === stack.length) stack.push(0); } if (result !== null) { - if (traverseChildren(node, traverse, pre, post, stack) === true) return true; + if (traverseChildren(node, traverse, pre, post) === true) return true; } if (relevant) { if (post) { - var postResult = post(node, type, stack); + var postResult = post(node, type); result = result || postResult; } - if (stack) stack.pop(); } return result; } @@ -231,38 +225,12 @@ function traverseGeneratedFunctions(ast, callback) { } } -function traverseGenerated(ast, pre, post, stack) { +function traverseGenerated(ast, pre, post) { traverseGeneratedFunctions(ast, function(func) { - traverse(func, pre, post, stack); + traverse(func, pre, post); }); } -// Walk the ast in a simple way, with an understanding of which JS variables are defined) -function traverseWithVariables(ast, callback) { - traverse(ast, function(node, type, stack) { - if (type in FUNCTION) { - stack.push({ type: 'function', vars: node[2] }); - } else if (type === 'var') { - // Find our function, add our vars - var func = stack[stack.length-1]; - if (func) { - func.vars = func.vars.concat(node[1].map(function(varItem) { return varItem[0] })); - } - } - }, function(node, type, stack) { - if (type === 'toplevel' || type in FUNCTION) { - // We know all of the variables that are seen here, proceed to do relevant replacements - var allVars = stack.map(function(item) { return item ? item.vars : [] }).reduce(concatenator, []); // FIXME dictionary for speed? - traverse(node, function(node2, type2, stack2) { - // Be careful not to look into our inner functions. They have already been processed. - if (sum(stack2) > 1 || (type === 'toplevel' && sum(stack2) === 1)) return; - if (type2 in FUNCTION) stack2.push(1); - return callback(node2, type2, allVars); - }, null, []); - } - }, []); -} - function emptyNode() { // XXX do we need to create new nodes here? can't we reuse? return ['toplevel', []] } @@ -327,58 +295,6 @@ function dumpSrc(ast) { printErr(astToSrc(ast)); } -// Undos closure's creation of global variables with values true, false, -// undefined, null. These cut down on size, but do not affect gzip size -// and make JS engine's lives slightly harder (?) -function unGlobalize(ast) { - - throw 'this is deprecated!'; // and does not work with parallel compilation - - assert(ast[0] === 'toplevel'); - var values = {}; - // Find global renamings of the relevant values - ast[1].forEach(function(node, i) { - if (node[0] != 'var') return; - node[1] = node[1].filter(function(varItem, j) { - var ident = varItem[0]; - var value = varItem[1]; - if (!value) return true; - var possible = false; - if (jsonCompare(value, NULL_NODE) || - jsonCompare(value, UNDEFINED_NODE) || - jsonCompare(value, TRUE_NODE) || - jsonCompare(value, FALSE_NODE)) { - possible = true; - } - if (!possible) return true; - // Make sure there are no assignments to this variable. (This isn't fast, we traverse many times..) - ast[1][i][1][j] = emptyNode(); - var assigned = false; - traverseWithVariables(ast, function(node, type, allVars) { - if (type === 'assign' && node[2][0] === 'name' && node[2][1] === ident) assigned = true; - }); - ast[1][i][1][j] = [ident, value]; - if (!assigned) { - values[ident] = value; - return false; - } - return true; - }); - - if (node[1].length === 0) { - ast[1][i] = emptyNode(); - } - }); - traverseWithVariables(ast, function(node, type, allVars) { - if (type === 'name') { - var ident = node[1]; - if (ident in values && allVars.indexOf(ident) < 0) { - return copy(values[ident]); - } - } - }); -} - // Closure compiler, when inlining, will insert assignments to // undefined for the shared variables. However, in compiled code // - and in library/shell code too! - we should never rely on @@ -505,10 +421,12 @@ function simplifyExpressions(ast) { var rerun = true; while (rerun) { rerun = false; - traverse(ast, function process(node, type, stack) { + var stack = []; + traverse(ast, function process(node, type) { if (type === 'binary' && node[1] === '|') { if (node[2][0] === 'num' && node[3][0] === 'num') { node[2][1] |= node[3][1]; + stack.push(0); return node[2]; } var go = false; @@ -541,7 +459,7 @@ function simplifyExpressions(ast) { node[j] = result[j]; } rerun = true; - return process(result, result[0], stack); + return process(result, result[0]); } else if (stack[i] === -1) { break; // Too bad, we can't } @@ -557,7 +475,9 @@ function simplifyExpressions(ast) { } else { stack.push(-1); // This node is dangerous! Give up if you see this before you see '1' } - }, null, []); + }, function() { + stack.pop(); + }); } } @@ -992,340 +912,6 @@ function simplifyIfs(ast) { }); } - -// In typed arrays mode 2, we can have -// HEAP[x >> 2] -// very often. We can in some cases do the shift on the variable itself when it is set, -// to greatly reduce the number of shift operations. -// XXX this optimization is deprecated and currently invalid: does not handle overflows -// or non-aligned (round numbers, x >> 2 is a multiple of 4). Both are ok to assume -// for pointers (undefined behavior otherwise), but invalid in general, and we do -// no sufficiently-well distinguish the cases. -function optimizeShiftsInternal(ast, conservative) { - var MAX_SHIFTS = 3; - traverseGeneratedFunctions(ast, function(fun) { - var funMore = true; - var funFinished = {}; - while (funMore) { - funMore = false; - // Recognize variables and parameters - var vars = {}; - function newVar(name, param, addUse) { - if (!vars[name]) { - vars[name] = { - param: param, - defs: addUse ? 1 : 0, - uses: 0, - timesShifted: [0, 0, 0, 0], // zero shifts of size 0, 1, 2, 3 - benefit: 0, - primaryShift: -1 - }; - } - } - // params - if (fun[2]) { - fun[2].forEach(function(arg) { - newVar(arg, true, true); - }); - } - // vars - // XXX if var has >>=, ignore it here? That means a previous pass already optimized it - var hasSwitch = traverse(fun, function(node, type) { - if (type === 'var') { - node[1].forEach(function(arg) { - newVar(arg[0], false, arg[1]); - }); - } else if (type === 'switch') { - // The relooper can't always optimize functions, and we currently don't work with - // switch statements when optimizing shifts. Bail. - return true; - } - }); - if (hasSwitch) { - break; - } - // uses and defs TODO: weight uses by being inside a loop (powers). without that, we - // optimize for code size, not speed. - traverse(fun, function(node, type, stack) { - stack.push(node); - if (type === 'name' && vars[node[1]] && stack[stack.length-2][0] != 'assign') { - vars[node[1]].uses++; - } else if (type === 'assign' && node[2][0] === 'name' && vars[node[2][1]]) { - vars[node[2][1]].defs++; - } - }, null, []); - // First, break up elements inside a shift. This lets us see clearly what to do next. - traverse(fun, function(node, type) { - if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num') { - var shifts = node[3][1]; - if (shifts <= MAX_SHIFTS) { - // Push the >> inside the value elements - function addShift(subNode) { - if (subNode[0] === 'binary' && subNode[1] === '+') { - subNode[2] = addShift(subNode[2]); - subNode[3] = addShift(subNode[3]); - return subNode; - } - if (subNode[0] === 'name' && !subNode[2]) { // names are returned with a shift, but we also note their being shifted - var name = subNode[1]; - if (vars[name]) { - vars[name].timesShifted[shifts]++; - subNode[2] = true; - } - } - return ['binary', '>>', subNode, ['num', shifts]]; - } - return addShift(node[2]); - } - } - }); - traverse(fun, function(node, type) { - if (node[0] === 'name' && node[2]) { - return node.slice(0, 2); // clean up our notes - } - }); - // At this point, shifted expressions are split up, and we know who the vars are and their info, so we can decide - // TODO: vars that depend on other vars - for (var name in vars) { - var data = vars[name]; - var totalTimesShifted = sum(data.timesShifted); - if (totalTimesShifted === 0) { - continue; - } - if (totalTimesShifted != Math.max.apply(null, data.timesShifted)) { - // TODO: Handle multiple different shifts - continue; - } - if (funFinished[name]) continue; - // We have one shift size (and possible unshifted uses). Consider replacing this variable with a shifted clone. If - // the estimated benefit is >0, we will do it - if (data.defs === 1) { - data.benefit = totalTimesShifted - 2*(data.defs + (data.param ? 1 : 0)); - } - if (conservative) data.benefit = 0; - if (data.benefit > 0) { - funMore = true; // We will reprocess this function - for (var i = 0; i < 4; i++) { - if (data.timesShifted[i]) { - data.primaryShift = i; - } - } - } - } - //printErr(JSON.stringify(vars)); - function cleanNotes() { // We need to mark 'name' nodes as 'processed' in some passes here; this cleans the notes up - traverse(fun, function(node, type) { - if (node[0] === 'name' && node[2]) { - return node.slice(0, 2); - } - }); - } - cleanNotes(); - // Apply changes - function needsShift(name) { - return vars[name] && vars[name].primaryShift >= 0; - } - for (var name in vars) { // add shifts for params and var's for all new variables - var data = vars[name]; - if (needsShift(name)) { - if (data.param) { - fun[3].unshift(['var', [[name + '$s' + data.primaryShift, ['binary', '>>', ['name', name], ['num', data.primaryShift]]]]]); - } else { - fun[3].unshift(['var', [[name + '$s' + data.primaryShift]]]); - } - } - } - traverse(fun, function(node, type, stack) { // add shift to assignments - stack.push(node); - if (node[0] === 'assign' && node[1] === true && node[2][0] === 'name' && needsShift(node[2][1]) && !node[2][2]) { - var name = node[2][1]; - var data = vars[name]; - var parent = stack[stack.length-3]; - var statements = getStatements(parent); - assert(statements, 'Invalid parent for assign-shift: ' + dump(parent)); - var i = statements.indexOf(stack[stack.length-2]); - statements.splice(i+1, 0, ['stat', ['assign', true, ['name', name + '$s' + data.primaryShift], ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]]); - } else if (node[0] === 'var') { - var args = node[1]; - for (var i = 0; i < args.length; i++) { - var arg = args[i]; - var name = arg[0]; - var data = vars[name]; - if (arg[1] && needsShift(name)) { - args.splice(i+1, 0, [name + '$s' + data.primaryShift, ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]); - } - } - return node; - } - }, null, []); - cleanNotes(); - traverse(fun, function(node, type, stack) { // replace shifted name with new variable - stack.push(node); - if (node[0] === 'binary' && node[1] === '>>' && node[2][0] === 'name' && needsShift(node[2][1]) && node[3][0] === 'num') { - var name = node[2][1]; - var data = vars[name]; - var parent = stack[stack.length-2]; - // Don't modify in |x$sN = x >> 2|, in normal assigns and in var assigns - if (parent[0] === 'assign' && parent[2][0] === 'name' && parent[2][1] === name + '$s' + data.primaryShift) return; - if (parent[0] === name + '$s' + data.primaryShift) return; - if (node[3][1] === data.primaryShift) { - return ['name', name + '$s' + data.primaryShift]; - } - } - }, null, []); - cleanNotes(); - var SIMPLE_SHIFTS = set('<<', '>>'); - var more = true; - while (more) { // combine shifts in the same direction as an optimization - more = false; - traverse(fun, function(node, type) { - if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] === 'binary' && node[2][1] === node[1] && - node[3][0] === 'num' && node[2][3][0] === 'num') { // do not turn a << b << c into a << b + c; while logically identical, it is slower - more = true; - return ['binary', node[1], node[2][2], ['num', node[3][1] + node[2][3][1]]]; - } - }); - } - // Before recombining, do some additional optimizations - traverse(fun, function(node, type) { - // Apply constant shifts onto constants - if (type === 'binary' && node[1] === '>>' && node[2][0] === 'num' && node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) { - var subNode = node[2]; - var shifts = node[3][1]; - var result = subNode[1] / Math.pow(2, shifts); - if (result % 1 === 0) { - subNode[1] = result; - return subNode; - } - } - // Optimize the case of ($a*80)>>2 into ($a*20)|0 - if (type === 'binary' && node[1] in SIMPLE_SHIFTS && - node[2][0] === 'binary' && node[2][1] === '*') { - var mulNode = node[2]; - if (mulNode[2][0] === 'num') { - var temp = mulNode[2]; - mulNode[2] = mulNode[3]; - mulNode[3] = temp; - } - if (mulNode[3][0] === 'num') { - if (node[1] === '<<') { - mulNode[3][1] *= Math.pow(2, node[3][1]); - node[1] = '|'; - node[3][1] = 0; - return node; - } else { - if (mulNode[3][1] % Math.pow(2, node[3][1]) === 0) { - mulNode[3][1] /= Math.pow(2, node[3][1]); - node[1] = '|'; - node[3][1] = 0; - return node; - } - } - } - } - /* XXX - theoretically useful optimization(s), but commented out as not helpful in practice - // Transform (x << 2) >> 2 into x & mask or something even simpler - if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' && - node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' && node[3][1] === node[2][3][1]) { - var subNode = node[2]; - var shifts = node[3][1]; - var mask = ((0xffffffff << shifts) >>> shifts) | 0; - return ['binary', '&', subNode[2], ['num', mask]]; - //return ['binary', '|', subNode[2], ['num', 0]]; - //return subNode[2]; - } - */ - }); - // Re-combine remaining shifts, to undo the breaking up we did before. may require reordering inside +'s - traverse(fun, function(node, type, stack) { - stack.push(node); - if (type === 'binary' && node[1] === '+' && (stack[stack.length-2][0] != 'binary' || stack[stack.length-2][1] !== '+')) { - // 'Flatten' added items - var addedItems = []; - function flatten(node) { - if (node[0] === 'binary' && node[1] === '+') { - flatten(node[2]); - flatten(node[3]); - } else { - addedItems.push(node); - } - } - flatten(node); - var originalOrder = addedItems.slice(); - function key(node) { // a unique value for all relevant shifts for recombining, non-unique for stuff we don't need to bother with - function originalOrderKey(item) { - return -originalOrder.indexOf(item); - } - if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS) { - if (node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) return 2*node[3][1] + (node[1] === '>>' ? 100 : 0); // 0-106 - return (node[1] === '>>' ? 20000 : 10000) + originalOrderKey(node); - } - if (node[0] === 'num') return -20000 + node[1]; - return -10000 + originalOrderKey(node); // Don't modify the original order if we don't modify anything - } - for (var i = 0; i < addedItems.length; i++) { - if (addedItems[i][0] === 'string') return; // this node is not relevant for us - } - addedItems.sort(function(node1, node2) { - return key(node1) - key(node2); - }); - // Regenerate items, now sorted - var i = 0; - while (i < addedItems.length-1) { // re-combine inside addedItems - var k = key(addedItems[i]), k1 = key(addedItems[i+1]); - if (k === k1 && k >= 0 && k1 <= 106) { - addedItems[i] = ['binary', addedItems[i][1], ['binary', '+', addedItems[i][2], addedItems[i+1][2]], addedItems[i][3]]; - addedItems.splice(i+1, 1); - } else { - i++; - } - } - var num = 0; - for (i = 0; i < addedItems.length; i++) { // combine all numbers into one - if (addedItems[i][0] === 'num') { - num += addedItems[i][1]; - addedItems.splice(i, 1); - i--; - } - } - if (num != 0) { // add the numbers into an existing shift, we - // prefer (x+5)>>7 over (x>>7)+5 , since >>'s result is known to be 32-bit and is more easily optimized. - // Also, in the former we can avoid the parentheses, which saves a little space (the number will be bigger, - // so it might take more space, but normally at most one more digit). - var added = false; - for (i = 0; i < addedItems.length; i++) { - if (addedItems[i][0] === 'binary' && addedItems[i][1] === '>>' && addedItems[i][3][0] === 'num' && addedItems[i][3][1] <= MAX_SHIFTS) { - addedItems[i] = ['binary', '>>', ['binary', '+', addedItems[i][2], ['num', num << addedItems[i][3][1]]], addedItems[i][3]]; - added = true; - } - } - if (!added) { - addedItems.unshift(['num', num]); - } - } - var ret = addedItems.pop(); - while (addedItems.length > 0) { // re-create AST from addedItems - ret = ['binary', '+', ret, addedItems.pop()]; - } - return ret; - } - }, null, []); - // Note finished variables - for (var name in vars) { - funFinished[name] = true; - } - } - }); -} - -function optimizeShiftsConservative(ast) { - optimizeShiftsInternal(ast, true); -} - -function optimizeShiftsAggressive(ast) { - optimizeShiftsInternal(ast, false); -} - // We often have branchings that are simplified so one end vanishes, and // we then get // if (!(x < 5)) @@ -5449,13 +5035,10 @@ var passes = { // passes dumpAst: dumpAst, dumpSrc: dumpSrc, - unGlobalize: unGlobalize, removeAssignsToUndefined: removeAssignsToUndefined, //removeUnneededLabelSettings: removeUnneededLabelSettings, simplifyExpressions: simplifyExpressions, simplifyIfs: simplifyIfs, - optimizeShiftsConservative: optimizeShiftsConservative, - optimizeShiftsAggressive: optimizeShiftsAggressive, hoistMultiples: hoistMultiples, loopOptimizer: loopOptimizer, registerize: registerize, diff --git a/tools/test-js-optimizer-output.js b/tools/test-js-optimizer-output.js index 5e5ff29a..41f79f76 100644 --- a/tools/test-js-optimizer-output.js +++ b/tools/test-js-optimizer-output.js @@ -4,25 +4,25 @@ function expr() { function loopy() { $while_body$2 : while (1) { $ok = 1; - while (1) { - if ($ok) break; + $for_cond$4 : while (1) { + if ($ok) break $for_cond$4; var $inc = $ok + 1; if ($inc == 9999) break $while_body$2; } - continue; + continue $while_body$2; } next(); - while (1) { + b$while_body$2 : while (1) { $ok = 1; - while (1) { - if ($ok) break; + b$for_cond$4 : while (1) { + if ($ok) break b$for_cond$4; var $inc = $ok + 1; } - continue; + continue b$while_body$2; } next(); - do { - if (!$ok) break; + $once : do { + if (!$ok) break $once; something(); } while (0); next(); @@ -33,7 +33,9 @@ function loopy() { something(); } while (0); next(); - something(); + c$once : do { + something(); + } while (0); } function bits() { print(($s & 65535) + ((($f & 65535) << 16 >> 16) * (($f & 65535) << 16 >> 16) | 0) % 256 & 65535); @@ -68,9 +70,9 @@ function hoisting() { } } while (0); pause(2); - do { + cheez : do { if ($i < $N) { - if (callOther()) break; + if (callOther()) break cheez; } } while (0); pause(3); @@ -97,7 +99,7 @@ function hoisting() { somethingElse(); } pause(7); - while (1) { + free : while (1) { if ($i >= $N) { label = 3; break; @@ -110,24 +112,26 @@ function hoisting() { } pause(8); var $cmp95 = $69 == -1; - do { + $if_then96$$if_end110thread_pre_split$48 : do { if ($cmp95) { if (!$cmp103) { label = 38; - break; + break $if_then96$$if_end110thread_pre_split$48; } if (!$cmp106) { label = 38; - break; + break $if_then96$$if_end110thread_pre_split$48; } label = 39; - break; + break $if_then96$$if_end110thread_pre_split$48; } label = 38; } while (0); - if (label == 38) { - var $79 = $_pr6; - } + $if_end110$$if_end110thread_pre_split$52 : do { + if (label == 38) { + var $79 = $_pr6; + } + } while (0); pause(9); var $cmp70 = ($call69 | 0) != 0; pause(10); @@ -191,24 +195,26 @@ function sleep() { return 0; } function demangle($cmp) { - do { + $if_then$$lor_lhs_false$2 : do { if (!$cmp) { if (something()) { label = 3; - break; + break $if_then$$lor_lhs_false$2; } more(); - break; + break $if_then$$lor_lhs_false$2; } label = 3; } while (0); - if (label == 3) { - final(); - } + $if_then$$return$6 : do { + if (label == 3) { + final(); + } + } while (0); } function lua() { - while (1) { - do { + $5$98 : while (1) { + $15$$16$101 : do { if (!$14) { var $17 = $i; var $18 = $3; @@ -217,7 +223,7 @@ function lua() { var $21 = $20 + 1 | 0; var $22 = HEAP8[$21]; var $23 = $22 << 24 >> 24; - break; + break $15$$16$101; } } while (0); } @@ -236,14 +242,16 @@ function lua() { } } function moreLabels() { - while (1) { + $for_cond$2 : while (1) { if (!$cmp) { - break; + break $for_cond$2; } - if ($cmp1) { - break; - } - inc(); + $if_then$$for_inc$5 : do { + if ($cmp1) { + break $for_cond$2; + } + inc(); + } while (0); } pause(999); $while_body$$while_end$31 : do { diff --git a/tools/test-js-optimizer-t2-output.js b/tools/test-js-optimizer-t2-output.js deleted file mode 100644 index 334d7999..00000000 --- a/tools/test-js-optimizer-t2-output.js +++ /dev/null @@ -1,91 +0,0 @@ -function shifty($id2) { - var $tp$s2; - var $parameters_addr$s2; - var $wavelet38$s2; - var _dwt_norms_real$s2; - var $a_addr$s2; - var _idents$s2; - var $id3$s3; - var $id2$s1 = $id2 >> 1; - q(HEAP32[$id >> 2]); - q(HEAP32[$id + 40 >> 2]); - q(HEAP32[$id + 80 >> 2]); - q(HEAP32[unknown1 + unknown2 + $id >> 2]); - q(HEAP32[unknown1 + $id + unknown2 >> 2]); - var localUnchanged1 = get(1), localUnchanged2 = get(1); - q(HEAP32[localUnchanged1 + $id + localUnchanged2 >> 2]); - q($id >> _something_); - $id = q(".."); - q($id << _somethingElse_); - pause(-1); - q(HEAP32[$id2$s1]); - q(HEAP32[$id2$s1]); - q(HEAP32[$id2$s1]); - q(HEAP32[$id2$s1]); - q(HEAP32[$id2$s1 + 20]); - q(HEAP32[$id2$s1 + 40]); - var $id3 = get(74), $id3$s3 = $id3 >> 3; - q(HEAP32[$id3$s3]); - q(HEAP32[$id3$s3 + 5]); - q(HEAP32[$id3$s3 + 10]); - q($id3); - pause(0); - var _idents = get("abc"), _idents$s2 = _idents >> 2; - q(HEAP32[HEAP32[_idents$s2] + 8 >> 2]); - q(HEAP32[HEAP32[_idents$s2] + 8 >> 2]); - q(HEAP32[HEAP32[_idents$s2] + 8 >> 2]); - pause(1); - var $sn_addr = get(12), $a_addr = get(999), $a_addr$s2 = $a_addr >> 2; - var $i = get(112233); - q(HEAP32[(($sn_addr - 1 << 1) + 1 << 2 >> 2) + $a_addr$s2]); - q(HEAP32[(($i - 1 << 1) + 1 << 2 >> 2) + $a_addr$s2]); - q(HEAP32[($i << 3 >> 2) + $a_addr$s2]); - q(HEAP32[($i << 2 >> 2) + $a_addr$s2]); - q($a_addr$s2, z($a_addr$s2)); - pause(2); - var $level = HEAP[get(322) >> 2]; - var _dwt_norms_real = get("a"), _dwt_norms_real$s2 = _dwt_norms_real >> 2, $orient = get("cheez"); - q(HEAP32[($level << 3 >> 2) + _dwt_norms_real$s2 + ($orient * 20 | 0)]); - q(HEAP32[(($level << 3) + 4 >> 2) + _dwt_norms_real$s2 + ($orient * 20 | 0)]); - q(HEAP32[(($level << 3) + 8 >> 2) + _dwt_norms_real$s2 + ($orient * 20 | 0)]); - pause(3); - var $wavelet38 = get(38), $wavelet38$s2 = $wavelet38 >> 2; - $k = $a_addr; - q(HEAPF32[HEAP32[$wavelet38$s2] + ($k << 4) + 8 >> 2]); - q(HEAPF32[HEAP32[$wavelet38$s2] + ($k << 4) + 12 >> 2]); - q(HEAPF32[HEAP32[$wavelet38$s2] + ($k << 4) + 400 >> 2]); - pause(4); - var $p = $k, $parameters_addr = get("burger"), $parameters_addr$s2 = $parameters_addr >> 2; - q(HEAP32[(($p << 2) + 5624 >> 2) + $parameters_addr$s2]); - q(HEAP32[(($p << 2) + 5644 >> 2) + $parameters_addr$s2]); - q(HEAP32[(($p << 2) + 5664 >> 2) + $parameters_addr$s2]); - pause(5); - var $res_spec242 = get($real), $cp = get("b"), $tileno = arguments[2]; - q(HEAP32[(($res_spec242 - 1 << 2) + 5624 >> 2) + $parameters_addr$s2]); - q(HEAP32[(HEAP32[$cp + 108 >> 2] + 420 >> 2) + ($tileno * 1397 | 0)]); - pause(6); - q($idx << 3); - q(1 << $idx << 1); - print(INDENT + "Entering: _main" + "hi"); - pause(7); - var $tp = get("tp"), $tp$s2 = $tp >> 2; - q($tp$s2); - q($tp$s2); - q($tp$s2); - HEAP32[$H400] = $tp; - HEAP32[$tp] = 5; - HEAP32[$tp$s2] = 5; - HEAP32[HEAP[$tp$s2]] = 5; - HEAP32[HEAP[$tp$s2] >> 2] = 5; - pause(7); - q(go() >> 1 << 1); - q(go() << 1 >> 1); - q(go() >> 2); - q(go() << 2); - q(go() >> 8 << 8); - q(go() << 8 >> 8); - q(go() >> 16); - q(go() << 16); - q(go() + 2 >> 2); -} - diff --git a/tools/test-js-optimizer-t2.js b/tools/test-js-optimizer-t2.js deleted file mode 100644 index 8dd82485..00000000 --- a/tools/test-js-optimizer-t2.js +++ /dev/null @@ -1,92 +0,0 @@ -// TODO also with >> 1 and >> 3 -// also HEAP*U*, and HEAP8, 16 -function shifty($id2) { - // $id is a non-ssa, $id2 is a param. both should be replaced with a shifted version - q(HEAP32[$id >> 2]); - q(HEAP32[($id + 40) >> 2]); - q(HEAP32[($id + 80 | 0) >> 2]); - q(HEAP32[(unknown1 + unknown2 + $id) >> 2]); - q(HEAP32[(unknown1 + $id + unknown2) >> 2]); // unknowns should be shifted together - var localUnchanged1 = get(1), localUnchanged2 = get(1); - q(HEAP32[(localUnchanged1 + $id + localUnchanged2) >> 2]); // unknowns should be shifted together - q($id >> _something_); // non-fixed shift - $id = q('..'); - q($id << _somethingElse_); // non-fixed shift - pause(-1); - q(HEAP32[$id2 >> 1]); - q(HEAP32[$id2 >> 1]); - q(HEAP32[$id2 >> 1]); - q(HEAP32[$id2 >> 1]); - q(HEAP32[($id2 + 40) >> 1]); - q(HEAP32[($id2 + 80 | 0) >> 1]); - var $id3 = get(74); - q(HEAP32[$id3 >> 3]); - q(HEAP32[($id3 + 40) >> 3]); - q(HEAP32[($id3 + 80 | 0) >> 3]); - q($id3); - pause(0); - // similar, but inside another HEAP - var _idents = get('abc'); - q(HEAP32[(HEAP32[_idents >> 2] + 8 | 0) >> 2]); - q(HEAP32[(HEAP32[_idents >> 2] + 8 | 0) >> 2]); - q(HEAP32[(HEAP32[_idents >> 2] + 8 | 0) >> 2]); - pause(1); - // $i's shifts should consolidate (the last should be 0..? - // since we may have had |0 in the middle!) - var $sn_addr = get(12), $a_addr = get(999); - var $i = get(112233); - q(HEAP32[($a_addr + ((($sn_addr - 1 << 1) + 1 | 0) << 2) | 0) >> 2]); - q(HEAP32[($a_addr + ((($i - 1 << 1) + 1 | 0) << 2) | 0) >> 2]); - q(HEAP32[($a_addr + (($i << 1 | 0) << 2) | 0) >> 2]); - q(HEAP32[($a_addr + ($i << 2)) >> 2]); - q($a_addr >> 2, z($a_addr >> 2)); - pause(2); - var $level = HEAP[get(322) >> 2]; // ignore this - var _dwt_norms_real = get('a'), $orient = get('cheez'); - q(HEAP32[(_dwt_norms_real + $orient * 80 + ($level << 3) | 0) >> 2]); - q(HEAP32[(_dwt_norms_real + $orient * 80 + ($level << 3) + 4 | 0) >> 2]); - q(HEAP32[(_dwt_norms_real + $orient * 80 + ($level << 3) + 8 | 0) >> 2]); - pause(3); - // reuse $a_addr here - var $wavelet38 = get(38); - $k = $a_addr; - q(HEAPF32[(HEAP32[$wavelet38 >> 2] + ($k << 4) + 8 | 0) >> 2]); - q(HEAPF32[(HEAP32[$wavelet38 >> 2] + ($k << 4) + 12 | 0) >> 2]); - q(HEAPF32[(HEAP32[$wavelet38 >> 2] + ($k << 4) + 400 | 0) >> 2]); - pause(4); - // reuse $k, which already reuses $a_addr - var $p = $k, $parameters_addr = get('burger') - q(HEAP32[($parameters_addr + 5624 + ($p << 2) | 0) >> 2]); - q(HEAP32[($parameters_addr + 5644 + ($p << 2) | 0) >> 2]); - q(HEAP32[($parameters_addr + 5664 + ($p << 2) | 0) >> 2]); - pause(5); - // loops count as more uses! - var $res_spec242 = get($real), $cp = get('b'), $tileno = arguments[2]; - q(HEAP32[($parameters_addr + 5624 + (($res_spec242 - 1 | 0) << 2) | 0) >> 2]); - q(HEAP32[(HEAP32[($cp + 108 | 0) >> 2] + $tileno * 5588 + 420 | 0) >> 2]); - pause(6); - q($idx << 1 << 2); - q(1 << $idx << 1); // Do not turn this into the slower 1 << $idx + 1 (which is identical though) - print(INDENT + "Entering: _main" + "hi"); // this order should not be modified - pause(7); - var $tp = get('tp'); - q($tp >> 2); - q($tp >> 2); - q($tp >> 2); - HEAP32[$H400] |