js optimizer pass to simplify certain bit ops

This commit is contained in:
Alon Zakai 2011-12-15 18:39:03 -08:00
Родитель 8b1ee6dde8
Коммит 693dcd6d30
5 изменённых файлов: 60 добавлений и 13 удалений

12
emcc
Просмотреть файл

@ -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':

Просмотреть файл

@ -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

Просмотреть файл

@ -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
};

Просмотреть файл

@ -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"]

Просмотреть файл

@ -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"]