diff options
-rw-r--r-- | src/parseTools.js | 37 | ||||
-rw-r--r-- | src/runtime.js | 35 | ||||
-rwxr-xr-x | tests/runner.py | 18 |
3 files changed, 77 insertions, 13 deletions
diff --git a/src/parseTools.js b/src/parseTools.js index a53ff1c0..815d1a1b 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1616,7 +1616,9 @@ function processMathop(item) { case 'shl': case 'ashr': case 'lshr': { - assert(isNumber(ident2)); + if (!isNumber(ident2)) { + return 'Runtime.bitshift64(' + ident1 + ',"' + op + '",' + stripCorrections(ident2) + '[0]|0)'; + } bits = parseInt(ident2); var ander = Math.pow(2, bits)-1; if (bits < 32) { @@ -1892,17 +1894,28 @@ function finalizeBlockAddress(param) { function stripCorrections(param) { var m; - if (m = /^\((.*)\)$/.exec(param)) { - param = m[1]; - } - if (m = /^\((\w+)\)&\d+$/.exec(param)) { - param = m[1]; - } - if (m = /^\((\w+)\)\|0$/.exec(param)) { - param = m[1]; - } - if (m = /CHECK_OVERFLOW\(([^,)]*),.*/.exec(param)) { - param = m[1]; + while (true) { + if (m = /^\((.*)\)$/.exec(param)) { + param = m[1]; + continue; + } + if (m = /^\(([$_\w]+)\)&\d+$/.exec(param)) { + param = m[1]; + continue; + } + if (m = /^\(([$_\w()]+)\)\|0$/.exec(param)) { + param = m[1]; + continue; + } + if (m = /^\(([$_\w()]+)\)\>>>0$/.exec(param)) { + param = m[1]; + continue; + } + if (m = /CHECK_OVERFLOW\(([^,)]*),.*/.exec(param)) { + param = m[1]; + continue; + } + break; } return param; } diff --git a/src/runtime.js b/src/runtime.js index 8e5238da..39aed12c 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -118,6 +118,41 @@ var Runtime = { INT_TYPES: set('i1', 'i8', 'i16', 'i32', 'i64'), FLOAT_TYPES: set('float', 'double'), + // Mirrors processMathop's treatment of constants (which we optimize directly) + bitshift64: function(value, op, bits) { + var ander = Math.pow(2, bits)-1; + if (bits < 32) { + switch (op) { + case 'shl': + return [value[0] << bits, (value[1] << bits) | ((value[0]&(ander << (32 - bits))) >>> (32 - bits))]; + case 'ashr': + return [(((value[0] >>> bits ) | ((value[1]&ander) << (32 - bits))) >> 0) >>> 0, (value[1] >> bits) >>> 0]; + case 'lshr': + return [((value[0] >>> bits) | ((value[1]&ander) << (32 - bits))) >>> 0, value[1] >>> bits]; + } + } else if (bits == 32) { + switch (op) { + case 'shl': + return [0, value[0]]; + case 'ashr': + return [value[1], (value[1]|0) < 0 ? ander : 0]; + case 'lshr': + return [value[1], 0]; + } + } else { // bits > 32 + switch (op) { + case 'shl': + return [0, value[0] << (bits - 32)]; + case 'ashr': + return [(value[1] >> (bits - 32)) >>> 0, (value[1]|0) < 0 ? ander : 0]; + case 'lshr': + return [value[1] >>> (bits - 32) , 0]; + } + } + abort('unknown bitshift64 op: ' + [value, op, bits]); + }, + + // Imprecise bitops utilities or64: function(x, y) { var l = (x | 0) | (y | 0); var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296; diff --git a/tests/runner.py b/tests/runner.py index 2a0307e9..55d0bd0b 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -496,7 +496,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): { 122, 25769803837 }, }; - int main() + int main(int argc, char **argv) { int64_t x1 = 0x1234def123450789ULL; int64_t x2 = 0x1234def123450788ULL; @@ -533,6 +533,20 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud); } + // Nonconstant bitshifts + { + int64_t a = -1; + int64_t b = a >> (29 - argc + 1); + int64_t c = a >> (32 - argc + 1); + int64_t d = a >> (34 - argc + 1); + printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d); + uint64_t ua = -1; + int64_t ub = ua >> (29 - argc + 1); + int64_t uc = ua >> (32 - argc + 1); + int64_t ud = ua >> (34 - argc + 1); + printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud); + } + // Math mixtures with doubles { uint64_t a = 5; @@ -565,6 +579,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): '*122,25769803837*\n' + '*-1,-1,-1,-1*\n' + '*-1,34359738367,4294967295,1073741823*\n' + + '*-1,-1,-1,-1*\n' + + '*-1,34359738367,4294967295,1073741823*\n' + '*prod:34*') Settings.CORRECT_SIGNS = 1 |