diff options
30 files changed, 1518 insertions, 164 deletions
@@ -79,6 +79,7 @@ import os, sys, shutil, tempfile, subprocess, shlex, time, re from subprocess import PIPE, STDOUT from tools import shared from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename +from tools.response_file import read_response_file # Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt # levels 2 and 3 (emcc 3 is unsafe opts, so unsuitable for the only level to get @@ -129,19 +130,10 @@ while response_file: for index in range(1, len(sys.argv)): if sys.argv[index][0] == '@': # found one, loop again next time - response_file = sys.argv[index][1:] - print >>sys.stderr, 'emcc: using response file: %s' % response_file - if not os.path.exists(response_file): - print >>sys.stderr, 'emcc: error: Response file not found: %s' % response_file - exit(1) - - response_fd = open(response_file, 'r') - extra_args = shlex.split(response_fd.read()) - response_fd.close() - + response_file = True + extra_args = read_response_file(sys.argv[index]) # slice in extra_args in place of the response file arg sys.argv[index:index+1] = extra_args - #if DEBUG: print >>sys.stderr, "Expanded response file: " + " | ".join(sys.argv) break if sys.argv[1] == '--version': @@ -473,7 +465,7 @@ Options that are modified or new in %s include: --memory-init-file <on> If on, we generate a separate memory initialization file. This is more efficient than storing the memory initialization data embedded inside - JavaScript as text. (default is on) + JavaScript as text. (default is off) The target file, if specified (-o <target>), defines what will be generated: @@ -483,8 +475,8 @@ be generated: <name>.bc LLVM bitcode (default) <name>.o LLVM bitcode (same as .bc) -Note that if --memory-init-file is used, then in addition to a -.js or .html file that is generated, a .mem file will also appear. +(Note that if --memory-init-file is used, then in addition to a +.js or .html file that is generated, a .mem file will also appear.) The -c option (which tells gcc not to run the linker) will cause LLVM bitcode to be generated, as %s only generates @@ -519,7 +511,7 @@ CONFIGURE_CONFIG = (os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in CMAKE_CONFIG = 'CMakeFiles/cmTryCompileExec.dir' in ' '.join(sys.argv)# or 'CMakeCCompilerId' in ' '.join(sys.argv) if CONFIGURE_CONFIG or CMAKE_CONFIG: debug_configure = 0 # XXX use this to debug configure stuff. ./configure's generally hide our normal output including stderr so we write to a file - use_clang = 1 # whether we fake configure tests using clang - the local, native compiler - or not. if not we generate JS and use node with a shebang + use_js = os.environ.get('EMCONFIGURE_JS') # whether we fake configure tests using clang - the local, native compiler - or not. if not we generate JS and use node with a shebang # neither approach is perfect, you can try both, but may need to edit configure scripts in some cases # XXX False is not fully tested yet @@ -536,13 +528,16 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: if debug_configure: open(tempout, 'a').write('============= ' + sys.argv[i] + '\n' + src + '\n=============\n\n') except: pass + if sys.argv[i].endswith('.s'): + if debug_configure: open(tempout, 'a').write('(compiling .s assembly, must use clang\n') + use_js = 0 if src: if 'fopen' in src and '"w"' in src: - use_clang = True # we cannot write to files from js! + use_js = 0 # we cannot write to files from js! if debug_configure: open(tempout, 'a').write('Forcing clang since uses fopen to write\n') - compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if use_clang else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that + compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if not use_js else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that if not ('CXXCompiler' in ' '.join(sys.argv) or os.environ.get('EMMAKEN_CXX')): compiler = shared.to_cc(compiler) @@ -561,12 +556,12 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: idx += 1 cmd = [compiler] + list(filter_emscripten_options(sys.argv[1:])) - if use_clang: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN'] + if not use_js: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN'] if DEBUG: print >> sys.stderr, 'emcc, just configuring: ', ' '.join(cmd) if debug_configure: open(tempout, 'a').write('emcc, just configuring: ' + ' '.join(cmd) + '\n\n') - if use_clang: + if not use_js: exit(subprocess.call(cmd)) else: only_object = '-c' in cmd @@ -589,7 +584,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: shutil.copyfile(target, target[:-3]) target = target[:-3] src = open(target).read() - full_node = shared.NODE_JS + full_node = ' '.join(shared.listify(shared.NODE_JS)) if os.path.sep not in full_node: full_node = '/usr/bin/' + full_node # TODO: use whereis etc. And how about non-*NIX? open(target, 'w').write('#!' + full_node + '\n' + src) # add shebang @@ -724,7 +719,7 @@ try: bind = False jcache = False save_bc = False - memory_init_file = True + memory_init_file = False if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. diff --git a/emscripten.py b/emscripten.py index 996e5cc3..6e5f1e7c 100755 --- a/emscripten.py +++ b/emscripten.py @@ -12,6 +12,7 @@ headers, for the libc implementation in JS). import os, sys, json, optparse, subprocess, re, time, multiprocessing, functools from tools import jsrun, cache as cache_module, tempfiles +from tools.response_file import read_response_file __rootpath__ = os.path.abspath(os.path.dirname(__file__)) def path_from_root(*pathelems): @@ -347,6 +348,14 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if settings.get('ASM_JS'): post_funcs, post_rest = post.split('// EMSCRIPTEN_END_FUNCS\n') post = post_rest + + # Move preAsms to their right place + def move_preasm(m): + contents = m.groups(0)[0] + outfile.write(contents + '\n') + return '' + post_funcs = re.sub(r'/\* PRE_ASM \*/(.*)\n', lambda m: move_preasm(m), post_funcs) + funcs_js += ['\n' + post_funcs + '// EMSCRIPTEN_END_FUNCS\n'] simple = os.environ.get('EMCC_SIMPLE_ASM') @@ -384,15 +393,12 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] - if forwarded_json['Types']['preciseI64MathUsed']: - basic_funcs += ['i64Math_' + op for op in ['add', 'subtract', 'multiply', 'divide', 'modulo']] - asm_setup += ''' -var i64Math_add = function(a, b, c, d) { i64Math.add(a, b, c, d) }; -var i64Math_subtract = function(a, b, c, d) { i64Math.subtract(a, b, c, d) }; -var i64Math_multiply = function(a, b, c, d) { i64Math.multiply(a, b, c, d) }; -var i64Math_divide = function(a, b, c, d, e) { i64Math.divide(a, b, c, d, e) }; -var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; -''' + + if forwarded_json['Types']['preciseI64MathUsed'] or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32') or \ + forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32'): + basic_vars += ['cttz_i8', 'ctlz_i8'] + asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables def asm_coerce(value, sig): @@ -442,7 +448,7 @@ function invoke_%s(%s) { pass # If no named globals, only need externals global_vars = map(lambda g: g['name'], filter(lambda g: settings['NAMED_GLOBALS'] or g.get('external') or g.get('unIndexable'), forwarded_json['Variables']['globals'].values())) - global_funcs = ['_' + x for x in forwarded_json['Functions']['libraryFunctions'].keys()] + global_funcs = ['_' + key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2] def math_fix(g): return g if not g.startswith('Math_') else g.split('_')[1]; asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global.' + g + ';\n' for g in maths]) + \ @@ -643,6 +649,18 @@ def main(args, compiler_engine, cache, jcache, relooper, temp_files, DEBUG, DEBU jcache=jcache, temp_files=temp_files, DEBUG=DEBUG, DEBUG_CACHE=DEBUG_CACHE) def _main(environ): + response_file = True + while response_file: + response_file = None + for index in range(1, len(sys.argv)): + if sys.argv[index][0] == '@': + # found one, loop again next time + response_file = True + response_file_args = read_response_file(sys.argv[index]) + # slice in extra_args in place of the response file arg + sys.argv[index:index+1] = response_file_args + break + parser = optparse.OptionParser( usage='usage: %prog [-h] [-H HEADERS] [-o OUTFILE] [-c COMPILER_ENGINE] [-s FOO=BAR]* infile', description=('You should normally never use this! Use emcc instead. ' diff --git a/src/analyzer.js b/src/analyzer.js index c10f18cc..df5a435e 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -124,6 +124,10 @@ function analyzer(data, sidePass) { bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }]; if (isNumber(base)) return getLegalLiterals(base, bits); + if (base[0] == '{') { + warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit'); + return getLegalLiterals('0', bits); + } var ret = new Array(Math.ceil(bits/32)); var i = 0; if (base == 'zeroinitializer' || base == 'undef') base = 0; @@ -320,12 +324,13 @@ function analyzer(data, sidePass) { } // call, return: Return the first 32 bits, the rest are in temp case 'call': { - bits = getBits(value.type); - var elements = getLegalVars(item.assignTo, bits); var toAdd = [value]; // legalize parameters legalizeFunctionParameters(value.params); + // legalize return value, if any if (value.assignTo && isIllegalType(item.type)) { + bits = getBits(value.type); + var elements = getLegalVars(item.assignTo, bits); // legalize return value value.assignTo = elements[0].ident; for (var j = 1; j < elements.length; j++) { diff --git a/src/fastLong.js b/src/fastLong.js new file mode 100644 index 00000000..95f398db --- /dev/null +++ b/src/fastLong.js @@ -0,0 +1,298 @@ +// ======== compiled code from system/lib/compiler-rt , see readme therein +function ___muldsi3($a, $b) { + $a = $a | 0; + $b = $b | 0; + 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); + $6 = $a >>> 16; + $8 = ($3 >>> 16) + Math.imul($2, $6) | 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; +} +function ___divdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $1$0 = 0, $1$1 = 0, $2$0 = 0, $2$1 = 0, $4$0 = 0, $4$1 = 0, $6$0 = 0, $7$0 = 0, $7$1 = 0, $8$0 = 0, $10$0 = 0; + $1$0 = $a$1 >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$1 = tempRet0; + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + $7$0 = $2$0 ^ $1$0; + $7$1 = $2$1 ^ $1$1; + $8$0 = ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, 0) | 0; + $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1); + return (tempRet0 = tempRet0, $10$0) | 0; +} +function ___remdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $rem = 0, $1$0 = 0, $1$1 = 0, $2$0 = 0, $2$1 = 0, $4$0 = 0, $4$1 = 0, $6$0 = 0, $10$0 = 0, $10$1 = 0, __stackBase__ = 0; + __stackBase__ = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + $rem = __stackBase__ | 0; + $1$0 = $a$1 >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; + $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$1 = tempRet0; + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem); + $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1); + $10$1 = tempRet0; + STACKTOP = __stackBase__; + return (tempRet0 = $10$1, $10$0) | 0; +} +function ___muldi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $x_sroa_0_0_extract_trunc = 0, $y_sroa_0_0_extract_trunc = 0, $1$0 = 0, $1$1 = 0, $2 = 0; + $x_sroa_0_0_extract_trunc = $a$0; + $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; +} +function ___udivdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $1$0 = 0; + $1$0 = ___udivmoddi4($a$0, $a$1, $b$0, $b$1, 0) | 0; + return (tempRet0 = tempRet0, $1$0) | 0; +} +function ___uremdi3($a$0, $a$1, $b$0, $b$1) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + var $rem = 0, __stackBase__ = 0; + __stackBase__ = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + $rem = __stackBase__ | 0; + ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem); + STACKTOP = __stackBase__; + return (tempRet0 = HEAP32[$rem + 4 >> 2] | 0, HEAP32[$rem >> 2] | 0) | 0; +} +function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { + $a$0 = $a$0 | 0; + $a$1 = $a$1 | 0; + $b$0 = $b$0 | 0; + $b$1 = $b$1 | 0; + $rem = $rem | 0; + var $n_sroa_0_0_extract_trunc = 0, $n_sroa_1_4_extract_shift$0 = 0, $n_sroa_1_4_extract_trunc = 0, $d_sroa_0_0_extract_trunc = 0, $d_sroa_1_4_extract_shift$0 = 0, $d_sroa_1_4_extract_trunc = 0, $4 = 0, $17 = 0, $37 = 0, $49 = 0, $51 = 0, $57 = 0, $58 = 0, $66 = 0, $78 = 0, $86 = 0, $88 = 0, $89 = 0, $91 = 0, $92 = 0, $95 = 0, $105 = 0, $117 = 0, $119 = 0, $125 = 0, $126 = 0, $130 = 0, $q_sroa_1_1_ph = 0, $q_sroa_0_1_ph = 0, $r_sroa_1_1_ph = 0, $r_sroa_0_1_ph = 0, $sr_1_ph = 0, $d_sroa_0_0_insert_insert99$0 = 0, $d_sroa_0_0_insert_insert99$1 = 0, $137$0 = 0, $137$1 = 0, $carry_0203 = 0, $sr_1202 = 0, $r_sroa_0_1201 = 0, $r_sroa_1_1200 = 0, $q_sroa_0_1199 = 0, $q_sroa_1_1198 = 0, $147 = 0, $149 = 0, $r_sroa_0_0_insert_insert42$0 = 0, $r_sroa_0_0_insert_insert42$1 = 0, $150$1 = 0, $151$0 = 0, $152 = 0, $154$0 = 0, $r_sroa_0_0_extract_trunc = 0, $r_sroa_1_4_extract_trunc = 0, $155 = 0, $carry_0_lcssa$0 = 0, $carry_0_lcssa$1 = 0, $r_sroa_0_1_lcssa = 0, $r_sroa_1_1_lcssa = 0, $q_sroa_0_1_lcssa = 0, $q_sroa_1_1_lcssa = 0, $q_sroa_0_0_insert_ext75$0 = 0, $q_sroa_0_0_insert_ext75$1 = 0, $q_sroa_0_0_insert_insert77$1 = 0, $_0$0 = 0, $_0$1 = 0; + $n_sroa_0_0_extract_trunc = $a$0; + $n_sroa_1_4_extract_shift$0 = $a$1; + $n_sroa_1_4_extract_trunc = $n_sroa_1_4_extract_shift$0; + $d_sroa_0_0_extract_trunc = $b$0; + $d_sroa_1_4_extract_shift$0 = $b$1; + $d_sroa_1_4_extract_trunc = $d_sroa_1_4_extract_shift$0; + if (($n_sroa_1_4_extract_trunc | 0) == 0) { + $4 = ($rem | 0) != 0; + if (($d_sroa_1_4_extract_trunc | 0) == 0) { + if ($4) { + HEAP32[$rem >> 2] = ($n_sroa_0_0_extract_trunc >>> 0) % ($d_sroa_0_0_extract_trunc >>> 0); + HEAP32[$rem + 4 >> 2] = 0; + } + $_0$1 = 0; + $_0$0 = ($n_sroa_0_0_extract_trunc >>> 0) / ($d_sroa_0_0_extract_trunc >>> 0) >>> 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } else { + if (!$4) { + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + HEAP32[$rem >> 2] = $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $a$1 & 0; + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + } + $17 = ($d_sroa_1_4_extract_trunc | 0) == 0; + do { + if (($d_sroa_0_0_extract_trunc | 0) == 0) { + if ($17) { + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = ($n_sroa_1_4_extract_trunc >>> 0) % ($d_sroa_0_0_extract_trunc >>> 0); + HEAP32[$rem + 4 >> 2] = 0; + } + $_0$1 = 0; + $_0$0 = ($n_sroa_1_4_extract_trunc >>> 0) / ($d_sroa_0_0_extract_trunc >>> 0) >>> 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + if (($n_sroa_0_0_extract_trunc | 0) == 0) { + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = 0; + HEAP32[$rem + 4 >> 2] = ($n_sroa_1_4_extract_trunc >>> 0) % ($d_sroa_1_4_extract_trunc >>> 0); + } + $_0$1 = 0; + $_0$0 = ($n_sroa_1_4_extract_trunc >>> 0) / ($d_sroa_1_4_extract_trunc >>> 0) >>> 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + $37 = $d_sroa_1_4_extract_trunc - 1 | 0; + if (($37 & $d_sroa_1_4_extract_trunc | 0) == 0) { + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = 0 | $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $37 & $n_sroa_1_4_extract_trunc | $a$1 & 0; + } + $_0$1 = 0; + $_0$0 = $n_sroa_1_4_extract_trunc >>> ((_llvm_cttz_i32($d_sroa_1_4_extract_trunc | 0) | 0) >>> 0); + return (tempRet0 = $_0$1, $_0$0) | 0; + } + $49 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc | 0) | 0; + $51 = $49 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc | 0) | 0) | 0; + if ($51 >>> 0 <= 30) { + $57 = $51 + 1 | 0; + $58 = 31 - $51 | 0; + $sr_1_ph = $57; + $r_sroa_0_1_ph = $n_sroa_1_4_extract_trunc << $58 | $n_sroa_0_0_extract_trunc >>> ($57 >>> 0); + $r_sroa_1_1_ph = $n_sroa_1_4_extract_trunc >>> ($57 >>> 0); + $q_sroa_0_1_ph = 0; + $q_sroa_1_1_ph = $n_sroa_0_0_extract_trunc << $58; + break; + } + if (($rem | 0) == 0) { + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + HEAP32[$rem >> 2] = 0 | $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $n_sroa_1_4_extract_shift$0 | $a$1 & 0; + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } else { + if (!$17) { + $117 = _llvm_ctlz_i32($d_sroa_1_4_extract_trunc | 0) | 0; + $119 = $117 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc | 0) | 0) | 0; + if ($119 >>> 0 <= 31) { + $125 = $119 + 1 | 0; + $126 = 31 - $119 | 0; + $130 = $119 - 31 >> 31; + $sr_1_ph = $125; + $r_sroa_0_1_ph = $n_sroa_0_0_extract_trunc >>> ($125 >>> 0) & $130 | $n_sroa_1_4_extract_trunc << $126; + $r_sroa_1_1_ph = $n_sroa_1_4_extract_trunc >>> ($125 >>> 0) & $130; + $q_sroa_0_1_ph = 0; + $q_sroa_1_1_ph = $n_sroa_0_0_extract_trunc << $126; + break; + } + if (($rem | 0) == 0) { + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + HEAP32[$rem >> 2] = 0 | $a$0 & -1; + HEAP32[$rem + 4 >> 2] = $n_sroa_1_4_extract_shift$0 | $a$1 & 0; + $_0$1 = 0; + $_0$0 = 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + $66 = $d_sroa_0_0_extract_trunc - 1 | 0; + if (($66 & $d_sroa_0_0_extract_trunc | 0) != 0) { + $86 = (_llvm_ctlz_i32($d_sroa_0_0_extract_trunc | 0) | 0) + 33 | 0; + $88 = $86 - (_llvm_ctlz_i32($n_sroa_1_4_extract_trunc | 0) | 0) | 0; + $89 = 64 - $88 | 0; + $91 = 32 - $88 | 0; + $92 = $91 >> 31; + $95 = $88 - 32 | 0; + $105 = $95 >> 31; + $sr_1_ph = $88; + $r_sroa_0_1_ph = $91 - 1 >> 31 & $n_sroa_1_4_extract_trunc >>> ($95 >>> 0) | ($n_sroa_1_4_extract_trunc << $91 | $n_sroa_0_0_extract_trunc >>> ($88 >>> 0)) & $105; + $r_sroa_1_1_ph = $105 & $n_sroa_1_4_extract_trunc >>> ($88 >>> 0); + $q_sroa_0_1_ph = $n_sroa_0_0_extract_trunc << $89 & $92; + $q_sroa_1_1_ph = ($n_sroa_1_4_extract_trunc << $89 | $n_sroa_0_0_extract_trunc >>> ($95 >>> 0)) & $92 | $n_sroa_0_0_extract_trunc << $91 & $88 - 33 >> 31; + break; + } + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = $66 & $n_sroa_0_0_extract_trunc; + HEAP32[$rem + 4 >> 2] = 0; + } + if (($d_sroa_0_0_extract_trunc | 0) == 1) { + $_0$1 = $n_sroa_1_4_extract_shift$0 | $a$1 & 0; + $_0$0 = 0 | $a$0 & -1; + return (tempRet0 = $_0$1, $_0$0) | 0; + } else { + $78 = _llvm_cttz_i32($d_sroa_0_0_extract_trunc | 0) | 0; + $_0$1 = 0 | $n_sroa_1_4_extract_trunc >>> ($78 >>> 0); + $_0$0 = $n_sroa_1_4_extract_trunc << 32 - $78 | $n_sroa_0_0_extract_trunc >>> ($78 >>> 0) | 0; + return (tempRet0 = $_0$1, $_0$0) | 0; + } + } + } while (0); + if (($sr_1_ph | 0) == 0) { + $q_sroa_1_1_lcssa = $q_sroa_1_1_ph; + $q_sroa_0_1_lcssa = $q_sroa_0_1_ph; + $r_sroa_1_1_lcssa = $r_sroa_1_1_ph; + $r_sroa_0_1_lcssa = $r_sroa_0_1_ph; + $carry_0_lcssa$1 = 0; + $carry_0_lcssa$0 = 0; + } else { + $d_sroa_0_0_insert_insert99$0 = 0 | $b$0 & -1; + $d_sroa_0_0_insert_insert99$1 = $d_sroa_1_4_extract_shift$0 | $b$1 & 0; + $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1); + $137$1 = tempRet0; + $q_sroa_1_1198 = $q_sroa_1_1_ph; + $q_sroa_0_1199 = $q_sroa_0_1_ph; + $r_sroa_1_1200 = $r_sroa_1_1_ph; + $r_sroa_0_1201 = $r_sroa_0_1_ph; + $sr_1202 = $sr_1_ph; + $carry_0203 = 0; + while (1) { + $147 = $q_sroa_0_1199 >>> 31 | $q_sroa_1_1198 << 1; + $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); + $150$1 = tempRet0; + $151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1; + $152 = $151$0 & 1; + $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1); + $r_sroa_0_0_extract_trunc = $154$0; + $r_sroa_1_4_extract_trunc = tempRet0; + $155 = $sr_1202 - 1 | 0; + if (($155 | 0) == 0) { + break; + } else { + $q_sroa_1_1198 = $147; + $q_sroa_0_1199 = $149; + $r_sroa_1_1200 = $r_sroa_1_4_extract_trunc; + $r_sroa_0_1201 = $r_sroa_0_0_extract_trunc; + $sr_1202 = $155; + $carry_0203 = $152; + } + } + $q_sroa_1_1_lcssa = $147; + $q_sroa_0_1_lcssa = $149; + $r_sroa_1_1_lcssa = $r_sroa_1_4_extract_trunc; + $r_sroa_0_1_lcssa = $r_sroa_0_0_extract_trunc; + $carry_0_lcssa$1 = 0; + $carry_0_lcssa$0 = $152; + } + $q_sroa_0_0_insert_ext75$0 = $q_sroa_0_1_lcssa; + $q_sroa_0_0_insert_ext75$1 = 0; + $q_sroa_0_0_insert_insert77$1 = $q_sroa_1_1_lcssa | $q_sroa_0_0_insert_ext75$1; + if (($rem | 0) != 0) { + HEAP32[$rem >> 2] = 0 | $r_sroa_0_1_lcssa; + HEAP32[$rem + 4 >> 2] = $r_sroa_1_1_lcssa | 0; + } + $_0$1 = (0 | $q_sroa_0_0_insert_ext75$0) >>> 31 | $q_sroa_0_0_insert_insert77$1 << 1 | ($q_sroa_0_0_insert_ext75$1 << 1 | $q_sroa_0_0_insert_ext75$0 >>> 31) & 0 | $carry_0_lcssa$1; + $_0$0 = ($q_sroa_0_0_insert_ext75$0 << 1 | 0 >>> 31) & -2 | $carry_0_lcssa$0; + return (tempRet0 = $_0$1, $_0$0) | 0; +} +// ======================================================================= diff --git a/src/jsifier.js b/src/jsifier.js index 2a9dc5bd..926be71a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -468,7 +468,7 @@ function JSify(data, functionsOnly, givenFunctions) { asmLibraryFunctions.push(contentText); contentText = ' '; EXPORTED_FUNCTIONS[ident] = 1; - delete Functions.libraryFunctions[ident.substr(1)]; + Functions.libraryFunctions[ident.substr(1)] = 2; } } if ((!ASM_JS || phase == 'pre') && @@ -1149,9 +1149,7 @@ function JSify(data, functionsOnly, givenFunctions) { } // If there is no current exception, set this one as it (during a resume, the current exception can be wiped out) var ptr = makeStructuralAccess(item.ident, 0); - return (EXCEPTION_DEBUG ? 'Module.print("Resuming exception");' : '') + - 'if (' + makeGetValue('_llvm_eh_exception.buf', 0, 'void*') + ' == 0) { ' + makeSetValue('_llvm_eh_exception.buf', 0, ptr, 'void*') + ' } ' + - makeThrow(ptr) + ';'; + return '___resumeException(' + asmCoercion(ptr, 'i32') + ')'; }); makeFuncLineActor('invoke', function(item) { // Wrapping in a function lets us easily return values if we are @@ -1162,8 +1160,10 @@ function JSify(data, functionsOnly, givenFunctions) { var ret; - if (disabled || ASM_JS) { // TODO: EXCEPTION_DEBUG for asm.js + if (disabled) { ret = call_ + ';'; + } else if (ASM_JS) { + ret = '(__THREW__ = 0,' + call_ + ');'; } else { ret = '(function() { try { __THREW__ = 0; return ' + call_ + ' ' @@ -1210,8 +1210,8 @@ function JSify(data, functionsOnly, givenFunctions) { } }); makeFuncLineActor('landingpad', function(item) { - var catchTypeArray = item.catchables.map(finalizeLLVMParameter).join(','); - var ret = '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')'; + var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); + var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); if (USE_TYPED_ARRAYS == 2) { ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;'; item.assignTo = null; @@ -1348,7 +1348,7 @@ function JSify(data, functionsOnly, givenFunctions) { args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); if (ASM_JS) { - if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions) { + if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced) { args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); } else { args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); @@ -1426,10 +1426,12 @@ function JSify(data, functionsOnly, givenFunctions) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - if (!forceByPointer) { + if (!byPointerForced) { callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py } else { - // add initial argument for invoke. note: no need to update argsTypes at this point + // This is a forced call, through an invoke_*. + // note: no need to update argsTypes at this point + Functions.unimplementedFunctions[callIdent] = sig; args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent); callIdent = 'invoke_' + sig; } @@ -1604,10 +1606,26 @@ function JSify(data, functionsOnly, givenFunctions) { // "Final shape that will be created"). if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { if (!INCLUDE_FULL_LIBRARY) { - ['i64Add', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr'].forEach(function(func) { - print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code - Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; + // first row are utilities called from generated code, second are needed from fastLong + ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr', + 'llvm_ctlz_i32', 'llvm_cttz_i32'].forEach(function(func) { + if (!Functions.libraryFunctions[func]) { + print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code + Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; + Functions.libraryFunctions[func] = 1; + // limited dependency handling + var deps = LibraryManager.library[func + '__deps']; + if (deps) { + deps.forEach(function(dep) { + assert(typeof dep == 'function'); + var text = dep(); + assert(text.indexOf('\n') < 0); + print('/* PRE_ASM */ ' + text + '\n'); + }); + } + } }); + print(read('fastLong.js')); } print('// EMSCRIPTEN_END_FUNCS\n'); print(read('long.js')); diff --git a/src/library.js b/src/library.js index f58c7150..11f30a1c 100644 --- a/src/library.js +++ b/src/library.js @@ -4913,16 +4913,20 @@ LibraryManager.library = { } return 8; } - return 'var ctlz_i8 = [' + range(256).map(function(x) { return ctlz(x) }).join(',') + '];'; + return 'var ctlz_i8 = allocate([' + range(256).map(function(x) { return ctlz(x) }).join(',') + '], "i8", ALLOC_STACK);'; }], + llvm_ctlz_i32__asm: true, + llvm_ctlz_i32__sig: 'ii', llvm_ctlz_i32: function(x) { - var ret = ctlz_i8[x >>> 24]; - if (ret < 8) return ret; - var ret = ctlz_i8[(x >> 16)&0xff]; - if (ret < 8) return ret + 8; - var ret = ctlz_i8[(x >> 8)&0xff]; - if (ret < 8) return ret + 16; - return ctlz_i8[x&0xff] + 24; + x = x|0; + var ret = 0; + ret = {{{ makeGetValueAsm('ctlz_i8', 'x >>> 24', 'i8') }}}; + if ((ret|0) < 8) return ret|0; + var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 8)|0; + var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 16)|0; + return ({{{ makeGetValueAsm('ctlz_i8', 'x&0xff', 'i8') }}} + 24)|0; }, llvm_ctlz_i64__deps: ['llvm_ctlz_i32'], @@ -4945,16 +4949,20 @@ LibraryManager.library = { } return 8; } - return 'var cttz_i8 = [' + range(256).map(function(x) { return cttz(x) }).join(',') + '];'; + return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STACK);'; }], + llvm_cttz_i32__asm: true, + llvm_cttz_i32__sig: 'ii', llvm_cttz_i32: function(x) { - var ret = cttz_i8[x & 0xff]; - if (ret < 8) return ret; - var ret = cttz_i8[(x >> 8)&0xff]; - if (ret < 8) return ret + 8; - var ret = cttz_i8[(x >> 16)&0xff]; - if (ret < 8) return ret + 16; - return cttz_i8[x >>> 24] + 24; + x = x|0; + var ret = 0; + ret = {{{ makeGetValueAsm('cttz_i8', 'x & 0xff', 'i8') }}}; + if ((ret|0) < 8) return ret|0; + var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 8)|0; + var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}}; + if ((ret|0) < 8) return (ret + 16)|0; + return ({{{ makeGetValueAsm('cttz_i8', 'x >>> 24', 'i8') }}} + 24)|0; }, llvm_cttz_i64__deps: ['llvm_cttz_i32'], @@ -5156,8 +5164,10 @@ LibraryManager.library = { // functionality boils down to picking a suitable 'catch' block. // We'll do that here, instead, to keep things simpler. - __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type'], + __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException'], __cxa_find_matching_catch: function(thrown, throwntype) { + if (thrown == -1) thrown = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; + if (throwntype == -1) throwntype = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}}; var typeArray = Array.prototype.slice.call(arguments, 2); // If throwntype is a pointer, this means a pointer has been @@ -5183,6 +5193,15 @@ LibraryManager.library = { {{{ makeStructuralReturn(['thrown', 'throwntype']) }}}; }, + __resumeException__deps: [function() { Functions.libraryFunctions['__resumeException'] = 1 }], // will be called directly from compiled code + __resumeException: function(ptr) { +#if EXCEPTION_DEBUG + Module.print("Resuming exception"); +#endif + if ({{{ makeGetValue('_llvm_eh_exception.buf', 0, 'void*') }}} == 0) {{{ makeSetValue('_llvm_eh_exception.buf', 0, 'ptr', 'void*') }}}; + {{{ makeThrow('ptr') }}}; + }, + // Recursively walks up the base types of 'possibilityType' // to see if any of them match 'definiteType'. __cxa_does_inherit__deps: ['__cxa_is_number_type'], @@ -5285,9 +5304,11 @@ LibraryManager.library = { llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }], llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) { - i64Math.multiply(xl, xh, yl, yh); - {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32'), '0']) }}}; - // XXX Need to hack support for second param in long.js +#if ASSERTIONS + Runtime.warnOnce('no overflow support in llvm_umul_with_overflow_i64'); +#endif + var low = ___muldi3(xl, xh, yl, yh); + {{{ makeStructuralReturn(['low', 'tempRet0', '0']) }}}; }, llvm_stacksave: function() { @@ -7471,13 +7492,27 @@ LibraryManager.library = { var l = 0, h = 0, overflow = 0; l = (a + c)>>>0; h = (b + d)>>>0; - if ((l>>>0) < (a>>>0)) { // iff we overflowed + if ((h>>>0) < (b>>>0)) overflow = 1; + if ((l>>>0) < (a>>>0)) { h = (h+1)>>>0; - overflow = 1; + if ((h>>>0) == 0) overflow = 1; // two possibilities to overflow here } {{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}}; }, + i64Subtract__asm: true, + i64Subtract__sig: 'iiiii', + i64Subtract: function(a, b, c, d) { + a = a|0; b = b|0; c = c|0; d = d|0; + var l = 0, h = 0; + l = (a - c)>>>0; + h = (b - d)>>>0; + if ((l>>>0) > (a>>>0)) { // iff we overflowed + h = (h-1)>>>0; + } + {{{ makeStructuralReturn(['l|0', 'h'], true) }}}; + }, + bitshift64Shl__asm: true, bitshift64Shl__sig: 'iiii', bitshift64Shl: function(low, high, bits) { diff --git a/src/long.js b/src/long.js index 6d0e873d..42c86c23 100644 --- a/src/long.js +++ b/src/long.js @@ -1530,20 +1530,6 @@ var i64Math = (function() { // Emscripten wrapper // Emscripten wrapper var Wrapper = { - subtract: function(xl, xh, yl, yh) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.subtract(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - }, - multiply: function(xl, xh, yl, yh) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.multiply(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - }, abs: function(l, h) { var x = new goog.math.Long(l, h); var ret; @@ -1576,48 +1562,6 @@ var i64Math = (function() { // Emscripten wrapper c.addTo(b, d); return d; }, - divide: function(xl, xh, yl, yh, unsigned) { - Wrapper.ensureTemps(); - if (!unsigned) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.div(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - } else { - // slow precise bignum division - var x = Wrapper.lh2bignum(xl >>> 0, xh >>> 0); - var y = Wrapper.lh2bignum(yl >>> 0, yh >>> 0); - var z = new BigInteger(); - x.divRemTo(y, z, null); - var l = new BigInteger(); - var h = new BigInteger(); - z.divRemTo(Wrapper.two32, h, l); - HEAP32[tempDoublePtr>>2] = parseInt(l.toString()) | 0; - HEAP32[tempDoublePtr+4>>2] = parseInt(h.toString()) | 0; - } - }, - modulo: function(xl, xh, yl, yh, unsigned) { - Wrapper.ensureTemps(); - if (!unsigned) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.modulo(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - } else { - // slow precise bignum division - var x = Wrapper.lh2bignum(xl >>> 0, xh >>> 0); - var y = Wrapper.lh2bignum(yl >>> 0, yh >>> 0); - var z = new BigInteger(); - x.divRemTo(y, null, z); - var l = new BigInteger(); - var h = new BigInteger(); - z.divRemTo(Wrapper.two32, h, l); - HEAP32[tempDoublePtr>>2] = parseInt(l.toString()) | 0; - HEAP32[tempDoublePtr+4>>2] = parseInt(h.toString()) | 0; - } - }, stringify: function(l, h, unsigned) { var ret = new goog.math.Long(l, h).toString(); if (unsigned && ret[0] == '-') { diff --git a/src/modules.js b/src/modules.js index f2994ada..5b5f7947 100644 --- a/src/modules.js +++ b/src/modules.js @@ -230,7 +230,7 @@ var Types = { var Functions = { // All functions that will be implemented in this file. Maps id to signature implementedFunctions: {}, - libraryFunctions: {}, // functions added from the library + libraryFunctions: {}, // functions added from the library. value 2 means asmLibraryFunction unimplementedFunctions: {}, // library etc. functions that we need to index, maps id to signature indexedFunctions: {}, diff --git a/src/parseTools.js b/src/parseTools.js index 7dafbebe..2eb456f1 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1756,7 +1756,7 @@ function makeStructuralReturn(values, inAsm) { return 'return ' + asmCoercion(values.slice(1).map(function(value) { i++; return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm.setTempRet' + i + '(' + value + ')') - : 'tempRet' + (i++) + ' = ' + value; + : 'tempRet' + i + ' = ' + value; }).concat([values[0]]).join(','), 'i32'); } else { var i = 0; @@ -1998,9 +1998,12 @@ function processMathop(item) { return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') + (lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); } - function i64PreciseLib(type) { + function preciseCall(name) { Types.preciseI64MathUsed = true; - return finish(['_i64' + type[0].toUpperCase() + type.substr(1) + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + return finish([name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + } + function i64PreciseLib(type) { + return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1)); } switch (op) { // basic integer ops @@ -2062,7 +2065,7 @@ function processMathop(item) { } case 'sub': { if (PRECISE_I64_MATH) { - return i64PreciseOp('subtract'); + return i64PreciseLib('subtract'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1]), true)); @@ -2070,7 +2073,7 @@ function processMathop(item) { } case 'sdiv': case 'udiv': { if (PRECISE_I64_MATH) { - return i64PreciseOp('divide', op[0] === 'u'); + return preciseCall(op[0] === 'u' ? '___udivdi3' : '___divdi3'); } else { warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's'), true)); @@ -2078,7 +2081,7 @@ function processMathop(item) { } case 'mul': { if (PRECISE_I64_MATH) { - return i64PreciseOp('multiply'); + return preciseCall('___muldi3'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u'), true)); @@ -2086,7 +2089,7 @@ function processMathop(item) { } case 'urem': case 'srem': { if (PRECISE_I64_MATH) { - return i64PreciseOp('modulo', op[0] === 'u'); + return preciseCall(op[0] === 'u' ? '___uremdi3' : '___remdi3'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u'), true)); diff --git a/system/lib/compiler-rt/LICENSE.TXT b/system/lib/compiler-rt/LICENSE.TXT new file mode 100644 index 00000000..6aab1f69 --- /dev/null +++ b/system/lib/compiler-rt/LICENSE.TXT @@ -0,0 +1,97 @@ +============================================================================== +compiler_rt License +============================================================================== + +The compiler_rt library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +mach_override lib/interception/mach_override diff --git a/system/lib/compiler-rt/divdi3.c b/system/lib/compiler-rt/divdi3.c new file mode 100644 index 00000000..09f4a04e --- /dev/null +++ b/system/lib/compiler-rt/divdi3.c @@ -0,0 +1,47 @@ +/* ===-- divdi3.c - Implement __divdi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI di_int +__divdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /*sign of quotient */ + return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} + +/* XXX EMSCRIPTEN */ + +COMPILER_RT_ABI di_int +__remdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + du_int rem; + __udivmoddi4(a, b, &rem); + return (rem ^ s_a) - s_a; /* negate if s_a == -1 */ +} + diff --git a/system/lib/compiler-rt/int_endianness.h b/system/lib/compiler-rt/int_endianness.h new file mode 100644 index 00000000..17905355 --- /dev/null +++ b/system/lib/compiler-rt/int_endianness.h @@ -0,0 +1,116 @@ +/* ===-- int_endianness.h - configuration header for compiler-rt ------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_ENDIANNESS_H +#define INT_ENDIANNESS_H + +#if defined(__SVR4) && defined(__sun) +#include <sys/byteorder.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* Solaris and AuroraUX. */ + +/* .. */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix) +#include <sys/endian.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* *BSD */ + +#if defined(__OpenBSD__) || defined(__Bitrig__) +#include <machine/endian.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* OpenBSD and Bitrig. */ + +/* .. */ + +/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */ +#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ ) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#endif +#endif /* __BIG_ENDIAN__ */ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif +#endif /* __LITTLE_ENDIAN__ */ + +#endif /* Mac OSX */ + +/* .. */ + +#if defined(__linux__) +#include <endian.h> + +#if __BYTE_ORDER == __BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* __BYTE_ORDER */ + +#endif /* GNU/Linux */ + +#if defined(_WIN32) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* Windows */ + +#if defined(EMSCRIPTEN) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* emscripten */ + +/* . */ + +#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) +#error Unable to determine endian +#endif /* Check we found an endianness correctly. */ + +#endif /* INT_ENDIANNESS_H */ diff --git a/system/lib/compiler-rt/int_lib.h b/system/lib/compiler-rt/int_lib.h new file mode 100644 index 00000000..a87426c5 --- /dev/null +++ b/system/lib/compiler-rt/int_lib.h @@ -0,0 +1,46 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_LIB_H +#define INT_LIB_H + +/* Assumption: Signed integral is 2's complement. */ +/* Assumption: Right shift of signed negative is arithmetic shift. */ +/* Assumption: Endianness is little or big (not mixed). */ + +/* ABI macro definitions */ + +#if __ARM_EABI__ +# define ARM_EABI_FNALIAS(aeabi_name, name) \ + void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); +# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +#else +# define ARM_EABI_FNALIAS(aeabi_name, name) +# define COMPILER_RT_ABI +#endif + +/* Include the standard compiler builtin headers we use functionality from. */ +#include <limits.h> +#include <stdint.h> +#include <stdbool.h> +#include <float.h> + +/* Include the commonly used internal type definitions. */ +#include "int_types.h" + +/* Include internal utility function declarations. */ +#include "int_util.h" + +#endif /* INT_LIB_H */ diff --git a/system/lib/compiler-rt/int_math.h b/system/lib/compiler-rt/int_math.h new file mode 100644 index 00000000..d6b4bdae --- /dev/null +++ b/system/lib/compiler-rt/int_math.h @@ -0,0 +1,67 @@ +/* ===-- int_math.h - internal math inlines ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines substitutes for the libm functions used in some of the + * compiler-rt implementations, defined in such a way that there is not a direct + * dependency on libm or math.h. Instead, we use the compiler builtin versions + * where available. This reduces our dependencies on the system SDK by foisting + * the responsibility onto the compiler. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_MATH_H +#define INT_MATH_H + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#define CRT_INFINITY __builtin_huge_valf() + +#define crt_isinf(x) __builtin_isinf((x)) +#define crt_isnan(x) __builtin_isnan((x)) + +/* Define crt_isfinite in terms of the builtin if available, otherwise provide + * an alternate version in terms of our other functions. This supports some + * versions of GCC which didn't have __builtin_isfinite. + */ +#if __has_builtin(__builtin_isfinite) +# define crt_isfinite(x) __builtin_isfinite((x)) +#else +# define crt_isfinite(x) \ + __extension__(({ \ + __typeof((x)) x_ = (x); \ + !crt_isinf(x_) && !crt_isnan(x_); \ + })) +#endif + +#define crt_copysign(x, y) __builtin_copysign((x), (y)) +#define crt_copysignf(x, y) __builtin_copysignf((x), (y)) +#define crt_copysignl(x, y) __builtin_copysignl((x), (y)) + +#define crt_fabs(x) __builtin_fabs((x)) +#define crt_fabsf(x) __builtin_fabsf((x)) +#define crt_fabsl(x) __builtin_fabsl((x)) + +#define crt_fmax(x, y) __builtin_fmax((x), (y)) +#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y)) +#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y)) + +#define crt_logb(x) __builtin_logb((x)) +#define crt_logbf(x) __builtin_logbf((x)) +#define crt_logbl(x) __builtin_logbl((x)) + +#define crt_scalbn(x, y) __builtin_scalbn((x), (y)) +#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y)) +#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y)) + +#endif /* INT_MATH_H */ diff --git a/system/lib/compiler-rt/int_types.h b/system/lib/compiler-rt/int_types.h new file mode 100644 index 00000000..fcce390f --- /dev/null +++ b/system/lib/compiler-rt/int_types.h @@ -0,0 +1,140 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines various standard types, most importantly a number of unions + * used to access parts of larger types. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_TYPES_H +#define INT_TYPES_H + +#include "int_endianness.h" + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +typedef union +{ + di_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + si_int high; +#else + si_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} dwords; + +typedef union +{ + du_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + su_int high; +#else + su_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} udwords; + +#if __x86_64 + +typedef int ti_int __attribute__ ((mode (TI))); +typedef unsigned tu_int __attribute__ ((mode (TI))); + +typedef union +{ + ti_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + di_int high; +#else + di_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} twords; + +typedef union +{ + tu_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + du_int high; +#else + du_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} utwords; + +static inline ti_int make_ti(di_int h, di_int l) { + twords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +static inline tu_int make_tu(du_int h, du_int l) { + utwords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +#endif /* __x86_64 */ + +typedef union +{ + su_int u; + float f; +} float_bits; + +typedef union +{ + udwords u; + double f; +} double_bits; + +typedef struct +{ +#if _YUGA_LITTLE_ENDIAN + udwords low; + udwords high; +#else + udwords high; + udwords low; +#endif /* _YUGA_LITTLE_ENDIAN */ +} uqwords; + +typedef union +{ + uqwords u; + long double f; +} long_double_bits; + +#endif /* INT_TYPES_H */ + diff --git a/system/lib/compiler-rt/int_util.h b/system/lib/compiler-rt/int_util.h new file mode 100644 index 00000000..1348b85e --- /dev/null +++ b/system/lib/compiler-rt/int_util.h @@ -0,0 +1,29 @@ +/* ===-- int_util.h - internal utility functions ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines non-inline utilities which are available for use in the + * library. The function definitions themselves are all contained in int_util.c + * which will always be compiled into any compiler-rt library. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_UTIL_H +#define INT_UTIL_H + +/** \brief Trigger a program abort (or panic for kernel code). */ +#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \ + __FUNCTION__) + +void compilerrt_abort_impl(const char *file, int line, + const char *function) __attribute__((noreturn)); + +#endif /* INT_UTIL_H */ diff --git a/system/lib/compiler-rt/muldi3.c b/system/lib/compiler-rt/muldi3.c new file mode 100644 index 00000000..2dae44c1 --- /dev/null +++ b/system/lib/compiler-rt/muldi3.c @@ -0,0 +1,56 @@ +/* ===-- muldi3.c - Implement __muldi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +static +di_int +__muldsi3(su_int a, su_int b) +{ + dwords r; + const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2; + const su_int lower_mask = (su_int)~0 >> bits_in_word_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + su_int t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (a >> bits_in_word_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high = t >> bits_in_word_2; + t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (b >> bits_in_word_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high += t >> bits_in_word_2; + r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2); + return r.all; +} + +/* Returns: a * b */ + +ARM_EABI_FNALIAS(lmul, muldi3) + +COMPILER_RT_ABI di_int +__muldi3(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + dwords r; + r.all = __muldsi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt new file mode 100644 index 00000000..d10f53e4 --- /dev/null +++ b/system/lib/compiler-rt/readme.txt @@ -0,0 +1,20 @@ +These files are from compiler-rt, + +Last Changed Rev: 179380 +Last Changed Date: 2013-04-12 07:57:03 -0700 (Fri, 12 Apr 2013) + +=========================================================================== + +Changes: + + * add emscripten endianness to int_endianness.h + * add rem functions + +=========================================================================== + +Compile with something like + +./emcc system/lib/compiler-rt/*.c -Isystem/lib/compiler-rt/ -o rt.bc +./emcc -O2 -s ASM_JS=1 -g rt.bc -s LINKABLE=1 +manually replace Math_imul with Math.imul + diff --git a/system/lib/compiler-rt/udivdi3.c b/system/lib/compiler-rt/udivdi3.c new file mode 100644 index 00000000..3d55785c --- /dev/null +++ b/system/lib/compiler-rt/udivdi3.c @@ -0,0 +1,36 @@ +/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI du_int +__udivdi3(du_int a, du_int b) +{ + return __udivmoddi4(a, b, 0); +} + +/* XXX EMSCRIPTEN */ + +COMPILER_RT_ABI du_int +__uremdi3(du_int a, du_int b) +{ + du_int rem; + __udivmoddi4(a, b, &rem); + return rem; +} + diff --git a/system/lib/compiler-rt/udivmoddi4.c b/system/lib/compiler-rt/udivmoddi4.c new file mode 100644 index 00000000..57282d5b --- /dev/null +++ b/system/lib/compiler-rt/udivmoddi4.c @@ -0,0 +1,251 @@ +/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmoddi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +COMPILER_RT_ABI du_int +__udivmoddi4(du_int a, du_int b, du_int* rem) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 2 or sr large */ + if (sr > n_uword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits - 1 */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + *0 K + */ + sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + /* 2 <= sr <= n_udword_bits - 1 + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_uword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_uword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 + * { + * q.s.low = n.s.low << (n_udword_bits - sr); + * q.s.high = (n.s.high << (n_udword_bits - sr)) | + * (n.s.low >> (sr - n_uword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_uword_bits); + * } + */ + q.s.low = (n.s.low << (n_udword_bits - sr)) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)); + q.s.high = ((n.s.low << ( n_uword_bits - sr)) & + ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits))) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_uword_bits)) & + ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_uword_bits - sr)) | + (n.s.low >> sr)) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 1 or sr large */ + if (sr > n_uword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_uword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = (n.s.high << (n_uword_bits - sr)) | + ((n.s.low >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_udword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} diff --git a/tests/cases/call_i64_noret.ll b/tests/cases/call_i64_noret.ll new file mode 100644 index 00000000..a8a30fc0 --- /dev/null +++ b/tests/cases/call_i64_noret.ll @@ -0,0 +1,17 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*] + +; [#uses=0] +define i32 @main() { +entry: + %retval = alloca i32, align 4 ; [#uses=1 type=i32*] + store i32 0, i32* %retval + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0), i64 0) ; [#uses=0 type=i32] + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) diff --git a/tests/cases/uadd_overflow_64_ta2.ll b/tests/cases/uadd_overflow_64_ta2.ll new file mode 100644 index 00000000..a4f3e40b --- /dev/null +++ b/tests/cases/uadd_overflow_64_ta2.ll @@ -0,0 +1,30 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@.str2 = private constant [11 x i8] c"*%llx,%d*\0A\00", align 1 ; [#uses=1] + +; [#uses=0] +define i32 @main() { +entry: + %uadd1 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 18446744073709551606, i64 9999) + %a0 = extractvalue { i64, i1 } %uadd1, 0 + %a1 = extractvalue { i64, i1 } %uadd1, 1 + %a2 = zext i1 %a1 to i32 + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str2, i32 0, i32 0), i64 %a0, i32 %a2) ; [#uses=0] + + %uadd2 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 18446744073709, i64 9999) + %b0 = extractvalue { i64, i1 } %uadd2, 0 + %b1 = extractvalue { i64, i1 } %uadd2, 1 + %b2 = zext i1 %b1 to i32 + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str2, i32 0, i32 0), i64 %b0, i32 %b2) ; [#uses=0] + + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) + +declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) nounwind readnone +declare { i64, i1 } @llvm.uadd.with.overflow.i64(i64, i64) nounwind readnone + diff --git a/tests/cases/uadd_overflow_64_ta2.txt b/tests/cases/uadd_overflow_64_ta2.txt new file mode 100644 index 00000000..f5711309 --- /dev/null +++ b/tests/cases/uadd_overflow_64_ta2.txt @@ -0,0 +1,2 @@ +*2705,1* +*10c6f7a0dcfc,0* diff --git a/tests/cases/uadd_overflow_ta2.ll b/tests/cases/uadd_overflow_ta2.ll index 81a76bcd..feac60e3 100644 --- a/tests/cases/uadd_overflow_ta2.ll +++ b/tests/cases/uadd_overflow_ta2.ll @@ -33,6 +33,12 @@ entry: %64ba2 = zext i1 %64ba1 to i32 call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str2, i32 0, i32 0), i32 %64ba0, i32 %64ba2) ; [#uses=0] + %zbuadd1 = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 10, 0 ; undef and explicit + %zba0 = extractvalue { i32, i1 } %zbuadd1, 0 + %zba1 = extractvalue { i32, i1 } %zbuadd1, 1 + %zba2 = zext i1 %ba1 to i32 + call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str2, i32 0, i32 0), i32 %zba0, i32 %zba2) ; [#uses=0] + ret i32 1 } diff --git a/tests/cases/uadd_overflow_ta2.txt b/tests/cases/uadd_overflow_ta2.txt index bcd04599..81513080 100644 --- a/tests/cases/uadd_overflow_ta2.txt +++ b/tests/cases/uadd_overflow_ta2.txt @@ -1,3 +1,4 @@ *3319578,1* *5177,0* *9875,1* +*10,0* diff --git a/tests/runner.py b/tests/runner.py index fa984f05..db5ba108 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -266,11 +266,11 @@ process(sys.argv[1]) if output_processor is not None: output_processor(open(filename + '.o.js').read()) - if self.emcc_args is not None: + if self.emcc_args is not None and 'ASM_JS=1' in self.emcc_args: if '--memory-init-file' in self.emcc_args: memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1]) else: - memory_init_file = 1 + memory_init_file = 0 if memory_init_file: assert '/* memory initializer */' not in open(filename + '.o.js').read() else: @@ -735,7 +735,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows uint64_t a = 5; double b = 6.8; uint64_t c = a * b; - printf("*prod:%llu*\n*%d,%d,%d*\n", c, (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations + if (truthy()) printf("*%d,%d,%d*\n", (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations + printf("*prod:%llu*\n", c); } // Basic (rounded, for now) math. Just check compilation. @@ -745,6 +746,14 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows b++; if (truthy()) b--; // confuse optimizer printf("*%Ld,%Ld,%Ld,%Ld*\n", (a+b)/5000, (a-b)/5000, (a*3)/5000, (a/5)/5000); + a -= 17; if (truthy()) a += 5; // confuse optimizer + b -= 17; if (truthy()) b += 121; // confuse optimizer + printf("*%Lx,%Lx,%Lx,%Lx*\n", b - a, b - a/2, b/2 - a, b - 20); + + if (truthy()) a += 5/b; // confuse optimizer + if (truthy()) b += 121*(3+a/b); // confuse optimizer + printf("*%Lx,%Lx,%Lx,%Lx*\n", a - b, a - b/2, a/2 - b, a - 20); + return 0; } ''' @@ -764,7 +773,10 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows '*-1,34359738367,4294967295,1073741823*\n' + '*-1,-1,-1,-1*\n' + '*-1,34359738367,4294967295,1073741823*\n' + - '*prod:34*') + '*prod:34*\n' + + '*524718382041609,49025451137,787151111239120,52476740749274*\n' + + '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' + + '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n') src = r''' #include <stdio.h> @@ -2486,7 +2498,6 @@ Exception execution path of first function! 1 ''') def test_exceptions(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly') @@ -2576,7 +2587,6 @@ Exception execution path of first function! 1 self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...') def test_white_list_exception(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') Settings.DISABLE_EXCEPTION_CATCHING = 2 Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"] Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified @@ -2608,9 +2618,7 @@ Exception execution path of first function! 1 Settings.DISABLE_EXCEPTION_CATCHING = 0 Settings.EXCEPTION_CATCHING_WHITELIST = [] - def test_uncaught_exception(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc') Settings.DISABLE_EXCEPTION_CATCHING = 0 @@ -2650,7 +2658,6 @@ Exception execution path of first function! 1 self.do_run(src, 'success') def test_typed_exceptions(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') Settings.DISABLE_EXCEPTION_CATCHING = 0 Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access. src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read() @@ -2658,7 +2665,6 @@ Exception execution path of first function! 1 self.do_run(src, expected) def test_multiexception(self): - if Settings.ASM_JS: return self.skip('no exceptions support in asm') Settings.DISABLE_EXCEPTION_CATCHING = 0 src = r''' #include <stdio.h> @@ -8079,11 +8085,11 @@ def process(filename): shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js')) pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1] - open('pgo_data', 'w').write(pgo_output) + open('pgo_data.rsp', 'w').write(pgo_output) # with response file - self.emcc_args += ['@pgo_data'] + self.emcc_args += ['@pgo_data.rsp'] self.do_run(src, output) self.emcc_args.pop() shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed.js')) @@ -8996,7 +9002,7 @@ TT = %s # asm.js exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') - exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "0"])') + exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ @@ -10979,12 +10985,13 @@ elif 'browser' in str(sys.argv): self.run_browser('page.html', '', '/report_result?1') def test_sdl_image(self): - # load an image file, get pixel data. Also O2 coverage for --preload-file + # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpg')) open(os.path.join(self.get_dir(), 'sdl_image.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-O2', '--preload-file', 'screenshot.jpg', '-o', 'page.html']).communicate() - self.run_browser('page.html', '', '/report_result?600') + for mem in [0, 1]: + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-O2', '--preload-file', 'screenshot.jpg', '-o', 'page.html', '--memory-init-file', str(mem)]).communicate() + self.run_browser('page.html', '', '/report_result?600') def test_sdl_image_jpeg(self): shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpeg')) @@ -12090,7 +12097,7 @@ elif 'benchmark' in str(sys.argv): try_delete(final_filename) output = Popen([PYTHON, EMCC, filename, #'-O3', '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',# '-s', 'EXPLICIT_ZEXT=1', - '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', '--llvm-lto', '1', + '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', '--llvm-lto', '1', '--memory-init-file', '0', '-s', 'TOTAL_MEMORY=128*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024', '-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] diff --git a/tests/unistd/misc.out b/tests/unistd/misc.out index 810da215..a872a258 100644 --- a/tests/unistd/misc.out +++ b/tests/unistd/misc.out @@ -29,7 +29,7 @@ alarm: 0, errno: 0 ualarm: 0, errno: 0 fork: -1, errno: 11 vfork: -1, errno: 11 -crypt: 0, errno: 38 +crypt: (null), errno: 38 encrypt, errno: 38 getgid: 0, errno: 0 getegid: 0, errno: 0 diff --git a/tools/file_packager.py b/tools/file_packager.py index 73ff4919..e434e813 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] [--pre-run] [--crunch[=X]] + file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] --pre-run Will generate wrapper code that does preloading in Module.preRun. This is necessary if you add this code before the main file has been loading, which includes necessary components like addRunDependency. @@ -24,6 +24,10 @@ Usage: DDS files will not be crunched if the .crn is more recent than the .dds. This prevents a lot of unneeded computation. + --js-output=FILE Writes output in FILE, if not specified, standard output is used. + + --no-force Don't create output if no valid input file is specified. + Notes: * The file packager generates unix-style file paths. So if you are on windows and a file is accessed at @@ -39,6 +43,11 @@ import shared from shared import Compression, execute, suffix, unsuffixed from subprocess import Popen, PIPE, STDOUT +if len(sys.argv) == 1: + print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] +See the source for more details.''' + sys.exit(0) + data_target = sys.argv[1] IMAGE_SUFFIXES = ('.jpg', '.png', '.bmp') @@ -59,6 +68,8 @@ in_compress = 0 pre_run = False crunch = 0 plugins = [] +jsoutput = None +force = True for arg in sys.argv[1:]: if arg == '--preload': @@ -80,6 +91,10 @@ for arg in sys.argv[1:]: in_preload = False in_embed = False in_compress = 0 + elif arg == '--no-force': + force = False + elif arg.startswith('--js-output'): + jsoutput = arg.split('=')[1] if '=' in arg else None elif arg.startswith('--crunch'): from shared import CRUNCH crunch = arg.split('=')[1] if '=' in arg else '128' @@ -93,9 +108,15 @@ for arg in sys.argv[1:]: in_embed = False in_compress = 0 elif in_preload: - data_files.append({ 'name': arg, 'mode': 'preload' }) + if os.path.isfile(arg) or os.path.isdir(arg): + data_files.append({ 'name': arg, 'mode': 'preload' }) + else: + print >> sys.stderr, 'Warning: ' + arg + ' does not exist, ignoring.' elif in_embed: - data_files.append({ 'name': arg, 'mode': 'embed' }) + if os.path.isfile(arg) or os.path.isdir(arg): + data_files.append({ 'name': arg, 'mode': 'embed' }) + else: + print >> sys.stderr, 'Warning:' + arg + ' does not exist, ignoring.' elif in_compress: if in_compress == 1: Compression.encoder = arg @@ -107,7 +128,10 @@ for arg in sys.argv[1:]: Compression.js_name = arg in_compress = 0 -print ''' +if (not force) and len(data_files) == 0: + has_preloaded = False + +ret = ''' (function() { ''' @@ -152,7 +176,7 @@ for file_ in data_files: # Crunch files if crunch: shutil.copyfile(shared.path_from_root('tools', 'crunch-worker.js'), 'crunch-worker.js') - print ''' + ret += ''' var decrunchWorker = new Worker('crunch-worker.js'); var decrunchCallbacks = []; decrunchWorker.onmessage = function(msg) { @@ -386,26 +410,30 @@ if has_preloaded: ''' % (data_target, os.path.basename(Compression.compressed_name(data_target) if Compression.on else data_target), use_data, data_target) # use basename because from the browser's point of view, we need to find the datafile in the same dir as the html file if pre_run: - print ''' + ret += ''' if (typeof Module == 'undefined') Module = {}; if (!Module['preRun']) Module['preRun'] = []; Module["preRun"].push(function() { ''' - -print code +ret += code if pre_run: - print ' });\n' + ret += ' });\n' if crunch: - print ''' + ret += ''' if (!Module['postRun']) Module['postRun'] = []; Module["postRun"].push(function() { decrunchWorker.terminate(); }); ''' -print ''' +ret += ''' })(); ''' - +if force or len(data_files) > 0: + if jsoutput == None: + print ret + else: + f = open(jsoutput, 'w') + f.write(ret) diff --git a/tools/response_file.py b/tools/response_file.py new file mode 100644 index 00000000..312cda73 --- /dev/null +++ b/tools/response_file.py @@ -0,0 +1,28 @@ +import tempfile, os, sys, shlex + +# Routes the given cmdline param list in args into a new response file and returns the filename to it. +# The returned filename has a suffix '.rsp'. +def create_response_file(args, directory): + (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True) + response_fd = os.fdopen(response_fd, "w") + #print >> sys.stderr, "Creating response file '%s'" % response_filename + args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) + response_fd.write(' '.join(args)) + response_fd.close() + return response_filename + +# Reads a response file, and returns the list of cmdline params found in the file. +# The parameter response_filename may start with '@'. +def read_response_file(response_filename): + if response_filename.startswith('@'): + response_filename = response_filename[1:] + + #print >> sys.stderr, "Using response file '%s'" % response_filename + if not os.path.exists(response_filename): + raise Exception("Response file '%s' not found!" % response_filename) + + response_fd = open(response_filename, 'r') + args = response_fd.read() + response_fd.close() + args = shlex.split(args) + return args diff --git a/tools/shared.py b/tools/shared.py index 72f4868e..d5a37c03 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2,6 +2,7 @@ import shutil, time, os, sys, json, tempfile, copy, shlex, atexit, subprocess, h from subprocess import Popen, PIPE, STDOUT from tempfile import mkstemp import jsrun, cache, tempfiles +from response_file import create_response_file def listify(x): if type(x) is not list: return [x] @@ -34,9 +35,15 @@ class WindowsPopen: self.stdout_ = PIPE if self.stderr_ == None: self.stderr_ = PIPE - - # Call the process with fixed streams. + + # emscripten.py supports reading args from a response file instead of cmdline. + # Use .rsp to avoid cmdline length limitations on Windows. + if len(args) >= 2 and args[1].endswith("emscripten.py"): + self.response_filename = create_response_file(args[2:], TEMP_DIR) + args = args[0:2] + ['@' + self.response_filename] + try: + # Call the process with fixed streams. self.process = subprocess.Popen(args, bufsize, executable, self.stdin_, self.stdout_, self.stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags) except Exception, e: print >> sys.stderr, '\nsubprocess.Popen(args=%s) failed! Exception %s\n' % (' '.join(args), str(e)) @@ -67,6 +74,13 @@ class WindowsPopen: def kill(self): return self.process.kill() + + def __del__(self): + try: + # Clean up the temporary response file that was used to spawn this process, so that we don't leave temp files around. + tempfiles.try_delete(self.response_filename) + except: + pass # Mute all exceptions in dtor, particularly if we didn't use a response file, self.response_filename doesn't exist. # Install our replacement Popen handler if we are running on Windows to avoid python spawn process function. if os.name == 'nt': |