aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parseTools.js38
-rw-r--r--src/preamble.js8
-rw-r--r--tests/runner.py13
3 files changed, 40 insertions, 19 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 03a529a1..ade22214 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -541,6 +541,7 @@ function makeI64(low, high) {
// 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
function splitI64(value) {
assert(I64_MODE == 1);
return '(tempInt=' + value + ',' + makeI64('tempInt>>>0', 'Math.floor(tempInt/4294967296)') + ')';
@@ -1439,24 +1440,35 @@ function makeSignOp(value, type, op, force) {
return value;
}
-function makeRounding(value, bits, signed) {
+// @param floatConversion Means that we are receiving a float and rounding it to
+// an integer. We must be careful here, the input has *not*
+// already been converted to a signed/unsigned value (that
+// would already do rounding, before us!)
+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.
- // With 32 bits and less, and a signed value, |0 will round it like C does.
- if (bits && bits <= 32 && signed) return '(('+value+')|0)';
- // If the value may be negative, and we care about proper rounding, then use a slow but correct function
- if (signed && correctRoundings()) return 'cRound(' + value + ')';
- // Either this must be positive, so Math.Floor is correct, or we don't care
- return 'Math.floor(' + value + ')';
-}
+ if (bits <= 32 && signed) return '((' + value + ')|0)'; // This is fast and even correct, for all cases
+ // 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 + ')';
+ // We are left with >32 bits signed, or a float conversion. Check and correct inline
+ // Note that if converting a float, we may have the wrong sign at this point! But, we have
+ // been rounded properly regardless, and we will be sign-corrected later when actually used, if
+ // necessary.
+ return '(tempBigInt='+value+',tempBigInt >= 0 ? Math.floor(tempBigInt) : Math.ceil(tempBigInt))';
+}
+
+// fptoui and fptosi are not in these, because we need to be careful about what we do there. We can't
+// just sign/unsign the input first.
+var UNSIGNED_OP = set('udiv', 'urem', 'uitofp', 'zext', 'lshr');
+var SIGNED_OP = set('sdiv', 'srem', 'sitofp', 'sext', 'ashr');
function isUnsignedOp(op, variant) {
- return op in set('udiv', 'urem', 'uitofp', 'zext', 'lshr') || (variant && variant[0] == 'u');
+ return op in UNSIGNED_OP || (variant && variant[0] == 'u');
}
-
function isSignedOp(op, variant) {
- return op in set('sdiv', 'srem', 'sitofp', 'sext', 'ashr') || (variant && variant[0] == 's');
+ return op in SIGNED_OP || (variant && variant[0] == 's');
}
function processMathop(item) { with(item) {
@@ -1622,7 +1634,7 @@ function processMathop(item) { with(item) {
case 'fdiv': return getFastValue(ident1, '/', ident2, item.type);
case 'fmul': return getFastValue(ident1, '*', ident2, item.type);
case 'uitofp': case 'sitofp': return ident1;
- case 'fptoui': case 'fptosi': return makeRounding(ident1, bitsLeft, op === 'fptosi');
+ case 'fptoui': case 'fptosi': return makeRounding(ident1, bitsLeft, op === 'fptosi', true);
// TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking
// Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs.
diff --git a/src/preamble.js b/src/preamble.js
index 9df6bf60..3fcdf1f8 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -230,12 +230,6 @@ var CorrectionsMonitor = {
}
};
-#if CORRECT_ROUNDINGS
-function cRound(x) {
- return x >= 0 ? Math.floor(x) : Math.ceil(x);
-}
-#endif
-
#if CHECK_OVERFLOWS
//========================================
// Debugging tools - Mathop overflows
@@ -381,6 +375,8 @@ var __ATEXIT__ = [];
var ABORT = false;
var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair;
#if I64_MODE == 1
var tempI64, tempI64b;
diff --git a/tests/runner.py b/tests/runner.py
index 9f1893ec..a808681e 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -4233,6 +4233,8 @@ Child2:9
Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
self.do_run(src, '*1*')
+ Settings.CORRECT_SIGNS = 0
+
# Overflows
src = '''
@@ -4287,6 +4289,8 @@ Child2:9
assert 'UNEXPECTED' not in str(e), str(e)
assert 'Expected to find' in str(e), str(e)
+ Settings.CORRECT_OVERFLOWS = 0
+
# Roundings
src = '''
@@ -4314,21 +4318,30 @@ Child2:9
Settings.CORRECT_ROUNDINGS = 0
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here!
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-6**5*') # We fail, since no fast shortcut for 32-bit unsigneds
Settings.CORRECT_ROUNDINGS = 1
self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') # Correct
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Correct
+ Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') # Correct
+ return
+ Settings.CORRECT_SIGNS = 0
Settings.CORRECT_ROUNDINGS = 2
Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*')
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-5**5*') # No such luck here
# And reverse the check with = 2
Settings.CORRECT_ROUNDINGS = 3
Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"]
self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*')
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*')
+ Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*')
+ Settings.CORRECT_SIGNS = 0
def test_pgo(self):
if Settings.USE_TYPED_ARRAYS == 2: return self.skip('LLVM opts optimize out the things we check')