diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-11-16 12:49:07 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-11-16 12:49:07 -0800 |
commit | f240c68de7fc6399af7b7ea08a42d9ee7c8d2748 (patch) | |
tree | 696507c4fe88bd65f0ef3f0cdd58c00e43a5acb9 /src | |
parent | 1e3a60f206041ec004ef9755a673103c62e3c213 (diff) |
initial support for unaligned reads/writes in t2
Diffstat (limited to 'src')
-rw-r--r-- | src/intertyper.js | 15 | ||||
-rw-r--r-- | src/jsifier.js | 6 | ||||
-rw-r--r-- | src/parseTools.js | 70 | ||||
-rw-r--r-- | src/preamble.js | 4 | ||||
-rw-r--r-- | src/settings.js | 7 |
5 files changed, 88 insertions, 14 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 30fd7250..c1b9b78e 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -546,7 +546,14 @@ function intertyper(data, parseFunctions, baseLineNum) { item.valueType = item.type = removePointing(item.pointerType); Types.needAnalysis[item.type] = 0; var last = getTokenIndexByText(item.tokens, ';'); - item.pointer = parseLLVMSegment(item.tokens.slice(1, last)); // TODO: Use this everywhere else too + var segments = splitTokenList(item.tokens.slice(1, last)); + item.pointer = parseLLVMSegment(segments[0]); + if (segments.length > 1) { + assert(segments[1][0].text == 'align'); + item.align = parseInt(segments[1][1].text) || QUANTUM_SIZE; // 0 means preferred arch align + } else { + item.align = QUANTUM_SIZE; + } item.ident = item.pointer.ident || null; this.forwardItem(item, 'Reintegrator'); } @@ -792,6 +799,12 @@ function intertyper(data, parseFunctions, baseLineNum) { ret.ident = toNiceIdent(ret.pointer.ident); ret.pointerType = ret.pointer.type; Types.needAnalysis[ret.pointerType] = 0; + if (segments.length > 2) { + assert(segments[2][0].text == 'align'); + ret.align = parseInt(segments[2][1].text) || QUANTUM_SIZE; // 0 means preferred arch align + } else { + ret.align = QUANTUM_SIZE; + } return [ret]; } }); diff --git a/src/jsifier.js b/src/jsifier.js index adf465ed..5f75b374 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -645,9 +645,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { break; case VAR_EMULATED: if (item.pointer.intertype == 'value') { - return makeSetValue(item.ident, 0, value, item.valueType) + ';'; + return makeSetValue(item.ident, 0, value, item.valueType, 0, 0, item.align) + ';'; } else { - return makeSetValue(0, finalizeLLVMParameter(item.pointer), value, item.valueType) + ';'; + return makeSetValue(0, finalizeLLVMParameter(item.pointer), value, item.valueType, 0, 0, item.align) + ';'; } break; default: @@ -784,7 +784,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { case VAR_NATIVIZED: { return value; // We have the actual value here } - case VAR_EMULATED: return makeGetValue(value, 0, item.type, 0, item.unsigned); + case VAR_EMULATED: return makeGetValue(value, 0, item.type, 0, item.unsigned, 0, item.align); default: throw "unknown [load] impl: " + impl; } }); diff --git a/src/parseTools.js b/src/parseTools.js index dc6f597b..423ed0cb 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -531,8 +531,11 @@ function makeI64(low, high) { return '[' + low + ',' + (high || '0') + ']'; // FIXME with this? return '[unSign(' + low + ',32),' + (high ? ('unSign(' + high + ',32)') : '0') + ']'; } else { - assert(!high); - return low; + var ret = low; + if (high) { + ret = '(' + low + '+(4294967296*' + high + '))'; + } + return ret; } } @@ -540,13 +543,20 @@ function makeI64(low, high) { // Will suffer from rounding. margeI64 does the opposite. function splitI64(value) { assert(I64_MODE == 1); - return '(tempInt=' + value + ',' + makeI64('tempInt|0', 'Math.floor(tempInt/4294967296)') + ')'; + return '(tempInt=' + value + ',' + makeI64('tempInt>>>0', 'Math.floor(tempInt/4294967296)') + ')'; } function mergeI64(value) { assert(I64_MODE == 1); return '(tempI64=' + value + ',tempI64[0]+tempI64[1]*4294967296)'; } +// Takes an i64 value and changes it into the [low, high] form used in i64 mode 1. In that +// mode, this is a no-op +function ensureI64_1(value) { + if (I64_MODE == 1) return value; + return '(tempInt=' + value + ',[tempInt>>>0, Math.floor(tempInt/4294967296)])'; +} + function makeCopyI64(value) { assert(I64_MODE == 1); @@ -687,7 +697,7 @@ function getLabelIds(labels) { return labels.map(function(label) { return label.ident }); } -//! Returns the size of a type, as C/C++ would have it (in 32-bit, for now). +//! Returns the size of a type, as C/C++ would have it (in 32-bit, for now), in bytes. //! @param type The type, by name. function getNativeTypeSize(type) { if (QUANTUM_SIZE == 1) return 1; @@ -851,7 +861,7 @@ function getHeapOffset(offset, type) { } // See makeSetValue -function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore) { +function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { if (isStructType(type)) { var typeData = Types.types[type]; var ret = []; @@ -861,6 +871,29 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore) { return '{ ' + ret.join(', ') + ' }'; } + 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 = getNativeTypeSize(type); + if (bytes > align) { + var ret = '/* unaligned */('; + if (bytes <= 4) { + for (var i = 0; i < bytes; i++) { + ret += 'tempInt' + (i == 0 ? '=' : (i < bytes-1 ? '+=((' : '+((')); + ret += makeSignOp(makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, unsigned, ignore), 'i8', 'un', true); + if (i > 0) ret += ')<<' + (8*i) + ')'; + if (i < bytes-1) ret += ','; + } + } else { + assert(bytes == 8); + ret += 'tempBigInt=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, true, ignore, align) + ','; + ret += 'tempBigInt2=' + makeGetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'i32', noNeedFirst, true, ignore, align) + ','; + ret += makeI64('tempBigInt', 'tempBigInt2'); + } + ret += ')'; + return ret; + } + } + if (type == 'i64' && I64_MODE == 1) { return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore) + ',' + makeGetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore) + ']'; @@ -899,7 +932,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) { +function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) { if (isStructType(type)) { var typeData = Types.types[type]; var ret = []; @@ -914,6 +947,27 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore) { return ret.join('; '); } + 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 = getNativeTypeSize(type); + if (bytes > align) { + var ret = '/* unaligned */'; + if (bytes <= 4) { + ret += 'tempInt=' + value + ';'; + for (var i = 0; i < bytes; i++) { + ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempInt&0xff', 'i8', noNeedFirst, ignore) + ';'; + if (i < bytes-1) ret += 'tempInt>>=8;'; + } + } else { + assert(bytes == 8); + ret += 'tempPair=' + ensureI64_1(value) + ';'; + ret += makeSetValue(ptr, pos, 'tempPair[0]', 'i32', noNeedFirst, ignore, align) + ';'; + ret += makeSetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'tempPair[1]', 'i32', noNeedFirst, ignore, align) + ';'; + } + return ret; + } + } + if (type == 'i64' && I64_MODE == 1) { return '(' + makeSetValue(ptr, pos, value + '[0]', 'i32', noNeedFirst, ignore) + ',' + makeSetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), value + '[1]', 'i32', noNeedFirst, ignore) + ')'; @@ -1338,7 +1392,7 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) { return ret; } -function makeSignOp(value, type, op) { +function makeSignOp(value, type, op, force) { if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints if (!value) return value; var bits, full; @@ -1352,7 +1406,7 @@ function makeSignOp(value, type, op) { return eval(full).toString(); } } - if (!correctSigns() && !CHECK_SIGNS) return value; + if (!correctSigns() && !CHECK_SIGNS && !force) return value; if (type in Runtime.INT_TYPES) { // shortcuts if (!CHECK_SIGNS) { diff --git a/src/preamble.js b/src/preamble.js index 7aa07cc1..4bdb4333 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -66,7 +66,7 @@ var warned64 = false; function warn64() { if (!warned64) { __ATEXIT__.push({ func: function() { - print('Warning: using a 64-bit type with USE_TYPED_ARRAYS == 2. This is emulated as a 32-bit value, and will likely fail horribly.'); + print('Warning: using a 64-bit type with USE_TYPED_ARRAYS == 2. Depending on I64_MODE this may be problematic.'); } }); warned64 = true; } @@ -381,7 +381,7 @@ var __ATEXIT__ = []; var ABORT = false; var undef = 0; -var tempValue, tempInt, tempBigInt; +var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair; #if I64_MODE == 1 var tempI64, tempI64b; #endif diff --git a/src/settings.js b/src/settings.js index 092822e9..7e076288 100644 --- a/src/settings.js +++ b/src/settings.js @@ -56,6 +56,13 @@ I64_MODE = 0; // 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 +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, + // specifically in the case where unsafe LLVM optimizations have generated possibly + // unaligned code. (Without unsafe LLVM optimizations, there should be no + // need for this option.) + // Currently this only works for integers, not doubles and floats. SKIP_STACK_IN_SMALL = 1; // When enabled, does not push/pop the stack at all in // functions that have no basic stack usage. But, they |