diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-02-08 21:23:07 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-02-11 14:54:29 -0800 |
commit | 574bc2c9207f455518eab14bd1656cf9ba8b30c1 (patch) | |
tree | c1e6615e9b2d3bfb16e35db3eb8549130a8be4d1 /src | |
parent | ee70b710083e7659f1391b239eb6365e4120d2d3 (diff) |
initial work on legalizing i64s
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 158 | ||||
-rw-r--r-- | src/intertyper.js | 3 | ||||
-rw-r--r-- | src/jsifier.js | 14 | ||||
-rw-r--r-- | src/parseTools.js | 102 | ||||
-rw-r--r-- | src/runtime.js | 7 |
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; } }; |