diff options
-rwxr-xr-x | emscripten.py | 20 | ||||
-rw-r--r-- | src/fastLong.js | 18 | ||||
-rw-r--r-- | src/jsifier.js | 7 | ||||
-rw-r--r-- | src/library.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 10 | ||||
-rw-r--r-- | src/runtime.js | 6 | ||||
-rw-r--r-- | tests/lua/binarytrees.lua | 17 | ||||
-rw-r--r-- | tests/lua/scimark.lua | 50 | ||||
-rwxr-xr-x | tests/runner.py | 37 | ||||
-rw-r--r-- | tools/js-optimizer.js | 118 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-pre-output.js | 4 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-pre.js | 4 |
12 files changed, 173 insertions, 120 deletions
diff --git a/emscripten.py b/emscripten.py index c9a5eb59..56f59273 100755 --- a/emscripten.py +++ b/emscripten.py @@ -407,7 +407,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, math_envs = ['Math.min'] # TODO: move min to maths asm_setup += '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs]) - basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat', 'copyTempDouble', 'copyTempFloat'] + [m.replace('.', '_') for m in math_envs] + basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] @@ -555,6 +555,24 @@ var asm = (function(global, env, buffer) { threwValue = value; } } + function copyTempFloat(ptr) { + ptr = ptr|0; + HEAP8[tempDoublePtr] = HEAP8[ptr]; + HEAP8[tempDoublePtr+1|0] = HEAP8[ptr+1|0]; + HEAP8[tempDoublePtr+2|0] = HEAP8[ptr+2|0]; + HEAP8[tempDoublePtr+3|0] = HEAP8[ptr+3|0]; + } + function copyTempDouble(ptr) { + ptr = ptr|0; + HEAP8[tempDoublePtr] = HEAP8[ptr]; + HEAP8[tempDoublePtr+1|0] = HEAP8[ptr+1|0]; + HEAP8[tempDoublePtr+2|0] = HEAP8[ptr+2|0]; + HEAP8[tempDoublePtr+3|0] = HEAP8[ptr+3|0]; + HEAP8[tempDoublePtr+4|0] = HEAP8[ptr+4|0]; + HEAP8[tempDoublePtr+5|0] = HEAP8[ptr+5|0]; + HEAP8[tempDoublePtr+6|0] = HEAP8[ptr+6|0]; + HEAP8[tempDoublePtr+7|0] = HEAP8[ptr+7|0]; + } ''' + ''.join([''' function setTempRet%d(value) { value = value|0; diff --git a/src/fastLong.js b/src/fastLong.js index d1ce5d39..4f6efd9f 100644 --- a/src/fastLong.js +++ b/src/fastLong.js @@ -5,12 +5,12 @@ function ___muldsi3($a, $b) { var $1 = 0, $2 = 0, $3 = 0, $6 = 0, $8 = 0, $11 = 0, $12 = 0; $1 = $a & 65535; $2 = $b & 65535; - $3 = Math.imul($2, $1); + $3 = Math.imul($2, $1) | 0; $6 = $a >>> 16; - $8 = ($3 >>> 16) + Math.imul($2, $6) | 0; + $8 = ($3 >>> 16) + (Math.imul($2, $6) | 0) | 0; $11 = $b >>> 16; - $12 = Math.imul($11, $1); - return (tempRet0 = (($8 >>> 16) + Math.imul($11, $6) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0; + $12 = Math.imul($11, $1) | 0; + return (tempRet0 = (($8 >>> 16) + (Math.imul($11, $6) | 0) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0; } function ___divdi3($a$0, $a$1, $b$0, $b$1) { $a$0 = $a$0 | 0; @@ -47,7 +47,7 @@ function ___remdi3($a$0, $a$1, $b$0, $b$1) { $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0; $4$1 = tempRet0; $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0; - ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem); + ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem) | 0; $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1) | 0; $10$1 = tempRet0; STACKTOP = __stackBase__; @@ -63,8 +63,8 @@ function ___muldi3($a$0, $a$1, $b$0, $b$1) { $y_sroa_0_0_extract_trunc = $b$0; $1$0 = ___muldsi3($x_sroa_0_0_extract_trunc, $y_sroa_0_0_extract_trunc) | 0; $1$1 = tempRet0; - $2 = Math.imul($a$1, $y_sroa_0_0_extract_trunc); - return (tempRet0 = (Math.imul($b$1, $x_sroa_0_0_extract_trunc) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0; + $2 = Math.imul($a$1, $y_sroa_0_0_extract_trunc) | 0; + return (tempRet0 = ((Math.imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0; } function ___udivdi3($a$0, $a$1, $b$0, $b$1) { $a$0 = $a$0 | 0; @@ -84,7 +84,7 @@ function ___uremdi3($a$0, $a$1, $b$0, $b$1) { __stackBase__ = STACKTOP; STACKTOP = STACKTOP + 8 | 0; $rem = __stackBase__ | 0; - ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem); + ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) | 0; STACKTOP = __stackBase__; return (tempRet0 = HEAP32[$rem + 4 >> 2] | 0, HEAP32[$rem >> 2] | 0) | 0; } @@ -258,7 +258,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { $149 = $carry_0203 | $q_sroa_0_1199 << 1; $r_sroa_0_0_insert_insert42$0 = 0 | ($r_sroa_0_1201 << 1 | $q_sroa_1_1198 >>> 31); $r_sroa_0_0_insert_insert42$1 = $r_sroa_0_1201 >>> 31 | $r_sroa_1_1200 << 1 | 0; - _i64Subtract($137$0, $137$1, $r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1); + _i64Subtract($137$0, $137$1, $r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1) | 0; $150$1 = tempRet0; $151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1; $152 = $151$0 & 1; diff --git a/src/jsifier.js b/src/jsifier.js index 88b9d9f6..e9bc9a79 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1185,8 +1185,13 @@ function JSify(data, functionsOnly, givenFunctions) { if (disabled) { ret = call_ + ';'; } else if (ASM_JS) { + if (item.type != 'void') call_ = asmCoercion(call_, item.type); // ensure coercion to ffi in comma operator call_ = call_.replace('; return', ''); // we auto-add returns when aborting, but do not need them here - ret = '(__THREW__ = 0,' + call_ + ');'; + if (item.type == 'void') { + ret = '__THREW__ = 0;' + call_ + ';'; + } else { + ret = '(__THREW__ = 0,' + call_ + ');'; + } } else { ret = '(function() { try { __THREW__ = 0; return ' + call_ + ' ' diff --git a/src/library.js b/src/library.js index 33dcbd5f..01a67804 100644 --- a/src/library.js +++ b/src/library.js @@ -4399,7 +4399,7 @@ LibraryManager.library = { {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}}; } } else { - _memcpy(dest, src, num); + _memcpy(dest, src, num) | 0; } }, llvm_memmove_i32: 'memmove', diff --git a/src/parseTools.js b/src/parseTools.js index 687faaa8..0b83a12b 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -710,9 +710,9 @@ function splitI64(value, floatConversion) { var lowInput = legalizedI64s ? value : 'VALUE'; if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput); if (legalizedI64s) { - return [lowInput + '>>>0', 'Math.min(Math.floor((' + value + ')/' + asmEnsureFloat(4294967296, 'float') + '), ' + asmEnsureFloat(4294967295, 'float') + ')>>>0']; + return [lowInput + '>>>0', asmCoercion('Math.min(' + asmCoercion('Math.floor((' + value + ')/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0']; } else { - return makeInlineCalculation(makeI64(lowInput + '>>>0', 'Math.min(Math.floor(VALUE/' + asmEnsureFloat(4294967296, 'float') + '), ' + asmEnsureFloat(4294967295, 'float') + ')>>>0'), value, 'tempBigIntP'); + return makeInlineCalculation(makeI64(lowInput + '>>>0', asmCoercion('Math.min(' + asmCoercion('Math.floor(VALUE/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0'), value, 'tempBigIntP'); } } function mergeI64(value, unsigned) { @@ -1049,7 +1049,7 @@ function getHeapOffset(offset, type, forceAsm) { offset = '(' + offset + ')'; if (shifts != 0) { if (CHECK_HEAP_ALIGN) { - return '(CHECK_ALIGN_' + sz + '(' + offset + '|0)>>' + shifts + ')'; + return '((CHECK_ALIGN_' + sz + '(' + offset + '|0)|0)>>' + shifts + ')'; } else { return '(' + offset + '>>' + shifts + ')'; } @@ -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/tests/lua/binarytrees.lua b/tests/lua/binarytrees.lua index 2ae3dd69..58c0ce87 100644 --- a/tests/lua/binarytrees.lua +++ b/tests/lua/binarytrees.lua @@ -21,7 +21,22 @@ local function ItemCheck(tree) end end -local N = tonumber(arg and arg[1]) or 0 +local N = tonumber(arg and arg[1]) or 4 + +if N == 0 then + N = 0 +elseif N == 1 then + N = 9.5 +elseif N == 2 then + N = 11.99 +elseif N == 3 then + N = 12.85 +elseif N == 4 then + N = 14.72 +elseif N == 5 then + N = 15.82 +end + local mindepth = 4 local maxdepth = mindepth + 2 if maxdepth < N then maxdepth = N end diff --git a/tests/lua/scimark.lua b/tests/lua/scimark.lua index 7e37c219..34fbc4ff 100644 --- a/tests/lua/scimark.lua +++ b/tests/lua/scimark.lua @@ -387,31 +387,31 @@ end --printf("Lua SciMark %s based on SciMark 2.0a. %s.\n\n", -- SCIMARK_VERSION, SCIMARK_COPYRIGHT) -while arg and arg[1] do - local a = table.remove(arg, 1) - if a == "-noffi" then - package.preload.ffi = nil - elseif a == "-small" then - SIZE_SELECT = "small" - elseif a == "-large" then - SIZE_SELECT = "large" - elseif benchmarks[a] then - local p = benchmarks[SIZE_SELECT][a] - measure(MIN_TIME, a, tonumber(arg[1]) or p[1], tonumber(arg[2]) or p[2]) - return - else - printf("Usage: scimark [-noffi] [-small|-large] [BENCH params...]\n\n") - printf("BENCH -small -large\n") - printf("---------------------------------------\n") - for _,name in ipairs(benchmarks) do - printf("%-7s %-13s %s\n", name, - fmtparams(unpack(benchmarks.small[name])), - fmtparams(unpack(benchmarks.large[name]))) - end - printf("\n") - os.exit(1) - end -end +--while arg and arg[1] do +-- local a = table.remove(arg, 1) +-- if a == "-noffi" then +-- package.preload.ffi = nil +-- elseif a == "-small" then +-- SIZE_SELECT = "small" +-- elseif a == "-large" then +-- SIZE_SELECT = "large" +-- elseif benchmarks[a] then +-- local p = benchmarks[SIZE_SELECT][a] +-- measure(MIN_TIME, a, tonumber(arg[1]) or p[1], tonumber(arg[2]) or p[2]) +-- return +-- else +-- printf("Usage: scimark [-noffi] [-small|-large] [BENCH params...]\n\n") +-- printf("BENCH -small -large\n") +-- printf("---------------------------------------\n") +-- for _,name in ipairs(benchmarks) do +-- printf("%-7s %-13s %s\n", name, +-- fmtparams(unpack(benchmarks.small[name])), +-- fmtparams(unpack(benchmarks.large[name]))) +-- end +-- printf("\n") +-- os.exit(1) +-- end +--end local params = benchmarks[SIZE_SELECT] local sum = 0 diff --git a/tests/runner.py b/tests/runner.py index 610a39f6..bcd8e84c 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -133,7 +133,7 @@ class RunnerCore(unittest.TestCase): # Hardcode in the arguments, so js is portable without manual commandlinearguments if not args: return js = open(filename).read() - open(filename, 'w').write(js.replace('run();', 'run(%s);' % str(args))) + open(filename, 'w').write(js.replace('run();', 'run(%s + Module["arguments"]);' % str(args))) def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None): if ll_file.endswith(('.bc', '.o')): @@ -12698,7 +12698,7 @@ elif 'browser' in str(sys.argv): src = filename filename = 'main.cpp' else: - with open(filepath) as f: f.read() + with open(filepath) as f: src = f.read() with open(temp_filepath, 'w') as f: f.write(self.with_report_result(src)) else: expected = [str(i) for i in range(0, reference_slack+1)] @@ -13314,17 +13314,26 @@ elif 'benchmark' in str(sys.argv): f.close() final_filename = os.path.join(dirname, name + '.js') + open('hardcode.py', 'w').write(''' +def process(filename): + js = open(filename).read() + replaced = js.replace("run();", "run(%s.concat(Module[\\"arguments\\"]));") + assert js != replaced + open(filename, 'w').write(replaced) +import sys +process(sys.argv[1]) +''' % str(args[:-1]) # do not hardcode in the last argument, the default arg +) + try_delete(final_filename) output = Popen([PYTHON, EMCC, filename, #'-O3', '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', - '--llvm-lto', '1', '--memory-init-file', '0', + '--llvm-lto', '1', '--memory-init-file', '0', '--js-transform', 'python hardcode.py', '-s', 'TOTAL_MEMORY=128*1024*1024', '--closure', '1', '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] - self.hardcode_arguments(final_filename, args) - # Run JS global total_times, tests_done times = [] @@ -13650,7 +13659,7 @@ elif 'benchmark' in str(sys.argv): native_args = self.get_library('lua_native', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=True) self.do_benchmark('lua_' + benchmark, '', expected, - force_c=True, args=[benchmark + '.lua'], emcc_args=emcc_args, native_args=native_args, native_exec=os.path.join('building', 'lua_native', 'src', 'lua'), + force_c=True, args=[benchmark + '.lua', DEFAULT_ARG], emcc_args=emcc_args, native_args=native_args, native_exec=os.path.join('building', 'lua_native', 'src', 'lua'), output_parser=output_parser, args_processor=args_processor) def test_zzz_lua_scimark(self): @@ -13661,21 +13670,7 @@ elif 'benchmark' in str(sys.argv): def test_zzz_lua_binarytrees(self): # js version: ['binarytrees.lua', {0: 0, 1: 9.5, 2: 11.99, 3: 12.85, 4: 14.72, 5: 15.82}[arguments[0]]] - def args_processor(args): - arg = int(DEFAULT_ARG) - if arg == 0: - return args + ['0'] - elif arg == 1: - return args + ['9.5'] - elif arg == 2: - return args + ['11.99'] - elif arg == 3: - return args + ['12.85'] - elif arg == 4: - return args + ['14.72'] - elif arg == 5: - return args + ['15.82'] - self.lua('binarytrees', 'long lived tree of depth', args_processor=args_processor) + self.lua('binarytrees', 'long lived tree of depth') def test_zzz_zlib(self): src = open(path_from_root('tests', 'zlib', 'benchmark.c'), 'r').read() diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 7f186252..432c6208 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(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) { + 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) { @@ -1108,11 +1116,15 @@ function simplifyNotCompsDirect(node) { return node[2][2]; } } - return node; + if (!simplifyNotCompsPass) return node; } +var simplifyNotCompsPass = false; + function simplifyNotComps(ast) { + simplifyNotCompsPass = true; traverse(ast, simplifyNotCompsDirect); + simplifyNotCompsPass = false; } function simplifyExpressionsPost(ast) { diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js index 903de1f9..0e95580f 100644 --- a/tools/test-js-optimizer-asm-pre-output.js +++ b/tools/test-js-optimizer-asm-pre-output.js @@ -15,6 +15,10 @@ 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); + $56 = _fcntl() | 0 | 1; } 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..4f3ba780 100644 --- a/tools/test-js-optimizer-asm-pre.js +++ b/tools/test-js-optimizer-asm-pre.js @@ -16,6 +16,10 @@ 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); + $56 = (_fcntl() | 0) | 1; } function b($this, $__n) { $this = $this | 0; |