aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/library.js9
-rw-r--r--src/parseTools.js59
-rw-r--r--src/runtime.js10
3 files changed, 55 insertions, 23 deletions
diff --git a/src/library.js b/src/library.js
index 5a429131..0e7b8b54 100644
--- a/src/library.js
+++ b/src/library.js
@@ -2260,7 +2260,6 @@ LibraryManager.library = {
} else if (type == 'i64') {
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
{{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}];
- ret = unSign(ret[0], 32) + unSign(ret[1], 32)*Math.pow(2, 32); // Unsigned in this notation. Signed later if needed. // XXX - loss of precision
#else
} else if (type == 'i64') {
ret = {{{ makeGetValue('varargs', 'argIndex', 'i64', undefined, undefined, true) }}};
@@ -2270,7 +2269,7 @@ LibraryManager.library = {
ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}};
}
argIndex += Runtime.getNativeFieldSize(type);
- return Number(ret);
+ return ret;
}
var ret = [];
@@ -2392,6 +2391,12 @@ LibraryManager.library = {
var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0);
argSize = argSize || 4;
var currArg = getNextArg('i' + (argSize * 8));
+#if I64_MODE == 1
+ // Flatten i64-1 [low, high] into a (slightly rounded) double
+ if (argSize == 8) {
+ currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 'u'.charCodeAt(0));
+ }
+#endif
// Truncate to requested size.
if (argSize <= 4) {
var limit = Math.pow(256, argSize) - 1;
diff --git a/src/parseTools.js b/src/parseTools.js
index b287b237..c3913298 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -558,22 +558,13 @@ function makeInlineCalculation(expression, value, tempVar) {
return '(' + expression.replace(/VALUE/g, value) + ')';
}
-// Given two 32-bit unsigned parts of an emulated 64-bit number, combine them into a JS number (double).
-// 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
-function makeBigInt(low, high) {
- // here VALUE will be the big part
- return '(' + high + ' <= 2147483648 ? (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))' +
- ' : (' + makeSignOp(low, 'i32', 're', 1, 1) + '+(1+' + makeSignOp(high, 'i32', 're', 1, 1) + ')*4294967296))';
-}
-
// Makes a proper runtime value for a 64-bit value from low and high i32s. low and high are assumed to be unsigned.
function makeI64(low, high) {
high = high || '0';
if (I64_MODE == 1) {
return '[' + makeSignOp(low, 'i32', 'un', 1, 1) + ',' + makeSignOp(high, 'i32', 'un', 1, 1) + ']';
} else {
- if (high) return makeBigInt(low, high);
+ if (high) return RuntimeGenerator.makeBigInt(low, high);
return low;
}
}
@@ -589,7 +580,7 @@ function splitI64(value) {
}
function mergeI64(value) {
assert(I64_MODE == 1);
- return makeInlineCalculation(makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
+ 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
@@ -1600,17 +1591,43 @@ function processMathop(item) {
case 'xor': {
return '[' + ident1 + '[0] ^ ' + ident2 + '[0], ' + ident1 + '[1] ^ ' + ident2 + '[1]]';
}
- case 'shl': {
- return '[' + ident1 + '[0] << ' + ident2 + ', ' +
- '('+ident1 + '[1] << ' + ident2 + ') | ((' + ident1 + '[0]&((Math.pow(2, ' + ident2 + ')-1)<<(32-' + ident2 + '))) >>> (32-' + ident2 + '))]';
- }
- case 'ashr': {
- return '[('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&(Math.pow(2, ' + ident2 + ')-1))<<(32-' + ident2 + ')),' +
- ident1 + '[1] >>> ' + ident2 + ']';
- }
+ case 'shl':
+ case 'ashr':
case 'lshr': {
- return '[('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&(Math.pow(2, ' + ident2 + ')-1))<<(32-' + ident2 + ')),' +
- ident1 + '[1] >>> ' + ident2 + ']';
+ assert(isNumber(ident2));
+ bits = parseInt(ident2);
+ var ander = Math.pow(2, bits)-1;
+ if (bits < 32) {
+ switch (op) {
+ case 'shl':
+ return '[' + ident1 + '[0] << ' + ident2 + ', ' +
+ '('+ident1 + '[1] << ' + ident2 + ') | ((' + ident1 + '[0]&(' + ander + '<<' + (32 - bits) + ')) >>> (32-' + ident2 + '))]';
+ case 'ashr':
+ return '[((('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&' + ander + ')<<' + (32 - bits) + ')) >> 0) >>> 0,' +
+ '(' + ident1 + '[1] >> ' + ident2 + ') >>> 0]';
+ case 'lshr':
+ return '[(('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&' + ander + ')<<' + (32 - bits) + ')) >>> 0,' +
+ ident1 + '[1] >>> ' + ident2 + ']';
+ }
+ } else if (bits == 32) {
+ switch (op) {
+ case 'shl':
+ return '[0, ' + ident1 + '[0]]';
+ case 'ashr':
+ return '[' + ident1 + '[1], (' + ident1 + '[1]|0) < 0 ? ' + ander + ' : 0]';
+ case 'lshr':
+ return '[' + ident1 + '[1], 0]';
+ }
+ } else { // bits > 32
+ switch (op) {
+ case 'shl':
+ return '[0, ' + ident1 + '[0] << ' + (bits - 32) + ']';
+ case 'ashr':
+ return '[(' + ident1 + '[1] >> ' + (bits - 32) + ') >>> 0, (' + ident1 + '[1]|0) < 0 ? ' + ander + ' : 0]';
+ case 'lshr':
+ return '[' + ident1 + '[1] >>> ' + (bits - 32) + ', 0]';
+ }
+ }
}
case 'uitofp': case 'sitofp': return ident1 + '[0] + ' + ident1 + '[1]*4294967296';
case 'fptoui': case 'fptosi': return splitI64(ident1);
diff --git a/src/runtime.js b/src/runtime.js
index 6439d0ed..495e72dd 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -73,6 +73,15 @@ var RuntimeGenerator = {
quantum = '(quantum ? quantum : {{{ QUANTUM_SIZE }}})';
}
return target + ' = ' + Runtime.forceAlign(target, quantum);
+ },
+
+ // Given two 32-bit unsigned parts of an emulated 64-bit number, combine them into a JS number (double).
+ // 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(high, 'i32', 're', 1, 1) + ' >= 0))' +
+ ' ? (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))' +
+ ' : (' + makeSignOp(low, 'i32', 're', 1, 1) + '+(1+' + makeSignOp(high, 'i32', 're', 1, 1) + ')*4294967296))';
}
};
@@ -260,6 +269,7 @@ var Runtime = {
Runtime.stackAlloc = unInline('stackAlloc', ['size']);
Runtime.staticAlloc = unInline('staticAlloc', ['size']);
Runtime.alignMemory = unInline('alignMemory', ['size', 'quantum']);
+Runtime.makeBigInt = unInline('makeBigInt', ['low', 'high', 'unsigned']);
function getRuntime() {
var ret = 'var Runtime = {\n';