js optimizer pass to simplify certain bit ops
This commit is contained in:
Родитель
8b1ee6dde8
Коммит
693dcd6d30
12
emcc
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"]
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче