diff options
-rwxr-xr-x | emcc | 12 | ||||
-rw-r--r-- | tests/runner.py | 7 | ||||
-rw-r--r-- | tools/js-optimizer.js | 42 | ||||
-rw-r--r-- | tools/test-js-optimizer-output.js | 7 | ||||
-rw-r--r-- | tools/test-js-optimizer.js | 5 |
5 files changed, 60 insertions, 13 deletions
@@ -219,8 +219,9 @@ if header: # header or such if TEMP_DIR: temp_dir = TEMP_DIR - if not os.path.exists(temp_dir): - os.makedirs(temp_dir) + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) # clear it + os.makedirs(temp_dir) else: temp_dir = tempfile.mkdtemp() @@ -386,14 +387,17 @@ try: # eliminator final = shared.Building.eliminator(final) + # js optimizer pre-pass + final = shared.Building.js_optimizer(final, 'simplifyExpressionsPre') + if closure: if DEBUG: print >> sys.stderr, 'emcc: running closure' final = shared.Building.closure_compiler(final) if opt_level >= 1: - # js optimizer + # js optimizer post-pass if DEBUG: print >> sys.stderr, 'emcc: running post-closure post-opts' - final = shared.Building.js_optimizer(final, 'simplifyExpressions') + final = shared.Building.js_optimizer(final, 'simplifyExpressionsPost') # If we were asked to also generate HTML, do that if final_suffix == 'html': diff --git a/tests/runner.py b/tests/runner.py index 5812c36e..68562215 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -4953,7 +4953,6 @@ Options that are modified or new in %s include: # Verify optimization level etc. in the generated code # XXX these are quite sensitive, and will need updating when code generation changes generated = open('something.js').read() # TODO: parse out the _main function itself, not support code, if the tests below need that some day - assert ('|0)/2)|0)' in generated or '| 0) / 2 | 0)' in generated) == (opt_level <= 2), 'corrections should be in opt <= 2' assert 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 should be used by default' assert 'SAFE_HEAP' not in generated, 'safe heap should not be used by default' assert ': while(' not in generated, 'when relooping we also js-optimize, so there should be no labelled whiles' @@ -4961,6 +4960,8 @@ Options that are modified or new in %s include: assert 'Module._main = ' in generated, 'closure compiler should have been run' else: # closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure + assert 'Module._main = ' not in generated, 'closure compiler should not have been run' + # XXX find a way to test this: assert ('& 255' in generated or '&255' in generated) == (opt_level <= 2), 'corrections should be in opt <= 2' assert ('(__label__)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2' assert ('assert(STACKTOP < STACK_MAX)' in generated) == (opt_level == 0), 'assertions should be in opt == 0' assert 'var $i;' in generated, 'micro opts should always be on' @@ -5081,7 +5082,7 @@ Options that are modified or new in %s include: def test_js_optimizer(self): input = open(path_from_root('tools', 'test-js-optimizer.js')).read() expected = open(path_from_root('tools', 'test-js-optimizer-output.js')).read() - output = Popen([NODE_JS, JS_OPTIMIZER, 'unGlobalize', 'removeAssignsToUndefined', 'simplifyExpressions', 'loopOptimizer'], + output = Popen([NODE_JS, JS_OPTIMIZER, 'unGlobalize', 'removeAssignsToUndefined', 'simplifyExpressionsPre', 'simplifyExpressionsPost', 'loopOptimizer'], stdin=PIPE, stdout=PIPE).communicate(input)[0] self.assertIdentical(expected, output.replace('\n\n', '\n')) @@ -5122,8 +5123,6 @@ else: print 'Benchmarking JS engine:', JS_ENGINE Building.COMPILER_TEST_OPTS = [] - # TODO: Use other js optimizer options, like remove assigns to undefined (seems to slow us down more than speed us up) - POST_OPTIMIZATIONS = [['js-optimizer', 'loopOptimizer'], 'eliminator', 'closure', ['js-optimizer', 'simplifyExpressions']] TEST_REPS = 10 TOTAL_TESTS = 7 diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index d22de39c..010739d3 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -260,7 +260,44 @@ function removeUnneededLabelSettings(ast) { } // Various expression simplifications -function simplifyExpressions(ast) { +function simplifyExpressionsPre(ast) { + // When there is a bunch of math like (((8+5)|0)+12)|0, only the external |0 is needed, one correction is enough. + // At each node, ((X|0)+Y)|0 can be transformed into (X+Y): The inner corrections are not needed + // TODO: Is the same is true for 0xff, 0xffff? + + function simplifyBitops(ast) { + var SAFE_BINARY_OPS = set('+', '-', '*', '/', '%', '|'); + var ZERO = ['num', 0]; + var rerun = true; + while (rerun) { + rerun = false; + traverseGenerated(ast, function(node, type, stack) { + if (type == 'binary' && node[1] == '|' && (jsonCompare(node[2], ZERO) || jsonCompare(node[3], ZERO))) { + stack.push(1); // From here on up, no need for this kind of correction, it's done at the top + + // We might be able to remove this correction + for (var i = stack.length-2; i >= 0; i--) { + if (stack[i] == 1) { + // Great, we can eliminate + rerun = true; + return jsonCompare(node[2], ZERO) ? node[3] : node[2]; + } else if (stack[i] == -1) { + break; // Too bad, we can't + } + } + } else if ((type == 'binary' && node[1] in SAFE_BINARY_OPS) || type == 'num' || type == 'name') { + stack.push(0); // This node is safe in that it does not interfere with this optimization + } else { + stack.push(-1); // This node is dangerous! Give up if you see this before you see '1' + } + }, null, []); + } + } + + simplifyBitops(ast); +} + +function simplifyExpressionsPost(ast) { // We often have branchings that are simplified so one end vanishes, and // we then get // if (!(x < 5)) @@ -373,7 +410,8 @@ var passes = { unGlobalize: unGlobalize, removeAssignsToUndefined: removeAssignsToUndefined, //removeUnneededLabelSettings: removeUnneededLabelSettings, - simplifyExpressions: simplifyExpressions, + simplifyExpressionsPre: simplifyExpressionsPre, + simplifyExpressionsPost: simplifyExpressionsPost, loopOptimizer: loopOptimizer }; diff --git a/tools/test-js-optimizer-output.js b/tools/test-js-optimizer-output.js index fcd2380d..95426478 100644 --- a/tools/test-js-optimizer-output.js +++ b/tools/test-js-optimizer-output.js @@ -79,6 +79,9 @@ function ignoreLoopy() { } } function bits() { - print((($s & 65535) + ((($f & 65535) << 16 >> 16) * (($f & 65535) << 16 >> 16) | 0 | 0) % 256 | 0) & 65535); + print((($s & 65535) + (($f & 65535) << 16 >> 16) * (($f & 65535) << 16 >> 16) % 256 | 0) & 65535); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits"] +function maths() { + __ZN6b2Vec2C1Ev($this1 + 20 + 8 + 8 + 8 + 8 + 8 + 8 + 8 | 0); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths"] diff --git a/tools/test-js-optimizer.js b/tools/test-js-optimizer.js index e06ebd29..c59454e6 100644 --- a/tools/test-js-optimizer.js +++ b/tools/test-js-optimizer.js @@ -83,5 +83,8 @@ function ignoreLoopy() { function bits() { // TODO: optimize this! print((($s & 65535) + ((($f & 65535) << 16 >> 16) * (($f & 65535) << 16 >> 16) | 0 | 0) % 256 | 0) & 65535); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits"] +function maths() { + __ZN6b2Vec2C1Ev(((((((($this1 + 20 | 0 | 0) + 8 | 0) + 8 | 0) + 8 | 0) + 8 | 0) + 8 | 0) + 8 | 0) + 8 | 0); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths"] |