diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/eliminator/asm-eliminator-test-output.js | 10 | ||||
-rw-r--r-- | tools/eliminator/asm-eliminator-test.js | 10 | ||||
-rw-r--r-- | tools/eliminator/eliminator-test-output.js | 11 | ||||
-rw-r--r-- | tools/eliminator/eliminator-test.js | 17 | ||||
-rw-r--r-- | tools/file_packager.py | 108 | ||||
-rw-r--r-- | tools/js-optimizer.js | 55 | ||||
-rw-r--r-- | tools/shared.py | 6 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-pre-output.js | 8 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-pre.js | 4 |
9 files changed, 162 insertions, 67 deletions
diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 434fbaf9..a344fc35 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -280,9 +280,10 @@ function tempDouble2($46, $14, $28, $42, $20, $32, $45) { $20 = $20 | 0; $32 = $32 | 0; $45 = $45 | 0; - var $_sroa_06_0_insert_insert$1 = 0; + var $46 = 0, $_sroa_06_0_insert_insert$1 = 0; + $46 = (HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0); $_sroa_06_0_insert_insert$1 = (HEAPF32[tempDoublePtr >> 2] = ($20 < $32 ? $20 : $32) - $42, HEAP32[tempDoublePtr >> 2] | 0) | 0; - HEAP32[$45 >> 2] = 0 | (HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0); + HEAP32[$45 >> 2] = 0 | $46; HEAP32[$45 + 4 >> 2] = $_sroa_06_0_insert_insert$1; HEAP32[$45 + 8 >> 2] = $_sroa_06_0_insert_insert$1; } @@ -298,4 +299,9 @@ function select2($foundBase_0_off0) { STACKTOP = sp; return ($foundBase_0_off0 ? 0 : $call24) | 0; } +function binary(x) { + x = x | 0; + memset(f(x)) | 0; + +dmemset(f(x)); +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index 7ec277d5..4b45e4d4 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -370,5 +370,13 @@ function select2($foundBase_0_off0) { STACKTOP = sp; return $retval_0 | 0; } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2"] +function binary(x) { + x = x | 0; + var y = 0, z = 0; + y = f(x); + memset(y) | 0; + z = f(x); + +dmemset(z); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary"] diff --git a/tools/eliminator/eliminator-test-output.js b/tools/eliminator/eliminator-test-output.js index 0171e99b..4551fb34 100644 --- a/tools/eliminator/eliminator-test-output.js +++ b/tools/eliminator/eliminator-test-output.js @@ -6122,4 +6122,15 @@ function intoCond() { function math(a, b, c, d) { print(Math_imul(d) + (Math_fround(c) + (a + Math_abs(b)))); } +function td(x, y) { + HEAP32[tempDoublePtr >> 2] = x; + var xf = HEAPF32[tempDoublePtr >> 2]; + HEAP32[tempDoublePtr >> 2] = y; + func(xf, HEAPF32[tempDoublePtr >> 2]); + HEAPF64[tempDoublePtr >> 3] = x; + var xl = HEAP32[tempDoublePtr >> 2]; + var xh = HEAP32[tempDoublePtr >> 2]; + HEAPF64[tempDoublePtr >> 3] = y; + func(xl, xh, HEAP32[tempDoublePtr >> 2], HEAP32[tempDoublePtr >> 2]); +} diff --git a/tools/eliminator/eliminator-test.js b/tools/eliminator/eliminator-test.js index ef17b388..e629d9f0 100644 --- a/tools/eliminator/eliminator-test.js +++ b/tools/eliminator/eliminator-test.js @@ -8860,5 +8860,20 @@ function math(a, b, c, d) { w = Math_imul(d); print(x + y + z + w); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "c", "f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1", "_inflate", "_malloc", "_mallocNoU", "asm", "phi", "intoCond", "math"] +function td(x, y) { // tempDoublePtr should invalidate each other + HEAP32[tempDoublePtr>>2] = x; + var xf = HEAPF32[tempDoublePtr>>2]; + HEAP32[tempDoublePtr>>2] = y; + var yf = HEAPF32[tempDoublePtr>>2]; + func(xf, yf); + // + HEAPF64[tempDoublePtr>>3] = x; + var xl = HEAP32[tempDoublePtr>>2]; + var xh = HEAP32[tempDoublePtr>>2]; + HEAPF64[tempDoublePtr>>3] = y; + var yl = HEAP32[tempDoublePtr>>2]; + var yh = HEAP32[tempDoublePtr>>2]; + func(xl, xh, yl, yh); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "c", "f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1", "_inflate", "_malloc", "_mallocNoU", "asm", "phi", "intoCond", "math", "td"] diff --git a/tools/file_packager.py b/tools/file_packager.py index 7d9344cd..8b65b219 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -11,7 +11,7 @@ data downloads. Usage: - file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy] + file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy] --crunch=X Will compress dxt files to crn with quality level X. The crunch commandline tool must be present and CRUNCH should be defined in ~/.emscripten that points to it. JS crunch decompressing code will @@ -45,9 +45,10 @@ import posixpath import shared from shared import Compression, execute, suffix, unsuffixed from subprocess import Popen, PIPE, STDOUT +import fnmatch if len(sys.argv) == 1: - print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy] + print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--exclude C...] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy] See the source for more details.''' sys.exit(0) @@ -66,10 +67,10 @@ DDS_HEADER_SIZE = 128 AV_WORKAROUND = 0 # Set to 1 to randomize file order and add some padding, to work around silly av false positives data_files = [] -in_preload = False -in_embed = False +excluded_patterns = [] +leading = '' has_preloaded = False -in_compress = 0 +compress_cnt = 0 crunch = 0 plugins = [] jsoutput = None @@ -81,45 +82,40 @@ use_preload_cache = False # If set to False, the XHR blob is kept intact, and fread()s etc. are performed directly to that data. This optimizes for minimal memory usage and fread() performance. no_heap_copy = True -for arg in sys.argv[1:]: +for arg in sys.argv[2:]: if arg == '--preload': - in_preload = True - in_embed = False has_preloaded = True - in_compress = 0 + leading = 'preload' elif arg == '--embed': - in_embed = True - in_preload = False - in_compress = 0 + leading = 'embed' + elif arg == '--exclude': + leading = 'exclude' elif arg == '--compress': + compress_cnt = 1 Compression.on = True - in_compress = 1 - in_preload = False - in_embed = False + leading = 'compress' elif arg == '--no-force': force = False + leading = '' elif arg == '--use-preload-cache': use_preload_cache = True + leading = '' elif arg == '--no-heap-copy': no_heap_copy = False + leading = '' elif arg.startswith('--js-output'): jsoutput = arg.split('=')[1] if '=' in arg else None + leading = '' elif arg.startswith('--crunch'): from shared import CRUNCH crunch = arg.split('=')[1] if '=' in arg else '128' - in_preload = False - in_embed = False - in_compress = 0 + leading = '' elif arg.startswith('--plugin'): plugin = open(arg.split('=')[1], 'r').read() eval(plugin) # should append itself to plugins - in_preload = False - in_embed = False - in_compress = 0 - elif in_preload or in_embed: - mode = 'preload' - if in_embed: - mode = 'embed' + leading = '' + elif leading == 'preload' or leading == 'embed': + mode = leading if '@' in arg: srcpath, dstpath = arg.split('@') # User is specifying destination filename explicitly. else: @@ -128,16 +124,21 @@ for arg in sys.argv[1:]: data_files.append({ 'srcpath': srcpath, 'dstpath': dstpath, 'mode': mode }) else: print >> sys.stderr, 'Warning: ' + arg + ' does not exist, ignoring.' - elif in_compress: - if in_compress == 1: + elif leading == 'exclude': + excluded_patterns.append(arg) + elif leading == 'compress': + if compress_cnt == 1: Compression.encoder = arg - in_compress = 2 - elif in_compress == 2: + compress_cnt = 2 + elif compress_cnt == 2: Compression.decoder = arg - in_compress = 3 - elif in_compress == 3: + compress_cnt = 3 + elif compress_cnt == 3: Compression.js_name = arg - in_compress = 0 + compress_cnt = 0 + else: + print >> sys.stderr, 'Unknown parameter:', arg + sys.exit(1) if (not force) and len(data_files) == 0: has_preloaded = False @@ -172,16 +173,14 @@ def has_hidden_attribute(filepath): result = False return result -# The packager should never preload/embed any directories that have a component starting with '.' in them, -# or if the file is hidden (Win32). Note that this filter ONLY applies to directories. Explicitly specified single files -# are always preloaded/embedded, even if they start with a '.'. -def should_ignore(filename): - if has_hidden_attribute(filename): +# The packager should never preload/embed files if the file is hidden (Win32). +# or it matches any pattern specified in --exclude +def should_ignore(fullname): + if has_hidden_attribute(fullname): return True - components = filename.replace('\\\\', '/').replace('\\', '/').split('/') - for c in components: - if c.startswith('.') and c != '.' and c != '..': + for p in excluded_patterns: + if fnmatch.fnmatch(fullname, p): return True return False @@ -190,20 +189,31 @@ def add(arg, dirname, names): # rootpathsrc: The path name of the root directory on the local FS we are adding to emscripten virtual FS. # rootpathdst: The name we want to make the source path available on the emscripten virtual FS. mode, rootpathsrc, rootpathdst = arg + new_names = [] for name in names: fullname = os.path.join(dirname, name) - if not os.path.isdir(fullname): - if should_ignore(fullname): - if DEBUG: - print >> sys.stderr, 'Skipping hidden file "' + fullname + '" from inclusion in the emscripten virtual file system.' - else: + if should_ignore(fullname): + if DEBUG: + print >> sys.stderr, 'Skipping file "' + fullname + '" from inclusion in the emscripten virtual file system.' + else: + new_names.append(name) + if not os.path.isdir(fullname): dstpath = os.path.join(rootpathdst, os.path.relpath(fullname, rootpathsrc)) # Convert source filename relative to root directory of target FS. - data_files.append({ 'srcpath': fullname, 'dstpath': dstpath, 'mode': mode }) + new_data_files.append({ 'srcpath': fullname, 'dstpath': dstpath, 'mode': mode }) + del names[:] + names.extend(new_names) +new_data_files = [] for file_ in data_files: - if os.path.isdir(file_['srcpath']): - os.path.walk(file_['srcpath'], add, [file_['mode'], file_['srcpath'], file_['dstpath']]) -data_files = filter(lambda file_: not os.path.isdir(file_['srcpath']), data_files) + if not should_ignore(file_['srcpath']): + if os.path.isdir(file_['srcpath']): + os.path.walk(file_['srcpath'], add, [file_['mode'], file_['srcpath'], file_['dstpath']]) + else: + new_data_files.append(file_) +data_files = filter(lambda file_: not os.path.isdir(file_['srcpath']), new_data_files) +if len(data_files) == 0: + print >> sys.stderr, 'Nothing to do!' + sys.exit(1) # Absolutize paths, and check that they make sense curr_abspath = os.path.abspath(os.getcwd()) diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 57ce0071..161ed59c 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -271,6 +271,16 @@ function isEmptyNode(node) { return node.length === 2 && node[0] === 'toplevel' && node[1].length === 0; } +function clearEmptyNodes(list) { + for (var i = 0; i < list.length;) { + if (isEmptyNode(list[i]) || (list[i][0] === 'stat' && isEmptyNode(list[i][1]))) { + list.splice(i, 1); + } else { + i++; + } + } +} + // Passes // Dump the AST. Useful for debugging. For example, @@ -585,12 +595,24 @@ function simplifyExpressions(ast) { } } else if (type === 'assign') { // optimizations for assigning into HEAP32 specifically - if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name' && node[2][1][1] === 'HEAP32') { - // HEAP32[..] = x | 0 does not need the | 0 (unless it is a mandatory |0 of a call) - if (node[3][0] === 'binary' && node[3][1] === '|') { - if (node[3][2][0] === 'num' && node[3][2][1] === 0 && node[3][3][0] != 'call') { - node[3] = node[3][3]; - } else if (node[3][3][0] === 'num' && node[3][3][1] === 0 && node[3][2][0] != 'call') { + if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name') { + if (node[2][1][1] === 'HEAP32') { + // HEAP32[..] = x | 0 does not need the | 0 (unless it is a mandatory |0 of a call) + if (node[3][0] === 'binary' && node[3][1] === '|') { + if (node[3][2][0] === 'num' && node[3][2][1] === 0 && node[3][3][0] != 'call') { + node[3] = node[3][3]; + } else if (node[3][3][0] === 'num' && node[3][3][1] === 0 && node[3][2][0] != 'call') { + node[3] = node[3][2]; + } + } + } else if (node[2][1][1] === 'HEAP8') { + // HEAP8[..] = x & 0xff does not need the & 0xff + if (node[3][0] === 'binary' && node[3][1] === '&' && node[3][3][0] == 'num' && node[3][3][1] == 0xff) { + node[3] = node[3][2]; + } + } else if (node[2][1][1] === 'HEAP16') { + // HEAP16[..] = x & 0xffff does not need the & 0xffff + if (node[3][0] === 'binary' && node[3][1] === '&' && node[3][3][0] == 'num' && node[3][3][1] == 0xffff) { node[3] = node[3][2]; } } @@ -2122,7 +2144,7 @@ function registerize(ast) { // In memSafe mode, we are more careful and assume functions can replace HEAP and FUNCTION_TABLE, which // can happen in ALLOW_MEMORY_GROWTH mode -var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch'); // do is checked carefully, however +var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch', 'binary', 'unary-prefix'); // do is checked carefully, however var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break', 'continue', 'dot'); // dot can only be STRING_TABLE.* var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body) @@ -2412,7 +2434,12 @@ function eliminate(ast, memSafe) { if (allowTracking) track(name, node[3], node); } } else if (target[0] === 'sub') { - if (!isTempDoublePtrAccess(target) && !memoryInvalidated) { + if (isTempDoublePtrAccess(target)) { + if (!globalsInvalidated) { + invalidateGlobals(); + globalsInvalidated = true; + } + } else if (!memoryInvalidated) { invalidateMemory(); memoryInvalidated = true; } @@ -2672,6 +2699,7 @@ function eliminate(ast, memSafe) { } if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') { var assigns = ifFalse[1]; + clearEmptyNodes(assigns); var loopers = [], helpers = []; for (var i = 0; i < assigns.length; i++) { if (assigns[i][0] === 'stat' && assigns[i][1][0] === 'assign') { @@ -3097,6 +3125,17 @@ function outline(ast) { parts = []; var curr = node; while (1) { + if (!curr[3]) { + // we normally expect ..if (cond) { .. } else [if (nextCond) {] (in [] is what we hope to see) + // but are now seeing ..if (cond) { .. } with no else. This might be + // ..if (cond) if (nextCond) { + // which vacuum can generate from if (cond) {} else if (nextCond), making it + // if (!cond) if (nextCond) + // so we undo that, in hopes of making it more flattenable + curr[3] = curr[2]; + curr[2] = ['block', []]; + curr[1] = simplifyNotCompsDirect(['unary-prefix', '!', curr[1]]); + } parts.push({ condition: curr[1], body: curr[2] }); curr = curr[3]; if (!curr) break; diff --git a/tools/shared.py b/tools/shared.py index 443ff4c7..eb1c63be 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -322,7 +322,7 @@ def find_temp_directory(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.7.8' +EMSCRIPTEN_VERSION = '1.8.0' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT @@ -682,7 +682,7 @@ def line_splitter(data): return out -def limit_size(string, MAX=12000*20): +def limit_size(string, MAX=800*20): if len(string) < MAX: return string return string[0:MAX/2] + '\n[..]\n' + string[-MAX/2:] @@ -1094,7 +1094,7 @@ class Building: # 8k is a bit of an arbitrary limit, but a reasonable one # for max command line size before we use a respose file response_file = None - if WINDOWS and len(' '.join(link_cmd)) > 8192: + if len(' '.join(link_cmd)) > 8192: logging.debug('using response file for llvm-link') [response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR) diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js index 2e3db000..0fa81050 100644 --- a/tools/test-js-optimizer-asm-pre-output.js +++ b/tools/test-js-optimizer-asm-pre-output.js @@ -58,12 +58,14 @@ function b($this, $__n) { _memset($38 + $23 | 0, 0, $__n | 0, 1, 1213141516); $40 = $23 + $__n | 0; if ((HEAP8[$4 & 16777215] & 1) == 0) { - HEAP8[$4 & 16777215] = $40 << 1 & 255; + HEAP8[$4 & 16777215] = $40 << 1; } else { HEAP32[($this + 4 & 16777215) >> 2] = $40; } HEAP8[$38 + $40 & 16777215] = 0; HEAP32[$4] = ~HEAP32[$5]; + HEAP8[$4] = HEAP32[$5]; + HEAP16[$4] = HEAP32[$5]; HEAP32[$4] = ~HEAP32[$5]; HEAP32[$4] = ~HEAP32[$5]; h(~~g ^ -1); @@ -240,10 +242,10 @@ function _main($argc, $argv) { } if (($i_09_i_i | 0) > (HEAP32[9600 + ($j_08_i_i << 2) >> 2] | 0)) { $34 = $j_08_i_i + 1 | 0; - HEAP8[$i_09_i_i + 8952 | 0] = $34 & 255; + HEAP8[$i_09_i_i + 8952 | 0] = $34; $j_1_i_i = $34; } else { - HEAP8[$i_09_i_i + 8952 | 0] = $j_08_i_i & 255; + HEAP8[$i_09_i_i + 8952 | 0] = $j_08_i_i; $j_1_i_i = $j_08_i_i; } $38 = $i_09_i_i + 1 | 0; diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js index 9e6edf0f..dadeef53 100644 --- a/tools/test-js-optimizer-asm-pre.js +++ b/tools/test-js-optimizer-asm-pre.js @@ -66,6 +66,10 @@ function b($this, $__n) { HEAP8[($38 + $40 | 0) & 16777215] = 0; // Eliminate the |0. HEAP32[$4] = ((~(HEAP32[$5]|0))|0); + // Eliminate the &255 + HEAP8[$4] = HEAP32[$5]&255; + // Eliminate the &65535 + HEAP16[$4] = HEAP32[$5]&65535; // Rewrite to ~. HEAP32[$4] = HEAP32[$5]^-1; // Rewrite to ~ and eliminate the |0. |