aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-02-08 21:23:07 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-02-11 14:54:29 -0800
commit574bc2c9207f455518eab14bd1656cf9ba8b30c1 (patch)
treec1e6615e9b2d3bfb16e35db3eb8549130a8be4d1 /src
parentee70b710083e7659f1391b239eb6365e4120d2d3 (diff)
initial work on legalizing i64s
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js158
-rw-r--r--src/intertyper.js3
-rw-r--r--src/jsifier.js14
-rw-r--r--src/parseTools.js102
-rw-r--r--src/runtime.js7
5 files changed, 171 insertions, 113 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index c007452b..104f2af8 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -22,7 +22,7 @@ function cleanFunc(func) {
var BRANCH_INVOKE = set('branch', 'invoke');
var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic');
-var UNFOLDABLE = set('value', 'type', 'phiparam');
+var UNUNFOLDABLE = set('value', 'type', 'phiparam');
// Analyzer
@@ -118,24 +118,16 @@ function analyzer(data, sidePass) {
// Currently we just legalize completely unrealistic types into bundles of i32s, and just
// the most common instructions that can be involved with such types: load, store, shifts,
// trunc and zext.
- //
- // TODO: Expand this also into legalization of i64 into i32,i32, which can then
- // replace our i64 mode 1 implementation. Legalizing i64s is harder though
- // as they can appear in function arguments and we would also need to implement
- // an unfolder (to uninline inline LLVM function calls, so that each LLVM line
- // has a single LLVM instruction).
substrate.addActor('Legalizer', {
processItem: function(data) {
// Legalization
if (USE_TYPED_ARRAYS == 2) {
function isIllegalType(type) {
var bits = getBits(type);
- return bits > 0 && (bits > 64 || !isPowerOfTwo(bits));
+ return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
}
function getLegalVars(base, bits) {
- if (isNumber(base)) {
- return getLegalLiterals(base, bits);
- }
+ assert(!isNumber(base));
var ret = new Array(Math.ceil(bits/32));
var i = 0;
while (bits > 0) {
@@ -173,14 +165,40 @@ function analyzer(data, sidePass) {
return toAdd.length;
}
data.functions.forEach(function(func) {
+ // Legalize function parameters
+ var i = 0;
+ while (i < func.params.length) {
+ var param = func.params[i];
+ if (param.intertype == 'value' && isIllegalType(param.type)) {
+ var toAdd = getLegalVars(param.ident, getBits(param.type)).map(function(element) {
+ return {
+ intertype: 'value',
+ type: 'i' + element.bits,
+ ident: element.ident,
+ byval: 0
+ };
+ });
+ Array.prototype.splice.apply(func.params, [i, 1].concat(toAdd));
+ i += toAdd.length;
+ continue;
+ }
+ i++;
+ }
+ // Legalize lines in labels
var tempId = 0;
func.labels.forEach(function(label) {
var i = 0, bits;
while (i < label.lines.length) {
var item = label.lines[i];
- // Check if we need to legalize here
+ // Check if we need to legalize here, and do some trivial legalization along the way
var isIllegal = false;
walkInterdata(item, function(item) {
+ if (item.intertype == 'getelementptr' || (item.intertype == 'call' && item.ident in LLVM.INTRINSICS_32)) {
+ // Turn i64 args into i32
+ for (var i = 0; i < item.params.length; i++) {
+ if (item.params[i].type == 'i64') item.params[i].type = 'i32';
+ }
+ }
if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
isIllegal = true;
}
@@ -193,7 +211,11 @@ function analyzer(data, sidePass) {
// generated - they may need legalization too
var unfolded = [];
walkAndModifyInterdata(item, function(subItem) {
- if (subItem != item && !(subItem.intertype in UNFOLDABLE)) {
+ // Unfold all non-value interitems that we can, and also unfold all numbers (doing the latter
+ // makes it easier later since we can then assume illegal expressions are always variables
+ // accessible through ident$x, and not constants we need to parse then and there)
+ if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) ||
+ (subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) {
var tempIdent = '$$emscripten$temp$' + (tempId++);
subItem.assignTo = tempIdent;
unfolded.unshift(subItem);
@@ -244,6 +266,23 @@ function analyzer(data, sidePass) {
} else if (item.assignTo) {
var value = item;
switch (value.intertype) {
+ case 'value': {
+ dprint('legalizer', 'Legalizing value at line ' + item.lineNum);
+ bits = getBits(value.type);
+ var elements = getLegalVars(item.assignTo, bits);
+ var values = getLegalLiterals(item.ident, bits);
+ var j = 0;
+ var toAdd = elements.map(function(element) {
+ return {
+ intertype: 'value',
+ assignTo: element.ident,
+ type: 'i' + bits,
+ ident: values[j++].ident
+ };
+ });
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
case 'load': {
dprint('legalizer', 'Legalizing load at line ' + item.lineNum);
bits = getBits(value.valueType);
@@ -309,9 +348,9 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
- case 'bitcast': {
+ case 'bitcast': case 'inttoptr': case 'ptrtoint': {
value = {
- op: 'bitcast',
+ op: item.intertype,
param1: item.params[0]
};
// fall through
@@ -321,49 +360,61 @@ function analyzer(data, sidePass) {
var toAdd = [];
var sourceBits = getBits(value.param1.type);
var sourceElements;
- if (sourceBits <= 64) {
+ if (sourceBits <= 32) {
// The input is a legal type
- if (sourceBits <= 32) {
- sourceElements = [{ ident: value.param1.ident, bits: sourceBits }];
- } else if (sourceBits == 64 && I64_MODE == 1) {
- sourceElements = [{ ident: value.param1.ident + '[0]', bits: 32 },
- { ident: value.param1.ident + '[1]', bits: 32 }];
- // Add the source element as a param so that it is not eliminated as unneeded (the idents are not a simple ident here)
- toAdd.push({
- intertype: 'value', ident: ';', type: 'rawJS',
- params: [{ intertype: 'value', ident: value.param1.ident, type: 'i32' }]
- });
- } else {
- throw 'Invalid legal type as source of legalization ' + sourceBits;
- }
+ sourceElements = [{ ident: value.param1.ident, bits: sourceBits }];
} else {
sourceElements = getLegalVars(value.param1.ident, sourceBits);
}
// All mathops can be parametrized by how many shifts we do, and how big the source is
var shifts = 0;
- var targetBits;
+ var targetBits = sourceBits;
var processor = null;
+ var signed = false;
switch (value.op) {
+ case 'ashr': {
+ signed = true;
+ // fall through
+ }
case 'lshr': {
shifts = parseInt(value.param2.ident);
- targetBits = sourceBits;
break;
}
case 'shl': {
shifts = -parseInt(value.param2.ident);
- targetBits = sourceBits;
break;
}
- case 'trunc': case 'zext': {
+ case 'sext': {
+ signed = true;
+ // fall through
+ }
+ case 'trunc': case 'zext': case 'ptrtoint': {
targetBits = getBits(value.param2.ident);
break;
}
+ case 'inttoptr': {
+ targetBits = 32;
+ break;
+ }
case 'bitcast': {
- targetBits = sourceBits;
+ break;
+ }
+ case 'select': {
+ var otherElementsA = getLegalVars(value.param2.ident, sourceBits);
+ var otherElementsB = getLegalVars(value.param3.ident, sourceBits);
+ processor = function(result, j) {
+ return {
+ intertype: 'mathop',
+ op: 'select',
+ type: 'i' + otherElementsA[j].bits,
+ param1: value.param1,
+ param2: { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits },
+ param2: { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits }
+ };
+ };
break;
}
case 'or': case 'and': case 'xor': {
- targetBits = sourceBits;
var otherElements = getLegalVars(value.param2.ident, sourceBits);
processor = function(result, j) {
return {
@@ -376,26 +427,32 @@ function analyzer(data, sidePass) {
};
break;
}
+ case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem':
+ case 'icmp':case 'uitofp': case 'sitofp': {
+ // We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop
+ i++;
+ continue;
+ }
default: throw 'Invalid mathop for legalization: ' + [value.op, item.lineNum, dump(item)];
}
// Do the legalization
assert(isNumber(shifts), 'TODO: handle nonconstant shifts');
var targetElements = getLegalVars(item.assignTo, targetBits);
var sign = shifts >= 0 ? 1 : -1;
- var shiftOp = shifts >= 0 ? 'shl' : 'lshr';
- var shiftOpReverse = shifts >= 0 ? 'lshr' : 'shl';
+ var shiftOp = shifts >= 0 ? 'shl' : (signed ? 'ashr' : 'lshr');
+ var shiftOpReverse = shifts >= 0 ? (signed ? 'ashr' : 'lshr') : 'shl';
var whole = shifts >= 0 ? Math.floor(shifts/32) : Math.ceil(shifts/32);
var fraction = Math.abs(shifts % 32);
for (var j = 0; j < targetElements.length; j++) {
var result = {
intertype: 'value',
- ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : '0',
+ ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : (signed ? '-1' : '0'),
type: 'i32',
};
if (fraction != 0) {
var other = {
intertype: 'value',
- ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : '0',
+ ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : (signed ? '-1' : '0'),
type: 'i32',
};
other = {
@@ -436,26 +493,10 @@ function analyzer(data, sidePass) {
result.assignTo = targetElements[j].ident;
toAdd.push(result);
}
- if (targetBits <= 64) {
+ if (targetBits <= 32) {
// We are generating a normal legal type here
- var legalValue;
- if (targetBits == 64 && I64_MODE == 1) {
- // Generate an i64-1 [low,high]. This will be unnecessary when we legalize i64s
- legalValue = {
- intertype: 'value',
- ident: '[' + targetElements[0].ident + ',' + targetElements[1].ident + ']',
- type: 'rawJS',
- // Add the target elements as params so that they are not eliminated as unneeded (the ident is not a simple ident here)
- params: targetElements.map(function(element) {
- return { intertype: 'value', ident: element.ident, type: 'i32' };
- })
- };
- } else if (targetBits <= 32) {
- legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'rawJS' };
- // truncation to smaller than 32 bits has already been done, if necessary
- } else {
- throw 'Invalid legal type as target of legalization ' + targetBits;
- }
+ legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'rawJS' };
+ // truncation to smaller than 32 bits has already been done, if necessary
legalValue.assignTo = item.assignTo;
toAdd.push(legalValue);
}
@@ -466,6 +507,7 @@ function analyzer(data, sidePass) {
}
assert(0, 'Could not legalize illegal line: ' + [item.lineNum, dump(item)]);
}
+ if (dcheck('legalizer')) dprint('zz legalized: \n' + dump(label.lines));
});
});
}
diff --git a/src/intertyper.js b/src/intertyper.js
index 3dab220b..91ad15eb 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -539,9 +539,6 @@ function intertyper(data, sidePass, baseLineNums) {
params: params,
hasVarArgs: hasVarArgs(params),
lineNum: item.lineNum,
- paramIdents: params.map(function(param) {
- return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident);
- }).filter(function(param) { return param != null; })
}];
}
});
diff --git a/src/jsifier.js b/src/jsifier.js
index 71533309..8bfe453b 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -497,16 +497,20 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS = '\n';
+ var paramIdents = func.params.map(function(param) {
+ return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident);
+ }).filter(function(param) { return param != null; })
+
if (CLOSURE_ANNOTATIONS) {
func.JS += '/**\n';
- func.paramIdents.forEach(function(param) {
+ paramIdents.forEach(function(param) {
func.JS += ' * @param {number} ' + param + '\n';
});
func.JS += ' * @return {number}\n'
func.JS += ' */\n';
}
- func.JS += 'function ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n';
+ func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
if (PROFILE) {
func.JS += ' if (PROFILING) { '
@@ -1046,11 +1050,6 @@ function JSify(data, functionsOnly, givenFunctions) {
var hasVarArgs = isVarArgsFunctionType(type);
var normalArgs = (hasVarArgs && !useJSArgs) ? countNormalArgs(type) : -1;
- if (I64_MODE == 1 && ident in LLVM.INTRINSICS_32) {
- // Some LLVM intrinsics use i64 where it is not needed, and would cause much overhead
- params.forEach(function(param) { if (param.type == 'i64') param.type = 'i32' });
- }
-
params.forEach(function(param, i) {
var val = finalizeParam(param);
if (!hasVarArgs || useJSArgs || i < normalArgs) {
@@ -1190,6 +1189,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print(postParts[0]);
// Print out global variables and postsets TODO: batching
+ legalizedI64s = false;
JSify(analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true), true, Functions);
data.unparsedGlobalss = null;
diff --git a/src/parseTools.js b/src/parseTools.js
index fcb85281..d8221499 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -533,18 +533,27 @@ function makeI64(low, high) {
}
}
+// XXX Make all i64 parts signed
+
// Splits a number (an integer in a double, possibly > 32 bits) into an I64_MODE 1 i64 value.
-// Will suffer from rounding. margeI64 does the opposite.
-// TODO: optimize I64 calcs. For example, saving their parts as signed 32 as opposed to unsigned would help
+// Will suffer from rounding. mergeI64 does the opposite.
function splitI64(value) {
// We need to min here, since our input might be a double, and large values are rounded, so they can
// be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a
// HEAP32 or |0'd, etc.
- return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP');
+ if (legalizedI64s) {
+ return [value + '>>>0', 'Math.min(Math.floor(' + value + '/4294967296), 4294967295)'];
+ } else {
+ return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP');
+ }
}
function mergeI64(value) {
assert(I64_MODE == 1);
- return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
+ if (legalizedI64s) {
+ return RuntimeGenerator.makeBigInt(value + '$0', value + '$1');
+ } else {
+ return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
+ }
}
// Takes an i64 value and changes it into the [low, high] form used in i64 mode 1. In that
@@ -649,10 +658,11 @@ function parseI64Constant(str) {
if (!isNumber(str)) {
// This is a variable. Copy it, so we do not modify the original
- return makeCopyI64(str);
+ return legalizedI64s ? str : makeCopyI64(str);
}
var parsed = parseArbitraryInt(str, 64);
+ if (legalizedI64s) return parsed;
return '[' + parsed[0] + ',' + parsed[1] + ']';
}
@@ -1534,6 +1544,8 @@ function isSignedOp(op, variant) {
return op in SIGNED_OP || (variant && variant[0] == 's');
}
+var legalizedI64s = true; // We do not legalize globals, but do legalize function lines. This will be true in the latter case
+
function processMathop(item) {
var op = item.op;
var variant = item.variant;
@@ -1543,7 +1555,7 @@ function processMathop(item) {
if (item['param'+i]) {
paramTypes[i-1] = item['param'+i].type || type;
item['ident'+i] = finalizeLLVMParameter(item['param'+i]);
- if (!isNumber(item['ident'+i])) {
+ if (!isNumber(item['ident'+i]) && !isNiceIdent(item['ident'+i])) {
item['ident'+i] = '(' + item['ident'+i] + ')'; // we may have nested expressions. So enforce the order of operations we want
}
} else {
@@ -1574,8 +1586,24 @@ function processMathop(item) {
if ((type == 'i64' || paramTypes[0] == 'i64' || paramTypes[1] == 'i64' || ident2 == '(i64)') && I64_MODE == 1) {
var warnI64_1 = function() {
- warnOnce('Arithmetic on 64-bit integers in mode 1 is rounded and flaky, like mode 0, but much slower!');
+ warnOnce('Arithmetic on 64-bit integers in mode 1 is rounded and flaky, like mode 0!');
};
+ // In ops that can be either legalized or not, we need to differentiate how we access low and high parts
+ var low1 = ident1 + (legalizedI64s ? '$0' : '[0]');
+ var high1 = ident1 + (legalizedI64s ? '$1' : '[1]');
+ var low2 = ident2 + (legalizedI64s ? '$0' : '[0]');
+ var high2 = ident2 + (legalizedI64s ? '$1' : '[1]');
+ function finish(result) {
+ // If this is in legalization mode, steal the assign and assign into two vars
+ if (legalizedI64s) {
+ assert(item.assignTo);
+ var ret = 'var ' + item.assignTo + '$0 = ' + result[0] + '; var ' + item.assignTo + '$1 = ' + result[1] + ';';
+ item.assignTo = null;
+ return ret;
+ } else {
+ return result;
+ }
+ }
switch (op) {
// basic integer ops
case 'or': {
@@ -1627,38 +1655,28 @@ function processMathop(item) {
}
}
}
- case 'uitofp': case 'sitofp': return ident1 + '[0] + ' + ident1 + '[1]*4294967296';
- case 'fptoui': case 'fptosi': return splitI64(ident1);
+ case 'uitofp': case 'sitofp': return low1 + ' + ' + high1 + '*4294967296';
+ case 'fptoui': case 'fptosi': return finish(splitI64(ident1));
case 'icmp': {
switch (variant) {
- case 'uge': return ident1 + '[1] >= ' + ident2 + '[1] && (' + ident1 + '[1] > ' + ident2 + '[1] || ' +
- ident1 + '[0] >= ' + ident2 + '[0])';
- case 'sge': return '(' + ident1 + '[1]|0) >= (' + ident2 + '[1]|0) && ((' + ident1 + '[1]|0) > (' + ident2 + '[1]|0) || ' +
- '(' + ident1 + '[0]|0) >= (' + ident2 + '[0]|0))';
- case 'ule': return ident1 + '[1] <= ' + ident2 + '[1] && (' + ident1 + '[1] < ' + ident2 + '[1] || ' +
- ident1 + '[0] <= ' + ident2 + '[0])';
- case 'sle': return '(' + ident1 + '[1]|0) <= (' + ident2 + '[1]|0) && ((' + ident1 + '[1]|0) < (' + ident2 + '[1]|0) || ' +
- '(' + ident1 + '[0]|0) <= (' + ident2 + '[0]|0))';
- case 'ugt': return ident1 + '[1] > ' + ident2 + '[1] || (' + ident1 + '[1] == ' + ident2 + '[1] && ' +
- ident1 + '[0] > ' + ident2 + '[0])';
- case 'sgt': return '(' + ident1 + '[1]|0) > (' + ident2 + '[1]|0) || ((' + ident1 + '[1]|0) == (' + ident2 + '[1]|0) && ' +
- '(' + ident1 + '[0]|0) > (' + ident2 + '[0]|0))';
- case 'ult': return ident1 + '[1] < ' + ident2 + '[1] || (' + ident1 + '[1] == ' + ident2 + '[1] && ' +
- ident1 + '[0] < ' + ident2 + '[0])';
- case 'slt': return '(' + ident1 + '[1]|0) < (' + ident2 + '[1]|0) || ((' + ident1 + '[1]|0) == (' + ident2 + '[1]|0) && ' +
- '(' + ident1 + '[0]|0) < (' + ident2 + '[0]|0))';
- case 'ne': case 'eq': {
- // We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
- // since LLVM tells us if <=, >= etc. comparisons are signed, but not == and !=.
- assert(paramTypes[0] == paramTypes[1]);
- ident1 = makeSignOp(ident1, paramTypes[0], 're');
- ident2 = makeSignOp(ident2, paramTypes[1], 're');
- if (variant === 'eq') {
- return ident1 + '[0] == ' + ident2 + '[0] && ' + ident1 + '[1] == ' + ident2 + '[1]';
- } else {
- return ident1 + '[0] != ' + ident2 + '[0] || ' + ident1 + '[1] != ' + ident2 + '[1]';
- }
- }
+ case 'uge': return high1 + ' >= ' + high2 + ' && (' + high1 + ' > ' + high + ' || ' +
+ low1 + ' >= ' + low2 + ')';
+ case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' +
+ '(' + low1 + '|0) >= (' + low2 + '|0))';
+ case 'ule': return high1 + ' <= ' + high2 + ' && (' + high1 + ' < ' + high2 + ' || ' +
+ low1 + ' <= ' + low2 + ')';
+ case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' +
+ '(' + low1 + '|0) <= (' + low2 + '|0))';
+ case 'ugt': return high1 + ' > ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' +
+ low1 + ' > ' + low2 + ')';
+ case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
+ '(' + low1 + '|0) > (' + low2 + '|0))';
+ case 'ult': return high1 + ' < ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' +
+ low1 + ' < ' + low2 + ')';
+ 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 + '';
default: throw 'Unknown icmp variant: ' + variant;
}
}
@@ -1671,11 +1689,11 @@ function processMathop(item) {
case 'ptrtoint': return makeI64(ident1, 0);
case 'inttoptr': return '(' + ident1 + '[0])'; // just directly truncate the i64 to a 'pointer', which is an i32
// Dangerous, rounded operations. TODO: Fully emulate
- case 'add': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '+' + mergeI64(ident2)), bits);
- case 'sub': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '-' + mergeI64(ident2)), bits);
- case 'sdiv': case 'udiv': warnI64_1(); return splitI64(makeRounding(mergeI64(ident1) + '/' + mergeI64(ident2), bits, op[0] === 's'));
- case 'mul': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '*' + mergeI64(ident2)), bits);
- case 'urem': case 'srem': warnI64_1(); return splitI64(mergeI64(ident1) + '%' + mergeI64(ident2));
+ case 'add': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '+' + mergeI64(ident2)));
+ case 'sub': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '-' + mergeI64(ident2)));
+ case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(ident1) + '/' + mergeI64(ident2), bits, op[0] === 's')));
+ case 'mul': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '*' + mergeI64(ident2)));
+ case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '%' + mergeI64(ident2)));
case 'bitcast': {
// Pointers are not 64-bit, so there is really only one possible type of bitcast here, int to float or vice versa
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
diff --git a/src/runtime.js b/src/runtime.js
index b5663045..803407c6 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -79,9 +79,10 @@ var RuntimeGenerator = {
// Rounding is inevitable if the number is large. This is a particular problem for small negative numbers
// (-1 will be rounded!), so handle negatives separately and carefully
makeBigInt: function(low, high, unsigned) {
- return '(' + unsigned +
- ' ? (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))' +
- ' : (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 're', 1, 1) + '*4294967296)))';
+ var unsignedRet = '(' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))';
+ var signedRet = '(' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 're', 1, 1) + '*4294967296))';
+ if (typeof unsigned === 'string') return '(' + unsigned + ' ? ' + unsignedRet + ' : ' + signedRet + ')';
+ return unsigned ? unsignedRet : signedRet;
}
};