diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-12-06 16:07:54 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-12-06 16:07:54 -0800 |
commit | 4e71da9599137a28676cd7635d57e7ad67660f35 (patch) | |
tree | 4b52f010f247d6a92806059394cabc43bccf7a15 /src | |
parent | 7a01a170be7b483a1b27010a84a4971939714899 (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.js | 20 | ||||
-rw-r--r-- | src/preamble.js | 138 | ||||
-rw-r--r-- | src/settings.js | 8 |
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, |