aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@mozilla.com>2011-03-04 20:02:31 -0800
committerAlon Zakai <azakai@mozilla.com>2011-03-04 20:02:31 -0800
commit1545aaf14f7ce5a92c5acec23687742d0d4fa0ec (patch)
treeeeceb9e8882aac1eaac1068789866ac0c19883c3 /src
parent46691ad5cd94f1a629ac747831e9572b3661682e (diff)
integer rounding fixes and CORRECT_ROUNDINGS option
Diffstat (limited to 'src')
-rw-r--r--src/compiler.js4
-rw-r--r--src/jsifier.js20
-rw-r--r--src/parseTools.js10
-rw-r--r--src/preamble.js6
-rw-r--r--src/settings.js3
5 files changed, 35 insertions, 8 deletions
diff --git a/src/compiler.js b/src/compiler.js
index e18492d5..b60f650e 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -25,10 +25,12 @@ var CONSTANTS = { 'QUANTUM_SIZE': QUANTUM_SIZE };
if (CORRECT_SIGNS === 2) {
CORRECT_SIGNS_LINES = set(CORRECT_SIGNS_LINES); // for fast checking
}
-
if (CORRECT_OVERFLOWS === 2) {
CORRECT_OVERFLOWS_LINES = set(CORRECT_OVERFLOWS_LINES); // for fast checking
}
+if (CORRECT_ROUNDINGS === 2) {
+ CORRECT_ROUNDINGS_LINES = set(CORRECT_ROUNDINGS_LINES); // for fast checking
+}
// Load compiler code
diff --git a/src/jsifier.js b/src/jsifier.js
index 0c7e56be..44f2ffe0 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -797,6 +797,16 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')';
}
+ function makeRounding(value, bits, signed) {
+ // 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 + ')';
+ }
+
var mathop = makeFuncLineActor('mathop', function(item) { with(item) {
for (var i = 1; i <= 4; i++) {
if (item['param'+i]) {
@@ -819,11 +829,13 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
if (item.type[0] === 'i') {
bits = parseInt(item.type.substr(1));
}
+ var bitsLeft = ident2 ? ident2.substr(2, ident2.length-3) : null; // remove (i and ), to leave number. This value is important in float ops
+
switch (op) {
// basic integer ops
case 'add': return handleOverflow(ident1 + ' + ' + ident2, bits);
case 'sub': return handleOverflow(ident1 + ' - ' + ident2, bits);
- case 'sdiv': case 'udiv': return 'Math.floor(' + ident1 + ' / ' + ident2 + ')';
+ case 'sdiv': case 'udiv': return makeRounding(ident1 + '/' + ident2, bits, op[0] === 's');
case 'mul': return handleOverflow(ident1 + ' * ' + ident2, bits);
case 'urem': case 'srem': return ident1 + ' % ' + ident2;
case 'or': return ident1 + ' | ' + ident2; // TODO this forces into a 32-bit int - add overflow-style checks? also other bitops below us
@@ -851,10 +863,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
case 'fdiv': return ident1 + ' / ' + ident2;
case 'fmul': return ident1 + ' * ' + ident2;
case 'uitofp': case 'sitofp': return ident1;
- case 'fptoui': case 'fptosi': return 'Math.floor(' + ident1 + ')'; // Note that this is different than C/C++ style rounding - they
- // round -2.75 to -2 and +2.75 to +2, in other words, they
- // floor the absolute value then restore the sign. JS doesn't
- // have a fast operator to do that
+ case 'fptoui': case 'fptosi': return makeRounding(ident1, bitsLeft, op === 'fptosi');
// 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.
@@ -895,7 +904,6 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
// truncating can change the number, e.g. by truncating to an i1
// in order to get the first bit
assert(ident2[1] == 'i');
- var bitsLeft = ident2.substr(2, ident2.length-3); // remove (i and ), to leave number
assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op');
return '((' + ident1 + ') & ' + (Math.pow(2, bitsLeft)-1) + ')';
}
diff --git a/src/parseTools.js b/src/parseTools.js
index 8b30554d..be3a6b4c 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -564,10 +564,18 @@ function correctSigns() {
}
function correctSpecificOverflow() {
- assert(!(CORRECT_SIGNS === 2 && !Debugging.on), 'Need debugging for line-specific corrections');
+ assert(!(CORRECT_OVERFLOWS === 2 && !Debugging.on), 'Need debugging for line-specific corrections');
return CORRECT_OVERFLOWS === 2 && Debugging.getIdentifier(Framework.currItem.lineNum) in CORRECT_OVERFLOWS_LINES;
}
function correctOverflows() {
return CORRECT_OVERFLOWS === 1 || correctSpecificOverflow();
}
+function correctSpecificRounding() {
+ assert(!(CORRECT_ROUNDINGS === 2 && !Debugging.on), 'Need debugging for line-specific corrections');
+ return CORRECT_ROUNDINGS === 2 && Debugging.getIdentifier(Framework.currItem.lineNum) in CORRECT_ROUNDINGS_LINES;
+}
+function correctRoundings() {
+ return CORRECT_ROUNDINGS === 1 || correctSpecificRounding();
+}
+
diff --git a/src/preamble.js b/src/preamble.js
index 92997d20..ea0c8fa4 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -118,6 +118,12 @@ 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
diff --git a/src/settings.js b/src/settings.js
index b5be8d3d..ceda7ec8 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -64,6 +64,9 @@ CORRECT_OVERFLOWS = 1; // Experimental code that tries to prevent unexpected JS
// NOTE: You can introduce signing issues by using this option. If you
// take a large enough 32-bit value, and correct it for overflows,
// you may get a negative number, as JS & operations are signed.
+CORRECT_ROUNDINGS = 1; // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that:
+ // Math.floor is to negative, ceil to positive. With CORRECT_ROUNDINGS,
+ // we will do slow but correct C rounding operations.
SHOW_LABELS = 0; // Show labels in the generated code