aboutsummaryrefslogtreecommitdiff
path: root/src/parseTools.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/parseTools.js')
-rw-r--r--src/parseTools.js58
1 files changed, 48 insertions, 10 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 520d278e..5ec3b4ed 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -683,16 +683,14 @@ function parseArbitraryInt(str, bits) {
return ret;
}
-function parseI64Constant(str) {
- assert(USE_TYPED_ARRAYS == 2);
-
+function parseI64Constant(str, legalized) {
if (!isNumber(str)) {
// This is a variable. Copy it, so we do not modify the original
return legalizedI64s ? str : makeCopyI64(str);
}
var parsed = parseArbitraryInt(str, 64);
- if (legalizedI64s) return parsed;
+ if (legalizedI64s || legalized) return parsed;
return '[' + parsed[0] + ',' + parsed[1] + ']';
}
@@ -1537,7 +1535,8 @@ function makeRounding(value, bits, signed, floatConversion) {
// TODO: handle roundings of i64s
assert(bits);
// C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that.
- if (bits <= 32 && signed) return '((' + value + ')|0)'; // This is fast and even correct, for all cases
+ if (bits <= 32 && signed) return '((' + value + ')&-1)'; // This is fast and even correct, for all cases. Note that it is the same
+ // as |0, but &-1 hints to the js optimizer that this is a rounding correction
// Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
// the value is non-negative
if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
@@ -1617,6 +1616,10 @@ function processMathop(item) {
return result;
}
}
+ function i64PreciseOp(type, lastArg) {
+ return finish(['(i64Math.' + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 +
+ (lastArg ? ',' + lastArg : '') + '),i64Math.result[0])', 'i64Math.result[1]']);
+ }
switch (op) {
// basic integer ops
case 'or': {
@@ -1702,11 +1705,46 @@ function processMathop(item) {
case 'ptrtoint': return makeI64(idents[0], 0);
case 'inttoptr': return '(' + idents[0] + '[0])'; // just directly truncate the i64 to a 'pointer', which is an i32
// Dangerous, rounded operations. TODO: Fully emulate
- case 'add': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1])));
- case 'sub': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1])));
- case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's')));
- case 'mul': warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u')));
- case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u')));
+ case 'add': {
+ if (PRECISE_I64_MATH) {
+ return i64PreciseOp('add');
+ } else {
+ warnI64_1();
+ return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1])));
+ }
+ }
+ case 'sub': {
+ if (PRECISE_I64_MATH) {
+ return i64PreciseOp('subtract');
+ } else {
+ warnI64_1();
+ return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1])));
+ }
+ }
+ case 'sdiv': case 'udiv': {
+ if (PRECISE_I64_MATH) {
+ return i64PreciseOp('divide', op[0] === 'u');
+ } else {
+ warnI64_1();
+ return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's')));
+ }
+ }
+ case 'mul': {
+ if (PRECISE_I64_MATH) {
+ return i64PreciseOp('multiply');
+ } else {
+ warnI64_1();
+ return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u')));
+ }
+ }
+ case 'urem': case 'srem': {
+ if (PRECISE_I64_MATH) {
+ return i64PreciseOp('modulo', op[0] === 'u');
+ } else {
+ warnI64_1();
+ return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u')));
+ }
+ }
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');