diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-06-19 15:08:10 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-06-19 15:20:54 -0700 |
commit | ea9efe32c9cc66bcbbdb15a1c33bf10dfbe821c5 (patch) | |
tree | 42eca8799db750aa01166d2c6640baed1db20d94 | |
parent | e4f8c8184058d8d621d8f3ac007a0d1a55980832 (diff) |
keep |0 on function calls, allow other bitwise ops on heap accesses etc.
-rw-r--r-- | src/parseTools.js | 4 | ||||
-rw-r--r-- | src/runtime.js | 6 | ||||
-rw-r--r-- | tools/js-optimizer.js | 112 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-pre-output.js | 3 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-pre.js | 3 |
5 files changed, 71 insertions, 57 deletions
diff --git a/src/parseTools.js b/src/parseTools.js index 687faaa8..d54480c7 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1383,7 +1383,7 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) { if (!isNumber(num)) num = stripCorrections(num); if (!isNumber(align)) align = stripCorrections(align); if (!isNumber(num) || (parseInt(num)/align >= UNROLL_LOOP_MAX)) { - return '_memcpy(' + dest + ', ' + src + ', ' + num + ')'; + return '(_memcpy(' + dest + ', ' + src + ', ' + num + ')|0)'; } num = parseInt(num); if (ASM_JS) { @@ -1465,7 +1465,7 @@ function getFastValue(a, op, b, type) { if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this } - return 'Math.imul(' + a + ',' + b + ')'; + return '(Math.imul(' + a + ',' + b + ')|0)'; } } else { if (a == '0') { diff --git a/src/runtime.js b/src/runtime.js index 9bedfe68..e6d5f962 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -25,7 +25,7 @@ var RuntimeGenerator = { sep = sep || ';'; var ret = RuntimeGenerator.alloc(size, 'STACK', false, sep, USE_TYPED_ARRAYS != 2 || (isNumber(size) && parseInt(size) % {{{ STACK_ALIGN }}} == 0)); if (ASSERTIONS) { - ret += sep + 'assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')'; + ret += sep + '(assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')|0)'; } return ret; }, @@ -37,11 +37,11 @@ var RuntimeGenerator = { if (USE_TYPED_ARRAYS == 2) { assert(initial % Runtime.STACK_ALIGN == 0); if (ASSERTIONS && Runtime.STACK_ALIGN == 4) { - ret += '; assert(' + asmCoercion('!(STACKTOP&3)', 'i32') + ')'; + ret += '; (assert(' + asmCoercion('!(STACKTOP&3)', 'i32') + ')|0)'; } } if (ASSERTIONS) { - ret += '; assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')'; + ret += '; (assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')|0)'; } if (false) { ret += '; _memset(' + asmCoercion('__stackBase__', 'i32') + ', 0, ' + initial + ')'; diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 7f186252..862b39eb 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -435,63 +435,69 @@ function simplifyExpressionsPre(ast) { } else { SAFE_BINARY_OPS = set('+', '-', '*'); } - var COERCION_REQUIRING_OPS = set('call', 'sub', 'unary-prefix'); // ops that in asm must be coerced + var COERCION_REQUIRING_OPS = set('sub', 'unary-prefix'); // ops that in asm must be coerced right away var COERCION_REQUIRING_BINARIES = set('*', '/', '%'); // binary ops that in asm must be coerced var ZERO = ['num', 0]; - var rerun = true; - while (rerun) { - rerun = false; - traverse(ast, function process(node, type, stack) { - if (type == 'binary' && node[1] == '|') { - if (node[2][0] == 'num' && node[3][0] == 'num') { - return ['num', node[2][1] | node[3][1]]; - } - var go = false; - if (jsonCompare(node[2], ZERO)) { - // canonicalize order - var temp = node[3]; - node[3] = node[2]; - node[2] = temp; - go = true; - } else if (jsonCompare(node[3], ZERO)) { - go = true; - } - if (!go) { - stack.push(1); - return; - } - // We might be able to remove this correction - for (var i = stack.length-1; i >= 0; i--) { - if (stack[i] == 1) { - if (asm && stack[stack.length-1] != 1) { - if (node[2][0] in COERCION_REQUIRING_OPS || - (node[2][0] == 'binary' && node[2][1] in COERCION_REQUIRING_BINARIES)) break; - } - // we will replace ourselves with the non-zero side. Recursively process that node. - var result = jsonCompare(node[2], ZERO) ? node[3] : node[2], other; - // replace node in-place - node.length = result.length; - for (var j = 0; j < result.length; j++) { - node[j] = result[j]; + + function removeMultipleOrZero() { + var rerun = true; + while (rerun) { + rerun = false; + traverse(ast, function process(node, type, stack) { + if (type == 'binary' && node[1] == '|') { + if (node[2][0] == 'num' && node[3][0] == 'num') { + return ['num', node[2][1] | node[3][1]]; + } + var go = false; + if (jsonCompare(node[2], ZERO)) { + // canonicalize order + var temp = node[3]; + node[3] = node[2]; + node[2] = temp; + go = true; + } else if (jsonCompare(node[3], ZERO)) { + go = true; + } + if (!go) { + stack.push(2); + return; + } + // We might be able to remove this correction + for (var i = stack.length-1; i >= 0; i--) { + if (stack[i] >= 1) { + if (asm) { + if (stack[stack.length-1] < 2 && node[2][0] == 'call') break; // we can only remove multiple |0s on these + if (stack[stack.length-1] < 1 && (node[2][0] in COERCION_REQUIRING_OPS || + (node[2][0] == 'binary' && node[2][1] in COERCION_REQUIRING_BINARIES))) break; // we can remove |0 or >>2 + } + // we will replace ourselves with the non-zero side. Recursively process that node. + var result = jsonCompare(node[2], ZERO) ? node[3] : node[2], other; + // replace node in-place + node.length = result.length; + for (var j = 0; j < result.length; j++) { + node[j] = result[j]; + } + rerun = true; + return process(result, result[0], stack); + } else if (stack[i] == -1) { + break; // Too bad, we can't } - rerun = true; - return process(result, result[0], stack); - } else if (stack[i] == -1) { - break; // Too bad, we can't } + stack.push(2); // From here on up, no need for this kind of correction, it's done at the top + // (Add this at the end, so it is only added if we did not remove it) + } else if (type == 'binary' && node[1] in USEFUL_BINARY_OPS) { + stack.push(1); + } 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' } - stack.push(1); // From here on up, no need for this kind of correction, it's done at the top - // (Add this at the end, so it is only added if we did not remove it) - } else if (type == 'binary' && node[1] in USEFUL_BINARY_OPS) { - stack.push(1); - } 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, []); + }, null, []); + } } + removeMultipleOrZero(); + // & and heap-related optimizations var heapBits, heapUnsigned; @@ -502,7 +508,7 @@ function simplifyExpressionsPre(ast) { return true; } - var hasTempDoublePtr = false; + var hasTempDoublePtr = false, rerunOrZeroPass = false; traverse(ast, function(node, type) { if (type == 'name') { @@ -537,7 +543,6 @@ 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)) { @@ -546,6 +551,7 @@ function simplifyExpressionsPre(ast) { node[1] = '|'; node[2] = node[2][2]; node[3][1] = 0; + rerunOrZeroPass = true; return node; } } @@ -578,6 +584,8 @@ function simplifyExpressionsPre(ast) { } }); + if (rerunOrZeroPass) removeMultipleOrZero(); + if (asm) { if (hasTempDoublePtr) { traverse(ast, function(node, type) { diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js index 903de1f9..1716059f 100644 --- a/tools/test-js-optimizer-asm-pre-output.js +++ b/tools/test-js-optimizer-asm-pre-output.js @@ -15,6 +15,9 @@ function a() { +f(); f(+(+h() + 5)); $140 = $p_3_i + (-$mantSize_0_i | 0) | 0; + f(g() | 0); + f(g() | 0 & -1); + f((g() | 0) >> 2); } function b($this, $__n) { $this = $this | 0; diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js index aac70b60..14531c23 100644 --- a/tools/test-js-optimizer-asm-pre.js +++ b/tools/test-js-optimizer-asm-pre.js @@ -16,6 +16,9 @@ function a() { +f(); f(+(+h() + 5)); $140 = $p_3_i + (-$mantSize_0_i | 0) | 0; + f(g() | 0 | 0); + f(g() | 0 & -1); + f((g() | 0) >> 2); } function b($this, $__n) { $this = $this | 0; |