aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemscripten.py20
-rw-r--r--src/analyzer.js13
-rw-r--r--src/intertyper.js2
-rw-r--r--src/jsifier.js20
-rw-r--r--src/library.js9
-rw-r--r--src/modules.js1
-rw-r--r--src/parseTools.js94
-rw-r--r--src/runtime.js21
-rwxr-xr-xtests/runner.py13
-rw-r--r--tools/js-optimizer.js14
-rw-r--r--tools/shared.py6
11 files changed, 137 insertions, 76 deletions
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 8146c75c..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, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';';
+ 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 44d9cc53..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';
}
@@ -1091,7 +1093,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (useIfs) {
value = targetLabels[targetLabel].map(function(value) {
return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type)
- }).join(' || ');
+ }).join(' | ');
ret += 'if (' + value + ') {\n';
} else {
value = targetLabels[targetLabel].map(function(value) {
@@ -1150,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
@@ -1191,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;
}
@@ -1311,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 7ae17fb7..b70aadbc 100644
--- a/src/library.js
+++ b/src/library.js
@@ -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) {},
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 32bf70e9..3ff5e710 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -1019,14 +1019,18 @@ function asmCoercion(value, type, signedness) {
if (type == 'void') {
return value;
} else if (type in Runtime.FLOAT_TYPES) {
- if (signedness) {
- if (signedness == 'u') {
- value = '(' + value + ')>>>0';
- } else {
- value = '(' + value + ')|0';
+ if (isNumber(value)) {
+ return asmEnsureFloat(value, type);
+ } else {
+ if (signedness) {
+ if (signedness == 'u') {
+ value = '(' + value + ')>>>0';
+ } else {
+ value = '(' + value + ')|0';
+ }
}
+ return '(+(' + value + '))';
}
- return '(+(' + value + '))';
} else {
return '((' + value + ')|0)';
}
@@ -1041,7 +1045,7 @@ function asmMultiplyI32(a, b) {
return '(~~(+((' + a + ')|0) * +((' + b + ')|0)))';
}
-function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble temporary storage
+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];
@@ -1053,7 +1057,13 @@ function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble t
} else {
offset = getHeapOffset(ptr, type);
}
- return slab + '[' + offset + ']';
+ 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
@@ -1069,8 +1079,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
- return '(' + makeGetTempDouble(0, 'i32') + '=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
- makeGetTempDouble(1, 'i32') + '=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
+ 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') + ')';
}
@@ -1165,7 +1175,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
}
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
- return '(' + makeGetTempDouble(0, 'double') + '=' + value + ',' +
+ 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') {
@@ -1191,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 {
@@ -1666,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;
@@ -1876,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
@@ -1894,7 +1908,7 @@ 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),' +
+ 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]);
@@ -1935,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;
}
}
@@ -2012,15 +2026,15 @@ function processMathop(item) {
var outType = item.type;
if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) {
if (legalizedI64s) {
- return '(' + makeGetTempDouble(0, 'i32') + '=' + idents[0] + '$0, ' + makeGetTempDouble(1, 'i32') + '=' + idents[0] + '$1, ' + makeGetTempDouble(0, 'double') + ')';
+ return '(' + makeSetTempDouble(0, 'i32', idents[0] + '$0') + ', ' + makeSetTempDouble(1, 'i32', idents[0] + '$1') + ', ' + makeGetTempDouble(0, 'double') + ')';
} else {
- return makeInlineCalculation(makeGetTempDouble(0, 'i32') + '=VALUE[0],' + makeGetTempDouble(1, 'i32') + '=VALUE[1],' + makeGetTempDouble(0, 'double'), 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 makeGetTempDouble(0, 'double') + '=' + idents[0] + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]);
+ return makeSetTempDouble(0, 'double', idents[0]) + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]);
} else {
- return '(' + makeGetTempDouble(0, 'double') + '=' + idents[0] + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])';
+ 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;
@@ -2038,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);
}
@@ -2159,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 '(' + makeGetTempDouble(0, 'i32') + '=' + idents[0] + ',' + makeGetTempDouble(0, 'float') + ')';
+ return '(' + makeSetTempDouble(0, 'i32', idents[0]) + ',' + makeGetTempDouble(0, 'float') + ')';
} else {
- return '(' + makeGetTempDouble(0, 'float') + '=' + idents[0] + ',' + makeGetTempDouble(0, 'i32') + ')';
+ 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/runner.py b/tests/runner.py
index 7c0edcbe..6e76d061 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -276,6 +276,11 @@ process(sys.argv[1])
os.chdir(cwd)
out = open(stdout, 'r').read()
err = open(stderr, 'r').read()
+ if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS:
+ if 'Successfully compiled asm.js code' in err and 'asm.js link error' not in err:
+ print >> sys.stderr, "[was asm.js'ified]"
+ else:
+ print >> sys.stderr, "[did NOT asm.js'ify]"
if output_nicerizer:
ret = output_nicerizer(out, err)
else:
@@ -2316,8 +2321,8 @@ Exception execution path of first function! 1
self.do_run(src, '*throw...caught!infunc...done!*')
Settings.DISABLE_EXCEPTION_CATCHING = 1
- self.do_run(src, 'Compiled code throwing an exception')
-
+ self.do_run(src, 'Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 to catch.')
+
src = '''
#include <iostream>
@@ -3348,6 +3353,8 @@ def process(filename):
self.do_run(src, '*96,97,98,-14,-14,101*')
def test_bigswitch(self):
+ if Settings.RELOOP: return self.skip('TODO: switch in relooper, issue #781')
+
src = open(path_from_root('tests', 'bigswitch.cpp')).read()
self.do_run(src, '''34962: GL_ARRAY_BUFFER (0x8892)
26214: what?
@@ -10556,7 +10563,7 @@ elif 'benchmark' in str(sys.argv):
times = []
for i in range(TEST_REPS):
start = time.time()
- js_output = self.run_generated_code(JS_ENGINE, final_filename, args, check_timeout=False)
+ js_output = run_js(final_filename, engine=JS_ENGINE, args=args, stderr=PIPE, full_output=True)
if i == 0 and 'Successfully compiled asm.js code' in js_output:
print "[%s was asm.js'ified]" % name
curr = time.time()-start
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 8db40bc6..d26d902f 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -473,6 +473,12 @@ function simplifyExpressionsPre(ast) {
if (!unsigned) {
input[1][1] = 'HEAPU' + bits; // make unsigned
}
+ if (asm) {
+ // we cannot return HEAPU8 without a coercion, but at least we do HEAP8 & 255 => HEAPU8 | 0
+ node[1] = '|';
+ node[3][1] = 0;
+ return node;
+ }
return input;
}
}
@@ -1316,6 +1322,14 @@ function normalizeAsm(func) {
while (i < stats.length) {
traverse(stats[i], function(node, type) {
if (type == 'var') {
+ for (var j = 0; j < node[1].length; j++) {
+ var v = node[1][j];
+ var name = v[0];
+ var value = v[1];
+ if (!(name in data.vars)) {
+ data.vars[name] = detectAsmCoercion(value);
+ }
+ }
unVarify(node[1], node);
} else if (type == 'dot') {
if (node[1][0] == 'name' && node[1][1] == 'Math') {
diff --git a/tools/shared.py b/tools/shared.py
index a78db8e0..f94bb263 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -344,10 +344,12 @@ try:
except:
COMPILER_OPTS = []
# Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms
+# -fno-ms-compatibility is passed, since on Windows, Clang enables a 'MS compatibility mode' by default, that disables char16_t and char32_t
+# to be MSVC header -compatible. This would cause build errors in libcxx file __config.
COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__',
'-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__',
- '-D__STDC__', '-Xclang', '-triple=i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno']
-
+ '-D__STDC__', '-Xclang', '-triple=i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno',
+ '-fno-ms-compatibility']
USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK')