aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-12-06 16:07:54 -0800
committerAlon Zakai <alonzakai@gmail.com>2011-12-06 16:07:54 -0800
commit4e71da9599137a28676cd7635d57e7ad67660f35 (patch)
tree4b52f010f247d6a92806059394cabc43bccf7a15 /src
parent7a01a170be7b483a1b27010a84a4971939714899 (diff)
DOUBLE_MODE=1 option to carefuly load and store doubles even in unaligned ta2 mode. fixes test_unaligned in ta2 and default
Diffstat (limited to 'src')
-rw-r--r--src/parseTools.js20
-rw-r--r--src/preamble.js138
-rw-r--r--src/settings.js8
3 files changed, 76 insertions, 90 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 3eaf3577..86bd6bc1 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -889,7 +889,7 @@ function getHeapOffset(offset, type) {
}
// See makeSetValue
-function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
+function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) {
if (isStructType(type)) {
var typeData = Types.types[type];
var ret = [];
@@ -899,6 +899,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
return '{ ' + ret.join(', ') + ' }';
}
+ if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
+ return '(tempDoubleF32[0]=' + makeGetValue(ptr, pos, 'float', noNeedFirst, unsigned, ignore) + ',' +
+ 'tempDoubleF32[1]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('float')), 'float', noNeedFirst, unsigned, ignore) + ',' +
+ 'tempDoubleF64[0])';
+ }
+
if (EMULATE_UNALIGNED_ACCESSES && USE_TYPED_ARRAYS == 2 && align && isIntImplemented(type)) { // TODO: support unaligned doubles and floats
// Alignment is important here. May need to split this up
var bytes = Runtime.getNativeTypeSize(type);
@@ -928,7 +934,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
}
var offset = calcFastOffset(ptr, pos, noNeedFirst);
- if (SAFE_HEAP) {
+ if (SAFE_HEAP && !noSafe) {
if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"';
if (type[0] === '#') type = type.substr(1);
return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
@@ -960,7 +966,7 @@ function indexizeFunctions(value, type) {
//! 'null' means, in the context of SAFE_HEAP, that we should accept all types;
//! which means we should write to all slabs, ignore type differences if any on reads, etc.
//! @param noNeedFirst Whether to ignore the offset in the pointer itself.
-function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) {
+function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe) {
if (isStructType(type)) {
var typeData = Types.types[type];
var ret = [];
@@ -975,6 +981,12 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) {
return ret.join('; ');
}
+ if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
+ return '(tempDoubleF64[0]=' + value + ',' +
+ makeSetValue(ptr, pos, 'tempDoubleF32[0]', 'float', noNeedFirst, ignore, align/2) + ',' +
+ makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleF32[1]', 'float', noNeedFirst, ignore, align/2) + ')';
+ }
+
if (EMULATE_UNALIGNED_ACCESSES && USE_TYPED_ARRAYS == 2 && align && isIntImplemented(type)) { // TODO: support unaligned doubles and floats
// Alignment is important here. May need to split this up
var bytes = Runtime.getNativeTypeSize(type);
@@ -1003,7 +1015,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) {
value = indexizeFunctions(value, type);
var offset = calcFastOffset(ptr, pos, noNeedFirst);
- if (SAFE_HEAP) {
+ if (SAFE_HEAP && !noSafe) {
if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"';
if (type[0] === '#') type = type.substr(1);
return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + type + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
diff --git a/src/preamble.js b/src/preamble.js
index 7fd51733..ad8cce68 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -86,93 +86,52 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) {
print((new Error()).stack);
throw "Bad store!" + dest;
}
-#if USE_TYPED_ARRAYS == 1
- if (type === null) {
- IHEAP[dest] = value;
-#if USE_FHEAP
- FHEAP[dest] = value;
-#endif
- } else if (type in Runtime.FLOAT_TYPES) {
- FHEAP[dest] = value;
- } else {
- IHEAP[dest] = value;
- }
-#else
+
#if USE_TYPED_ARRAYS == 2
- assert(type != 'null', 'typed arrays 2 with null type!');
- if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
+ // Check alignment
switch(type) {
- case 'i1': case 'i8': HEAP8[dest] = value; break;
- case 'i16': assert(dest % 2 === 0, type + ' stores must be aligned: ' + dest); HEAP16[dest>>1] = value; break;
- case 'i32': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAP32[dest>>2] = value; break;
- case 'i64': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAP32[dest>>2] = value; break; // XXX store int64 as int32
- case 'float': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAPF32[dest>>2] = value; break;
- case 'double': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAPF32[dest>>2] = value; break; // XXX store doubles as floats
- default: throw 'weird type for typed array II: ' + type + new Error().stack;
- }
+ case 'i16': assert(dest % 2 == 0); break;
+ case 'i32': assert(dest % 4 == 0); break;
+ case 'i64': assert(dest % 8 == 0); break;
+ case 'float': assert(dest % 4 == 0); break;
+#if DOUBLE_MODE == 1
+ case 'double': assert(dest % 4 == 0); break;
#else
- HEAP[dest] = value;
+ case 'double': assert(dest % 4 == 0); warn64(); break;
#endif
+ default: abort('invalid type for setValue: ' + type);
+ }
#endif
+
+ setValue(dest, value, type, 1, 1);
}
function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) {
SAFE_HEAP_ACCESS(dest, type, ignore);
-#if USE_TYPED_ARRAYS == 1
- if (type in Runtime.FLOAT_TYPES) {
-#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, type, FHEAP[dest], ignore]);
-#endif
- return FHEAP[dest];
- } else {
#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, type, IHEAP[dest], ignore]);
+ print('SAFE_HEAP load: ' + [dest, type, getValue(dest, type, 1, 1), ignore]);
#endif
- return IHEAP[dest];
- }
-#else
+
#if USE_TYPED_ARRAYS == 2
-#if SAFE_HEAP_LOG
- var originalType = type;
-#endif
- var ret;
- if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
+ // Check alignment
switch(type) {
- case 'i1': case 'i8': {
- ret = (unsigned ? HEAPU8 : HEAP8)[dest];
- break;
- }
- case 'i16': {
- assert(dest % 2 === 0, type + ' loads must be aligned: ' + dest);
- ret = (unsigned ? HEAPU16 : HEAP16)[dest>>1];
- break;
- }
- case 'i32': case 'i64': { // XXX store int64 as int32
- assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest);
- if (type === 'i64') warn64();
- ret = (unsigned ? HEAPU32 : HEAP32)[dest>>2];
- break;
- }
- case 'float': case 'double': { // XXX store doubles as floats
- assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest);
- if (type === 'double') warn64();
- ret = HEAPF32[dest>>2];
- break;
- }
- default: throw 'weird type for typed array II: ' + type;
- }
-#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, originalType, ret, unsigned, ignore]);
-#endif
- return ret;
+ case 'i16': assert(dest % 2 == 0); break;
+ case 'i32': assert(dest % 4 == 0); break;
+ case 'i64': assert(dest % 8 == 0); break;
+ case 'float': assert(dest % 4 == 0); break;
+#if DOUBLE_MODE == 1
+ case 'double': assert(dest % 4 == 0); break;
#else
-#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, type, HEAP[dest], ignore]);
-#endif
- return HEAP[dest];
+ case 'double': assert(dest % 4 == 0); warn64(); break;
#endif
+ default: abort('invalid type for setValue: ' + type);
+ }
#endif
+
+ var ret = getValue(dest, type, 1, 1);
+ if (unsigned) ret = unSign(ret, parseInt(type.substr(1)));
+ return ret;
}
function SAFE_HEAP_COPY_HISTORY(dest, src) {
@@ -381,6 +340,13 @@ var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair;
#if I64_MODE == 1
var tempI64, tempI64b;
#endif
+#if DOUBLE_MODE == 1
+#if USE_TYPED_ARRAYS == 2
+var tempDoubleBuffer = new ArrayBuffer(8);
+var tempDoubleF32 = new Float32Array(tempDoubleBuffer);
+var tempDoubleF64 = new Float64Array(tempDoubleBuffer);
+#endif
+#endif
function abort(text) {
print(text + ':\n' + (new Error).stack);
@@ -400,16 +366,16 @@ function assert(condition, text) {
// code then, whereas this function picks the right code at
// run-time.
-function setValue(ptr, value, type) {
+function setValue(ptr, value, type, ignore, noSafe) {
if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit
switch(type) {
- case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1') }}}; break;
- case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8') }}}; break;
- case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16') }}}; break;
- case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32') }}}; break;
- case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64') }}}; break;
- case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float') }}}; break;
- case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double') }}}; break;
+ case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1', undefined, 'ignore', undefined, 'noSafe') }}}; break;
+ case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8', undefined, 'ignore', undefined, 'noSafe') }}}; break;
+ case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16', undefined, 'ignore', undefined, 'noSafe') }}}; break;
+ case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32', undefined, 'ignore', undefined, 'noSafe') }}}; break;
+ case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64', undefined, 'ignore', undefined, 'noSafe') }}}; break;
+ case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float', undefined, 'ignore', undefined, 'noSafe') }}}; break;
+ case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double', undefined, 'ignore', undefined, 'noSafe') }}}; break;
default: abort('invalid type for setValue: ' + type);
}
}
@@ -417,16 +383,16 @@ Module['setValue'] = setValue;
// Parallel to setValue.
-function getValue(ptr, type) {
+function getValue(ptr, type, ignore, noSafe) {
if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit
switch(type) {
- case 'i1': return {{{ makeGetValue('ptr', '0', 'i1') }}};
- case 'i8': return {{{ makeGetValue('ptr', '0', 'i8') }}};
- case 'i16': return {{{ makeGetValue('ptr', '0', 'i16') }}};
- case 'i32': return {{{ makeGetValue('ptr', '0', 'i32') }}};
- case 'i64': return {{{ makeGetValue('ptr', '0', 'i64') }}};
- case 'float': return {{{ makeGetValue('ptr', '0', 'float') }}};
- case 'double': return {{{ makeGetValue('ptr', '0', 'double') }}};
+ case 'i1': return {{{ makeGetValue('ptr', '0', 'i1', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
+ case 'i8': return {{{ makeGetValue('ptr', '0', 'i8', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
+ case 'i16': return {{{ makeGetValue('ptr', '0', 'i16', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
+ case 'i32': return {{{ makeGetValue('ptr', '0', 'i32', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
+ case 'i64': return {{{ makeGetValue('ptr', '0', 'i64', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
+ case 'float': return {{{ makeGetValue('ptr', '0', 'float', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
+ case 'double': return {{{ makeGetValue('ptr', '0', 'double', undefined, undefined, 'ignore', undefined, 'noSafe') }}};
default: abort('invalid type for setValue: ' + type);
}
return null;
diff --git a/src/settings.js b/src/settings.js
index da39cbee..2d645a12 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -57,6 +57,14 @@ var I64_MODE = 1; // How to implement 64-bit integers:
// use doubles for addition etc., like mode 0. This mode is slower than
// mode 0, so its only benefit is proper support for 64 bit bitops.
// TODO: Full bignum support
+var DOUBLE_MODE = 1; // How to load and store 64-bit doubles. Without typed arrays or in typed array mode 1,
+ // this doesn't matter - these values are just values like any other. In typed array mode 2,
+ // a potentialy risk is that doubles may be only 32-bit aligned. Forcing 64-bit alignment
+ // in Clang itself should be able to solve that, or as a workaround in DOUBLE_MODE 1 we
+ // will carefully load in parts, in a way that requires only 32-bit alignment. In DOUBLE_MODE
+ // 0 we will simply store and load doubles as 32-bit floats, so when they are stored/loaded
+ // they will truncate from 64 to 32 bits, and lose precision. This is faster, and might
+ // work for some code (but probably that code should just use floats and not doubles anyhow).
var EMULATE_UNALIGNED_ACCESSES = 1; // If set, the compiler will 'emulate' loads and stores that are not known to
// be sufficiently aligned, by working on individual bytes. This can be
// important in USE_TYPED_ARRAYS == 2, where unaligned accesses do not work,