diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-01-15 13:10:55 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-01-15 13:10:55 -0800 |
commit | c05d19aef2eaeef7743c7ba574e71de786519d1b (patch) | |
tree | 4d1b493bb716c09df0db4b539ca17a9e8619f69b | |
parent | c47f7eba9be951c8e308e66c2541091c6b057af8 (diff) | |
parent | a21017cfe7ca199a6a51511ee65aea63f011446b (diff) |
Merge branch 'incoming'
-rwxr-xr-x | emcc | 27 | ||||
-rwxr-xr-x | emscripten.py | 20 | ||||
-rw-r--r-- | src/analyzer.js | 13 | ||||
-rw-r--r-- | src/intertyper.js | 2 | ||||
-rw-r--r-- | src/jsifier.js | 55 | ||||
-rw-r--r-- | src/library.js | 15 | ||||
-rw-r--r-- | src/library_browser.js | 4 | ||||
-rw-r--r-- | src/modules.js | 1 | ||||
-rw-r--r-- | src/parseTools.js | 120 | ||||
-rw-r--r-- | src/runtime.js | 21 | ||||
-rw-r--r-- | tests/bigswitch.cpp | 7938 | ||||
-rwxr-xr-x | tests/runner.py | 26 | ||||
-rw-r--r-- | tools/js-optimizer.js | 48 |
13 files changed, 8160 insertions, 130 deletions
@@ -1200,15 +1200,20 @@ try: js_optimizer_queue = [] def flush_js_optimizer_queue(): global final, js_optimizer_queue - if len(js_optimizer_queue) > 0: + if len(js_optimizer_queue) > 0 and not(len(js_optimizer_queue) == 1 and js_optimizer_queue[0] == 'last'): if DEBUG < 2: + if shared.Settings.ASM_JS: + js_optimizer_queue = ['asm'] + js_optimizer_queue if DEBUG: print >> sys.stderr, 'emcc: applying js optimization passes:', js_optimizer_queue final = shared.Building.js_optimizer(final, js_optimizer_queue, jcache) if DEBUG: save_intermediate('js_opts') else: for name in js_optimizer_queue: - print >> sys.stderr, 'emcc: applying js optimization pass:', name - final = shared.Building.js_optimizer(final, [name], jcache) + passes = [name] + if shared.Settings.ASM_JS: + passes = ['asm'] + passes + print >> sys.stderr, 'emcc: applying js optimization pass:', passes + final = shared.Building.js_optimizer(final, passes, jcache) save_intermediate(name) js_optimizer_queue = [] @@ -1221,20 +1226,12 @@ try: if DEBUG: save_intermediate('pretty') def get_eliminate(): - if shared.Settings.ASM_JS: - return 'eliminateAsm' - elif shared.Settings.ALLOW_MEMORY_GROWTH: + if shared.Settings.ALLOW_MEMORY_GROWTH: return 'eliminateMemSafe' else: return 'eliminate' - def get_simplify_pre(): - if shared.Settings.ASM_JS: - return 'simplifyExpressionsPreAsm' - else: - return 'simplifyExpressionsPre' - - js_optimizer_queue += [get_eliminate(), get_simplify_pre()] + js_optimizer_queue += [get_eliminate(), 'simplifyExpressionsPre'] if shared.Settings.RELOOP: js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches @@ -1246,7 +1243,7 @@ try: final = shared.Building.closure_compiler(final) if DEBUG: save_intermediate('closure') elif shared.Settings.ASM_JS and shared.Settings.RELOOP: - js_optimizer_queue += ['registerizeAsm'] # we can't use closure in asm, but this does much of the same + js_optimizer_queue += ['registerize'] # we can't use closure in asm, but this does much of the same if opt_level >= 1: if DEBUG: print >> sys.stderr, 'emcc: running post-closure post-opts' @@ -1255,6 +1252,8 @@ try: if minify_whitespace: js_optimizer_queue += ['compress'] + js_optimizer_queue += ['last'] + flush_js_optimizer_queue() # If we were asked to also generate HTML, do that diff --git a/emscripten.py b/emscripten.py index ac13f7a3..2662e40a 100755 --- a/emscripten.py +++ b/emscripten.py @@ -311,8 +311,9 @@ def emscript(infile, settings, outfile, libraries=[]): maths += ['Math.imul'] asm_setup = '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in maths]) fundamentals = ['buffer', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] - basic_funcs = ['abort', 'assert'] + [m.replace('.', '_') for m in maths] + basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in maths] 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 += ''' @@ -353,10 +354,13 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; # 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()] - asm_global_funcs = ''.join([' var ' + g + '=env.' + g + ';\n' for g in basic_funcs + global_funcs]) - asm_global_vars = ''.join([' var ' + g + '=env.' + g + '|0;\n' for g in basic_vars + global_vars]) + def math_fix(g): + return g if not g.startswith('Math_') else g.split('_')[1]; + asm_global_funcs = ''.join([' var ' + g + '=env.' + math_fix(g) + ';\n' for g in basic_funcs + global_funcs]) + asm_global_vars = ''.join([' var ' + g + '=env.' + g + '|0;\n' for g in basic_vars + global_vars]) + \ + ''.join([' var ' + g + '=+env.' + g + ';\n' for g in basic_float_vars]) # sent data - sending = '{ ' + ', '.join([s + ': ' + s for s in fundamentals + basic_funcs + global_funcs + basic_vars + global_vars]) + ' }' + sending = '{ ' + ', '.join([math_fix(s) + ': ' + s for s in fundamentals + basic_funcs + global_funcs + basic_vars + basic_float_vars + global_vars]) + ' }' # received if not simple: receiving = ';\n'.join(['var ' + s + ' = Module["' + s + '"] = asm.' + s for s in exported_implemented_functions + function_tables]) @@ -365,6 +369,12 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; # finalize funcs_js = ''' %s +function asmPrintInt(x) { + Module.print('int ' + x);// + ' ' + new Error().stack); +} +function asmPrintFloat(x) { + Module.print('float ' + x);// + ' ' + new Error().stack); +} var asmPre = (function(env, buffer) { 'use asm'; var HEAP8 = new env.Int8Array(buffer); @@ -378,7 +388,7 @@ var asmPre = (function(env, buffer) { ''' % (asm_setup,) + '\n' + asm_global_vars + ''' var __THREW__ = 0; var undef = 0; - var tempInt = 0, tempValue = 0; + var tempInt = 0, tempBigInt = 0, tempValue = 0; ''' + ''.join([''' var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs + ''' function stackAlloc(size) { diff --git a/src/analyzer.js b/src/analyzer.js index 0ad3e017..229bda9f 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -617,8 +617,8 @@ function analyzer(data, sidePass) { for (var i = 0; i < targetElements.length; i++) { if (i > 0) { switch(value.variant) { - case 'eq': ident += '&&'; break; - case 'ne': ident += '||'; break; + case 'eq': ident += '&'; break; + case 'ne': ident += '|'; break; default: throw 'unhandleable illegal icmp: ' + value.variant; } } @@ -654,9 +654,12 @@ function analyzer(data, sidePass) { // We can't statically legalize this, do the operation at runtime TODO: optimize assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits'); value.intertype = 'value'; - value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + sourceElements[0].ident + ', ' + - sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' + - 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0) + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1) + ';'; + value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + + asmCoercion(sourceElements[0].ident, 'i32') + ',' + + asmCoercion(sourceElements[1].ident, 'i32') + ',' + + Runtime['BITSHIFT64_' + value.op.toUpperCase()] + ',' + + asmCoercion(value.params[1].ident + '$0', 'i32') + ');' + + 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';'; value.assignTo = null; i++; continue; diff --git a/src/intertyper.js b/src/intertyper.js index 5bca9236..00d504f5 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -851,6 +851,8 @@ function intertyper(data, sidePass, baseLineNums) { item.type = item.params[1].ident; item.params[0].type = item.params[1].type; // TODO: also remove 2nd param? + } else if (item.op in LLVM.COMPS) { + item.type = 'i1'; } if (USE_TYPED_ARRAYS == 2) { // Some specific corrections, since 'i64' is special diff --git a/src/jsifier.js b/src/jsifier.js index e41bcf67..5fbea5ba 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -606,10 +606,12 @@ function JSify(data, functionsOnly, givenFunctions) { } for (i = 0; i < chunks.length; i++) { func.JS += ' var ' + chunks[i].map(function(v) { - if (v.type != 'i64') { + if (!isIllegalType(v.type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal return v.ident + ' = ' + asmInitializer(v.type); //, func.variables[v.ident].impl); } else { - return v.ident + '$0 = 0, ' + v.ident + '$1 = 1'; + return range(Math.ceil(getBits(v.type)/32)).map(function(i) { + return v.ident + '$' + i + '= 0'; + }).join(','); } }).join(', ') + ';\n'; } @@ -1060,7 +1062,7 @@ function JSify(data, functionsOnly, givenFunctions) { } }); makeFuncLineActor('switch', function(item) { - // TODO: Find a case where switch is important, and benchmark that. var SWITCH_IN_SWITCH = 1; + var useIfs = RELOOP || item.switchLabels.length < 1024; // with a huge number of cases, if-else which looks nested to js parsers can cause problems var phiSets = calcPhiSets(item); // Consolidate checks that go to the same label. This is important because it makes the relooper simpler and faster. var targetLabels = {}; // for each target label, the list of values going to it @@ -1078,16 +1080,27 @@ function JSify(data, functionsOnly, givenFunctions) { if (RELOOP) { item.groupedLabels = []; } + if (!useIfs) { + ret += 'switch(' + signedIdent + ') {\n'; + } for (var targetLabel in targetLabels) { - if (!first) { + if (!first && useIfs) { ret += 'else '; } else { first = false; } - var value = targetLabels[targetLabel].map(function(value) { - return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type) - }).join(' || '); - ret += 'if (' + value + ') {\n'; + var value; + if (useIfs) { + value = targetLabels[targetLabel].map(function(value) { + return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type) + }).join(' | '); + ret += 'if (' + value + ') {\n'; + } else { + value = targetLabels[targetLabel].map(function(value) { + return 'case ' + makeSignOp(value, item.type, 're') + ':'; + }).join(' '); + ret += value + '{\n'; + } var phiSet = getPhiSetsForLabel(phiSets, targetLabel); ret += ' ' + phiSet + makeBranch(targetLabel, item.currLabelId || null) + '\n'; ret += '}\n'; @@ -1099,10 +1112,18 @@ function JSify(data, functionsOnly, givenFunctions) { }); } } - if (item.switchLabels.length > 0) ret += 'else {\n'; var phiSet = item.defaultLabelJS = getPhiSetsForLabel(phiSets, item.defaultLabel); - ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n'; - if (item.switchLabels.length > 0) ret += '}\n'; + if (useIfs) { + if (item.switchLabels.length > 0) ret += 'else {\n'; + ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n'; + if (item.switchLabels.length > 0) ret += '}\n'; + } else { + ret += 'default: {\n'; + ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n'; + ret += '}\n'; + + ret += '} break; \n'; // finish switch and break, to move control flow properly (breaks from makeBranch just broke out of the switch) + } if (item.value) { ret += ' ' + toNiceIdent(item.value); } @@ -1131,7 +1152,7 @@ function JSify(data, functionsOnly, givenFunctions) { 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*') + ' } ' + - 'throw ' + ptr + ';'; + makeThrow('ptr') + ';'; }); makeFuncLineActor('invoke', function(item) { // Wrapping in a function lets us easily return values if we are @@ -1172,7 +1193,7 @@ function JSify(data, functionsOnly, givenFunctions) { case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type, null, null, null, null, ',') + ',tempValue)'; case 'cmpxchg': { var param3 = finalizeLLVMParameter(item.params[2]); - return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' && (' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ')),tempValue)'; + return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' ? ' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ' : 0),tempValue)'; } default: throw 'unhandled atomic op: ' + item.op; } @@ -1292,8 +1313,12 @@ function JSify(data, functionsOnly, givenFunctions) { }); args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); - if (ASM_JS && shortident in Functions.libraryFunctions) { - args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); + if (ASM_JS) { + if (shortident in Functions.libraryFunctions) { + args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); + } else { + args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); + } } varargs = varargs.map(function(vararg, i) { diff --git a/src/library.js b/src/library.js index be57e445..b70aadbc 100644 --- a/src/library.js +++ b/src/library.js @@ -3905,7 +3905,7 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.ERANGE); // not quite correct } - {{{ makeStructuralReturn([makeGetTempDouble(0), makeGetTempDouble(1)]) }}}; + {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}}; }, #endif strtoll__deps: ['_parseInt64'], @@ -4894,12 +4894,12 @@ LibraryManager.library = { } else { __ZSt18uncaught_exceptionv.uncaught_exception++; } - throw ptr; + {{{ makeThrow('ptr') }}}; }, __cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'], __cxa_rethrow: function() { ___cxa_end_catch.rethrown = true; - throw {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; + {{{ makeThrow(makeGetValue('_llvm_eh_exception.buf', '0', 'void*')) }}}; }, llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);', llvm_eh_exception: function() { @@ -4962,11 +4962,10 @@ LibraryManager.library = { }, _Unwind_Resume_or_Rethrow: function(ptr) { - throw ptr; + {{{ makeThrow('ptr') }}}; }, - _Unwind_RaiseException__deps: ['llvm_eh_exception', '__cxa_find_matching_catch'], _Unwind_RaiseException: function(ptr) { - throw ptr; + {{{ makeThrow('ptr') }}}; }, _Unwind_DeleteException: function(ptr) {}, @@ -5130,14 +5129,14 @@ LibraryManager.library = { llvm_uadd_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }], llvm_uadd_with_overflow_i64: function(xl, xh, yl, yh) { i64Math.add(xl, xh, yl, yh); - {{{ makeStructuralReturn(['HEAP32[tempDoublePtr>>2]', 'HEAP32[tempDoublePtr+4>>2]', '0']) }}}; + {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32'), '0']) }}}; // XXX Need to hack support for second param in long.js }, 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(['HEAP32[tempDoublePtr>>2]', 'HEAP32[tempDoublePtr+4>>2]', '0']) }}}; + {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32'), '0']) }}}; // XXX Need to hack support for second param in long.js }, diff --git a/src/library_browser.js b/src/library_browser.js index fd09f478..13275702 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -691,7 +691,7 @@ mergeInto(LibraryManager.library, { info.worker.postMessage({ 'funcName': funcName, 'callbackId': callbackId, - 'data': data ? {{{ makeHEAPView('U8', 'data', 'data + size') }}} : 0 + 'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705 }); }, @@ -701,7 +701,7 @@ mergeInto(LibraryManager.library, { workerResponded = true; postMessage({ 'callbackId': workerCallbackId, - 'data': data ? {{{ makeHEAPView('U8', 'data', 'data + size') }}} : 0 + 'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705 }); }, diff --git a/src/modules.js b/src/modules.js index b5a30866..2e4b206d 100644 --- a/src/modules.js +++ b/src/modules.js @@ -15,6 +15,7 @@ var LLVM = { SHIFTS: set('ashr', 'lshr', 'shl'), PHI_REACHERS: set('branch', 'switch', 'invoke'), EXTENDS: set('sext', 'zext'), + COMPS: set('icmp', 'fcmp'), INTRINSICS_32: set('_llvm_memcpy_p0i8_p0i8_i64', '_llvm_memmove_p0i8_p0i8_i64', '_llvm_memset_p0i8_i64'), // intrinsics that need args converted to i32 in USE_TYPED_ARRAYS == 2 }; LLVM.GLOBAL_MODIFIERS = set(keys(LLVM.LINKAGES).concat(['constant', 'global', 'hidden'])); diff --git a/src/parseTools.js b/src/parseTools.js index 6cb3e776..3ff5e710 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1014,12 +1014,23 @@ function asmInitializer(type, impl) { } } -function asmCoercion(value, type) { +function asmCoercion(value, type, signedness) { if (!ASM_JS) return value; if (type == 'void') { return value; } else if (type in Runtime.FLOAT_TYPES) { - return '(+(' + value + '))'; + if (isNumber(value)) { + return asmEnsureFloat(value, type); + } else { + if (signedness) { + if (signedness == 'u') { + value = '(' + value + ')>>>0'; + } else { + value = '(' + value + ')|0'; + } + } + return '(+(' + value + '))'; + } } else { return '((' + value + ')|0)'; } @@ -1031,11 +1042,28 @@ function asmMultiplyI32(a, b) { if (USE_MATH_IMUL) { return 'Math.imul(' + a + ',' + b + ')'; } - return '(~~(+' + a + ' * +' + b + '))'; + return '(~~(+((' + a + ')|0) * +((' + b + ')|0)))'; } -function makeGetTempDouble(i) { // TODO: Support other than i32 - return makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32')*i, 'i32'); +function makeGetTempDouble(i, type, forSet) { // get an aliased part of the tempDouble temporary storage + // Cannot use makeGetValue because it uses us + // this is a unique case where we *can* use HEAPF64 + var slab = type == 'double' ? 'HEAPF64' : makeGetSlabs(null, type)[0]; + var ptr = getFastValue('tempDoublePtr', '+', Runtime.getNativeTypeSize(type)*i); + var offset; + if (type == 'double') { + if (ASM_JS) ptr = '(' + ptr + ')&' + memoryMask; + offset = '(' + ptr + ')>>3'; + } else { + offset = getHeapOffset(ptr, type); + } + var ret = slab + '[' + offset + ']'; + if (!forSet) ret = asmCoercion(ret, type); + return ret; +} + +function makeSetTempDouble(i, type, value) { + return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type); } // See makeSetValue @@ -1051,9 +1079,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(HEAP32[tempDoublePtr>>2]=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' + - 'HEAP32[tempDoublePtr+4>>2]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' + - 'HEAPF64[tempDoublePtr>>3])'; + return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + + makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + + makeGetTempDouble(0, 'double') + ')'; } if (USE_TYPED_ARRAYS == 2 && align) { @@ -1076,9 +1104,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } } else { if (type == 'float') { - ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),HEAPF32[tempDoublePtr>>2]'; + ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),' + makeGetTempDouble(0, 'float'); } else { - ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),HEAP64[tempDoublePtr>>3]'; + ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),' + makeGetTempDouble(0, 'double'); } } ret += ')'; @@ -1147,9 +1175,9 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(HEAPF64[tempDoublePtr>>3]=' + value + ',' + - makeSetValue(ptr, pos, 'HEAP32[tempDoublePtr>>2]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + - makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'HEAP32[tempDoublePtr+4>>2]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; + return '(' + makeSetTempDouble(0, 'double', value) + ',' + + makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; } else if (USE_TYPED_ARRAYS == 2 && type == 'i64') { return '(tempI64 = [' + splitI64(value) + '],' + makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + @@ -1173,7 +1201,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, ret += 'tempBigInt=' + value + sep; for (var i = 0; i < bytes; i++) { ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1); - if (i < bytes-1) ret += sep + 'tempBigInt>>=8' + sep; + if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep; } } } else { @@ -1648,6 +1676,10 @@ function makeStructuralAccess(ident, i) { } } +function makeThrow(what) { + return 'throw ' + what + (DISABLE_EXCEPTION_CATCHING ? ' + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 to catch."' : '') + ';'; +} + // From parseLLVMSegment function finalizeLLVMParameter(param, noIndexizeFunctions) { var ret; @@ -1858,8 +1890,8 @@ function processMathop(item) { } function i64PreciseOp(type, lastArg) { Types.preciseI64MathUsed = true; - return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + - (lastArg ? ',' + lastArg : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); + 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')]); } switch (op) { // basic integer ops @@ -1876,8 +1908,8 @@ function processMathop(item) { case 'ashr': case 'lshr': { if (!isNumber(idents[1])) { - return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0),' + - '[' + makeGetTempDouble(0) + ',' + makeGetTempDouble(1) + '])'; + return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],' + Runtime['BITSHIFT64_' + op.toUpperCase()] + ',' + stripCorrections(idents[1]) + '[0]|0),' + + '[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])'; } bits = parseInt(idents[1]); var ander = Math.pow(2, bits)-1; @@ -1917,24 +1949,24 @@ function processMathop(item) { case 'fptoui': case 'fptosi': return finish(splitI64(idents[0])); case 'icmp': { switch (variant) { - case 'uge': return '(' + high1 + '>>>0) >= (' + high2 + '>>>0) && ((' + high1 + '>>>0) > (' + high2 + '>>>0) || ' + - '(' + low1 + '>>>0) >= (' + low2 + '>>>0))'; - case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' + - '(' + low1 + '>>>0) >= (' + low2 + '>>>0))'; - case 'ule': return '(' + high1 + '>>>0) <= (' + high2 + '>>>0) && ((' + high1 + '>>>0) < (' + high2 + '>>>0) || ' + - '(' + low1 + '>>>0) <= (' + low2 + '>>>0))'; - case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' + - '(' + low1 + '>>>0) <= (' + low2 + '>>>0))'; - case 'ugt': return '(' + high1 + '>>>0) > (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' + - '(' + low1 + '>>>0) > (' + low2 + '>>>0))'; - case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' + - '(' + low1 + '>>>0) > (' + low2 + '>>>0))'; - case 'ult': return '(' + high1 + '>>>0) < (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' + - '(' + low1 + '>>>0) < (' + low2 + '>>>0))'; - case 'slt': return '(' + high1 + '|0) < (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' + - '(' + low1 + '>>>0) < (' + low2 + '>>>0))'; - case 'ne': return low1 + ' != ' + low2 + ' || ' + high1 + ' != ' + high2 + ''; - case 'eq': return low1 + ' == ' + low2 + ' && ' + high1 + ' == ' + high2 + ''; + case 'uge': return '((' + high1 + '>>>0) >= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ' + + '(' + low1 + '>>>0) >= (' + low2 + '>>>0)))'; + case 'sge': return '((' + high1 + '|0) >= (' + high2 + '|0)) & ((((' + high1 + '|0) > (' + high2 + '|0)) | ' + + '(' + low1 + '>>>0) >= (' + low2 + '>>>0)))'; + case 'ule': return '((' + high1 + '>>>0) <= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ' + + '(' + low1 + '>>>0) <= (' + low2 + '>>>0)))'; + case 'sle': return '((' + high1 + '|0) <= (' + high2 + '|0)) & ((((' + high1 + '|0) < (' + high2 + '|0)) | ' + + '(' + low1 + '>>>0) <= (' + low2 + '>>>0)))'; + case 'ugt': return '((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' + + '(' + low1 + '>>>0) > (' + low2 + '>>>0))))'; + case 'sgt': return '((' + high1 + '|0) > (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' + + '(' + low1 + '>>>0) > (' + low2 + '>>>0))))'; + case 'ult': return '((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' + + '(' + low1 + '>>>0) < (' + low2 + '>>>0))))'; + case 'slt': return '((' + high1 + '|0) < (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' + + '(' + low1 + '>>>0) < (' + low2 + '>>>0))))'; + case 'ne': return '((' + low1 + '|0) != (' + low2 + '|0)) | ((' + high1 + '|0) != (' + high2 + '|0))'; + case 'eq': return '((' + low1 + '|0) == (' + low2 + '|0)) & ((' + high1 + '|0) == (' + high2 + '|0))'; default: throw 'Unknown icmp variant: ' + variant; } } @@ -1994,15 +2026,15 @@ function processMathop(item) { var outType = item.type; if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) { if (legalizedI64s) { - return '(HEAP32[tempDoublePtr>>2]=' + idents[0] + '$0, HEAP32[tempDoublePtr+4>>2]=' + idents[0] + '$1, HEAPF64[tempDoublePtr>>3])'; + return '(' + makeSetTempDouble(0, 'i32', idents[0] + '$0') + ', ' + makeSetTempDouble(1, 'i32', idents[0] + '$1') + ', ' + makeGetTempDouble(0, 'double') + ')'; } else { - return makeInlineCalculation('HEAP32[tempDoublePtr>>2]=VALUE[0],HEAP32[tempDoublePtr+4>>2]=VALUE[1],HEAPF64[tempDoublePtr>>>3]', idents[0], 'tempI64'); + return makeInlineCalculation(makeSetTempDouble(0, 'i32', 'VALUE[0]') + ',' + makeSetTempDouble(1, 'i32', 'VALUE[1]') + ',' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64'); } } else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) { if (legalizedI64s) { - return 'HEAPF64[tempDoublePtr>>3]=' + idents[0] + '; ' + finish(['HEAP32[tempDoublePtr>>2]','HEAP32[tempDoublePtr+4>>2]']); + return makeSetTempDouble(0, 'double', idents[0]) + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]); } else { - return '(HEAPF64[tempDoublePtr>>3]=' + idents[0] + ',[HEAP32[tempDoublePtr>>2],HEAP32[tempDoublePtr+4>>2]])'; + return '(' + makeSetTempDouble(0, 'double', idents[0]) + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])'; } } else { throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type; @@ -2020,7 +2052,7 @@ function processMathop(item) { case 'mul': { if (bits == 32 && PRECISE_I32_MUL) { Types.preciseI64MathUsed = true; - return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + idents[0] + ',0,' + idents[1] + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')'; + return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + asmCoercion(idents[0], 'i32') + ',0,' + asmCoercion(idents[1], 'i32') + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')'; } else { return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits); } @@ -2070,7 +2102,7 @@ function processMathop(item) { case 'fdiv': return getFastValue(idents[0], '/', idents[1], item.type); case 'fmul': return getFastValue(idents[0], '*', idents[1], item.type); case 'frem': return getFastValue(idents[0], '%', idents[1], item.type); - case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double'); + case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double', op[0]); case 'fptoui': case 'fptosi': return makeRounding(idents[0], bitsLeft, op === 'fptosi', true); // TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking @@ -2141,9 +2173,9 @@ function processMathop(item) { (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) { assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2'); if (inType in Runtime.INT_TYPES) { - return '(HEAP32[tempDoublePtr>>2] = ' + idents[0] + ',HEAPF32[tempDoublePtr>>2])'; + return '(' + makeSetTempDouble(0, 'i32', idents[0]) + ',' + makeGetTempDouble(0, 'float') + ')'; } else { - return '(HEAPF32[tempDoublePtr>>2] = ' + idents[0] + ',HEAP32[tempDoublePtr>>2])'; + return '(' + makeSetTempDouble(0, 'float', idents[0]) + ',' + makeGetTempDouble(0, 'i32') + ')'; } } return idents[0]; diff --git a/src/runtime.js b/src/runtime.js index 9d5e5e1f..d1475bd4 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -123,42 +123,45 @@ var Runtime = { FLOAT_TYPES: set('float', 'double'), // Mirrors processMathop's treatment of constants (which we optimize directly) + BITSHIFT64_SHL: 0, + BITSHIFT64_ASHR: 1, + BITSHIFT64_LSHR: 2, bitshift64: function(low, high, op, bits) { var ret; var ander = Math.pow(2, bits)-1; if (bits < 32) { switch (op) { - case 'shl': + case Runtime.BITSHIFT64_SHL: ret = [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))]; break; - case 'ashr': + case Runtime.BITSHIFT64_ASHR: ret = [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0]; break; - case 'lshr': + case Runtime.BITSHIFT64_LSHR: ret = [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits]; break; } } else if (bits == 32) { switch (op) { - case 'shl': + case Runtime.BITSHIFT64_SHL: ret = [0, low]; break; - case 'ashr': + case Runtime.BITSHIFT64_ASHR: ret = [high, (high|0) < 0 ? ander : 0]; break; - case 'lshr': + case Runtime.BITSHIFT64_LSHR: ret = [high, 0]; break; } } else { // bits > 32 switch (op) { - case 'shl': + case Runtime.BITSHIFT64_SHL: ret = [0, low << (bits - 32)]; break; - case 'ashr': + case Runtime.BITSHIFT64_ASHR: ret = [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0]; break; - case 'lshr': + case Runtime.BITSHIFT64_LSHR: ret = [high >>> (bits - 32) , 0]; break; } diff --git a/tests/bigswitch.cpp b/tests/bigswitch.cpp new file mode 100644 index 00000000..d4b7f459 --- /dev/null +++ b/tests/bigswitch.cpp @@ -0,0 +1,7938 @@ +#include <stdio.h>
+#include <stdlib.h>
+#include <SDL.h>
+#include "SDL/SDL_opengl.h"
+
+const |