diff options
-rw-r--r-- | src/analyzer.js | 2 | ||||
-rw-r--r-- | src/jsifier.js | 4 | ||||
-rw-r--r-- | src/library.js | 4 | ||||
-rw-r--r-- | src/parseTools.js | 76 | ||||
-rw-r--r-- | src/settings.js | 6 | ||||
-rw-r--r-- | tests/runner.py | 59 | ||||
-rw-r--r-- | tools/shared.py | 2 |
7 files changed, 121 insertions, 32 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index d0510e6e..366e2e02 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -361,6 +361,8 @@ function analyzer(data) { variable.impl = VAR_EMULATED; } else if (variable.origin == 'funcparam') { variable.impl = VAR_EMULATED; + } else if (variable.type == 'i64*' && I64_MODE == 1) { + variable.impl = VAR_EMULATED; } else if (OPTIMIZE && variable.pointingLevels === 0 && !variable.hasAddrTaken) { // A simple int value, can be implemented as a native variable variable.impl = VAR_NATIVE; diff --git a/src/jsifier.js b/src/jsifier.js index 021572f3..64fe5e4a 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) + ';'; } else { - return makeSetValue(0, finalizeLLVMParameter(item.pointer), value, item.valueType); + return makeSetValue(0, finalizeLLVMParameter(item.pointer), value, item.valueType) + ';'; } break; default: diff --git a/src/library.js b/src/library.js index 73caa37c..cb6a2ea3 100644 --- a/src/library.js +++ b/src/library.js @@ -706,8 +706,8 @@ LibraryManager.library = { mode = obj.link === undefined ? 0x8000 : 0xA000; // S_IFREG, S_IFLNK. } } - {{{ makeSetValue('buf', 'offsets.st_dev', 'dev', 'i64') }}} - {{{ makeSetValue('buf', 'offsets.st_rdev', 'rdev', 'i64') }}} + {{{ makeSetValue('buf', 'offsets.st_dev', makeI64('dev'), 'i64') }}} + {{{ makeSetValue('buf', 'offsets.st_rdev', makeI64('rdev'), 'i64') }}} // NOTE: These two may be i64, depending on compilation options. {{{ makeSetValue('buf', 'offsets.st_size', 'size', 'i32') }}} {{{ makeSetValue('buf', 'offsets.st_blocks', 'blocks', 'i32') }}} diff --git a/src/parseTools.js b/src/parseTools.js index 567e0ce1..89aab8d9 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -526,11 +526,64 @@ function IEEEUnHex(stringy) { return (absolute * (neg ? -1 : 1)).toString(); } +function parseI64Constant(v) { + assert(I64_MODE == 1); + + if (!isNumber(v)) { + // This is a variable. Copy it, so we do not modify the original + return v + '.slice(0)'; + } + + function getDigit(i) { + return v.charCodeAt(i) - '0'.charCodeAt(0); + } + function setDigit(i, d) { + v = v.substr(0, i) + String.fromCharCode(d + '0'.charCodeAt(0)) + v.substr(i+1); + } + function divide2() { + for (var i = v.length-1; i >= 0; i--) { + var d = getDigit(i); + var r = d % 2; + d = Math.floor(d/2); + setDigit(i, d); + if (r) { + assert(i+1 < v.length); + var d2 = getDigit(i+1); + d2 += 5; + if (d2 >= 10) { + setDigit(i, d+1); + d2 -= 10; + } + setDigit(i+1, d2); + } + } + } + + var bits = []; + while (!v.match(/^0+$/)) { + bits.push((getDigit(v.length-1) % 2 != 0)+0); + setDigit(v.length-1, getDigit(v.length-1) & 0xfe); + divide2(); + } + + var low = 0, high = 0; + for (var i = 0; i < bits.length; i++) { + if (i <= 31) { + low += bits[i]*Math.pow(2, i); + } else { + high += bits[i]*Math.pow(2, i-32); + } + } + return '[' + low + ',' + high + ']'; +} + function parseNumerical(value, type) { if ((!type || type == 'double' || type == 'float') && (value.substr && value.substr(0,2) == '0x')) { // Hexadecimal double value, as the llvm docs say, // "The one non-intuitive notation for constants is the hexadecimal form of floating point constants." value = IEEEUnHex(value); + } else if (type == 'i64' && I64_MODE == 1) { + value = parseI64Constant(value); } else if (value == 'null') { // NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.) value = '0'; @@ -715,6 +768,15 @@ function checkSafeHeap() { return SAFE_HEAP === 1 || checkSpecificSafeHeap(); } +// Makes a proper runtime value for a 64-bit value. Used in library. +function makeI64(low, high) { + if (I64_MODE == 1) { + return '[' + low + ',' + (high || '0') + ']'; + } else { + assert(!high); + return low; + } +} function getHeapOffset(offset, type) { if (USE_TYPED_ARRAYS !== 2) { @@ -743,6 +805,11 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore) { return '{ ' + ret.join(', ') + ' }'; } + if (type == 'i64' && I64_MODE == 1) { + return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore) + ',' + + makeGetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore) + ']'; + } + var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; @@ -791,14 +858,19 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore) { return ret.join('; '); } + 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) + ')'; + } + value = indexizeFunctions(value, type); var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { 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) + ');'; + return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + type + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; } else { - return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type) + ']=' + value }).join('; ') + ';'; + return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type) + ']=' + value }).join('; '); } } diff --git a/src/settings.js b/src/settings.js index 17f3f5e8..c5894b87 100644 --- a/src/settings.js +++ b/src/settings.js @@ -50,6 +50,12 @@ USE_TYPED_ARRAYS = 0; // Try to use typed arrays for the heap // TODO: require compiling with -malign-double, which does align doubles USE_FHEAP = 1; // Relevant in USE_TYPED_ARRAYS == 1. If this is disabled, only IHEAP will be used, and FHEAP // not generated at all. This is useful if your code is 100% ints without floats or doubles +I64_MODE = 0; // How to implement 64-bit integers: + // 0: As doubles. This will work up to about 53 bits. + // 1: As [low, high]. This will support all 64 bits for bit ops, etc., but not full math. + // TODO: reuse these arrays/escape analysis to avoid GC + // 2: Full bignum support. TODO + 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 // may allocate stack later, and in a loop, this can be diff --git a/tests/runner.py b/tests/runner.py index 95fe03c4..88462c58 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -31,7 +31,7 @@ except: # Core test runner class, shared between normal tests and benchmarks class RunnerCore(unittest.TestCase): - save_dir = 0 + save_dir = 1 save_JS = 0 def setUp(self): @@ -364,29 +364,34 @@ if 'benchmark' not in str(sys.argv): Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right self.do_run(src, output, force_c=True) - def test_bigint(self): - if Settings.USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64') - src = ''' - #include <stdio.h> - int main() - { - long long x = 0x0000def123450789ULL; // any bigger than this, and we - long long y = 0x00020ef123456089ULL; // start to run into the double precision limit! - printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2); - - printf("*"); - long long z = 13; - int n = 0; - while (z > 1) { - printf("%.2f,", (float)z); // these must be integers! - z = z >> 1; - n++; + def test_i64(self): + for i64_mode in [1]: # XXX add 0 + if i64_mode == 0 and Settings.USE_TYPED_ARRAYS != 0: continue # Typed arrays truncate i64' + Settings.I64_MODE = i64_mode + src = ''' + #include <stdio.h> + int main() + { + long long x = 0x0000def123450789ULL; // any bigger than this, and we + long long y = 0x00020ef123456089ULL; // start to run into the double precision limit! + printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2); + + printf("*"); + long long z = 13; + int n = 0; + while (z > 1) { + printf("%.2f,", (float)z); // these must be integers! + z = z >> 1; + n++; + } + printf("*%d*\\n", n); + return 0; } - printf("*%d*\\n", n); - return 0; - } - ''' - self.do_run(src, '*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*') + ''' + self.do_run(src, '*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*') + + # Stuff that only works in i64_mode = 1 + # TODO def test_unsigned(self): Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here @@ -1511,6 +1516,9 @@ if 'benchmark' not in str(sys.argv): self.do_run(src, '*96,97,98,101,101*') def test_indirectbr(self): + if Settings.USE_TYPED_ARRAYS == 2: + Settings.I64_MODE = 1 # Unsafe optimizations use 64-bit load/store on two i32s + src = ''' #include <stdio.h> int main(void) { @@ -3110,7 +3118,6 @@ if 'benchmark' not in str(sys.argv): Settings.CHECK_OVERFLOWS = 0 self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp') - #build_ll_hook=self.do_autodebug) def test_gcc_unmangler(self): self.do_run(path_from_root('third_party'), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c') @@ -4226,12 +4233,13 @@ class %s(T): Settings.DISABLE_EXCEPTION_CATCHING = 0 Settings.PROFILE = 0 Settings.TOTAL_MEMORY = Settings.FAST_MEMORY = None + Settings.I64_MODE = 1 # XXX if Settings.QUANTUM_SIZE == 1 or Settings.USE_TYPED_ARRAYS == 2: Settings.RELOOP = 0 # XXX Would be better to use this, but it isn't really what we test in these cases, and is very slow if Building.LLVM_OPTS: - self.pick_llvm_opts(3) + self.pick_llvm_opts(3) #, handpicked=Settings.USE_TYPED_ARRAYS != 2) Building.COMPILER_TEST_OPTS = ['-g'] @@ -4302,6 +4310,7 @@ else: Settings.QUANTUM_SIZE = 1 Settings.RELOOP = Settings.OPTIMIZE = 1 Settings.USE_TYPED_ARRAYS = 1 + Settings.I64_MODE = 0 Settings.ASSERTIONS = Settings.SAFE_HEAP = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.INIT_STACK = Settings.AUTO_OPTIMIZE = Settings.RUNTIME_TYPE_INFO = 0 Settings.INVOKE_RUN = 1 Settings.CORRECT_SIGNS = 0 diff --git a/tools/shared.py b/tools/shared.py index d5629b50..fe2c50c6 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -319,7 +319,7 @@ class Building: # Run Emscripten exported_settings = {} - for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTION_CATCHING', 'TOTAL_MEMORY', 'FAST_MEMORY', 'EXCEPTION_DEBUG', 'PROFILE']: + for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTION_CATCHING', 'TOTAL_MEMORY', 'FAST_MEMORY', 'EXCEPTION_DEBUG', 'PROFILE', 'I64_MODE']: try: value = eval('Settings.' + setting) if value is not None: |