aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-11-09 17:48:15 -0800
committerAlon Zakai <alonzakai@gmail.com>2011-11-09 17:48:15 -0800
commit35ee8e8ec0e5583faec00ade5f1c2bd24c19672b (patch)
tree4ad27edc11a3866bcaed14f6390b88c0a3e6f044
parentc5e70d1abcaa7779c3a8692d77745b3d3da9e3b4 (diff)
initial work on i64
-rw-r--r--src/analyzer.js2
-rw-r--r--src/jsifier.js4
-rw-r--r--src/library.js4
-rw-r--r--src/parseTools.js76
-rw-r--r--src/settings.js6
-rw-r--r--tests/runner.py59
-rw-r--r--tools/shared.py2
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: