From 3974e99db9779fa9d438acaa6fbea2589dbbb926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 21 Oct 2014 02:25:36 +0300 Subject: [PATCH 01/11] Add musl fenv.c needed by musl math functions. --- system/lib/libc.symbols | 7 +++++ system/lib/libc/musl/src/fenv/fenv.c | 38 ++++++++++++++++++++++++++++ tools/system_libs.py | 3 +++ 3 files changed, 48 insertions(+) create mode 100644 system/lib/libc/musl/src/fenv/fenv.c diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols index e47df094945b7..6254c69e42e11 100644 --- a/system/lib/libc.symbols +++ b/system/lib/libc.symbols @@ -46,6 +46,13 @@ T expm1 T expm1f T expm1l + T feclearexcept + T feraiseexcept + T fetestexcept + T fegetround + T __fesetround + T fegetenv + T fesetenv T fdim T fdimf T fdiml diff --git a/system/lib/libc/musl/src/fenv/fenv.c b/system/lib/libc/musl/src/fenv/fenv.c new file mode 100644 index 0000000000000..5588dad95f428 --- /dev/null +++ b/system/lib/libc/musl/src/fenv/fenv.c @@ -0,0 +1,38 @@ +#include + +/* Dummy functions for archs lacking fenv implementation */ + +int feclearexcept(int mask) +{ + return 0; +} + +int feraiseexcept(int mask) +{ + return 0; +} + +int fetestexcept(int mask) +{ + return 0; +} + +int fegetround(void) +{ + return FE_TONEAREST; +} + +int __fesetround(int r) +{ + return 0; +} + +int fegetenv(fenv_t *envp) +{ + return 0; +} + +int fesetenv(const fenv_t *envp) +{ + return 0; +} diff --git a/tools/system_libs.py b/tools/system_libs.py index 2b5e30f193b17..ca2a6d7ed1608 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -98,6 +98,9 @@ def create_libc(): 'isxdigit.c', 'tolower.c', ]], + ['fenv', [ + 'fenv.c' + ]], ['internal', [ 'intscan.c', 'floatscan.c', From b7f8cd22b855626bdbeb1b87d43d6c4ac51a4650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 21 Oct 2014 03:24:21 +0300 Subject: [PATCH 02/11] Add symbol __fpclassifyd as an alias to __fpclassify to satisfy test_python. --- src/library.js | 2 -- system/lib/libc/musl/src/math/__fpclassify.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 58fb51a4b2755..6a90ec4cfa28a 100644 --- a/src/library.js +++ b/src/library.js @@ -4531,8 +4531,6 @@ LibraryManager.library = { return divt; }, - __fpclassifyd: '__fpclassify', // Needed by tests/python/python.le32.bc - // ========================================================================== // sys/utsname.h // ========================================================================== diff --git a/system/lib/libc/musl/src/math/__fpclassify.c b/system/lib/libc/musl/src/math/__fpclassify.c index f7c0e2dfac828..13866746f52f2 100644 --- a/system/lib/libc/musl/src/math/__fpclassify.c +++ b/system/lib/libc/musl/src/math/__fpclassify.c @@ -1,6 +1,11 @@ #include #include +#ifdef __EMSCRIPTEN__ +// XXX Emscripten: for weak_alias. +#include "libc.h" +#endif + int __fpclassify(double x) { union {double f; uint64_t i;} u = {x}; @@ -9,3 +14,8 @@ int __fpclassify(double x) if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; return FP_NORMAL; } + +#ifdef __EMSCRIPTEN__ +// XXX Emscripten: Needed by tests/python/python.le32.bc +weak_alias(__fpclassify, __fpclassifyd); +#endif From f7651f8d792b3f3601272e2d96f1db515c2f5a7b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 13:08:05 -0800 Subject: [PATCH 03/11] update cashew --- tools/optimizer/simple_ast.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 25cd1cc682b8a..b757c1a267d9e 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -943,8 +943,10 @@ struct JSPrinter { if (finalize && node[1] == PLUS && (node[2][0] == NUM || (node[2][0] == UNARY_PREFIX && node[2][1] == MINUS && node[2][2][0] == NUM))) { // emit a finalized number - char *curr = buffer + used; + int last = used; print(node[2]); + ensure(1); // we temporarily append a 0 + char *curr = buffer + last; // ensure might invalidate buffer[used] = 0; if (strchr(curr, '.')) return; // already a decimal point, all good char *e = strchr(curr, 'e'); @@ -953,6 +955,7 @@ struct JSPrinter { return; } ensure(3); + curr = buffer + last; // ensure might invalidate char *end = strchr(curr, 0); while (end >= e) { end[2] = end[0]; From b7967e63f6e0d474117fc7e109f9c54d37ef7320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 17 Dec 2014 07:17:31 +0200 Subject: [PATCH 04/11] Fix up sincos, sincosf and sincosl to call to browser sin and cos functions to fix missing symbols in libc build, and to give better performance than the musl provided ones. --- system/lib/libc/musl/src/math/sincos.c | 11 +++++++++++ system/lib/libc/musl/src/math/sincosf.c | 10 ++++++++++ system/lib/libc/musl/src/math/sincosl.c | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/system/lib/libc/musl/src/math/sincos.c b/system/lib/libc/musl/src/math/sincos.c index 35b2d923968f1..6cfb9950418c0 100644 --- a/system/lib/libc/musl/src/math/sincos.c +++ b/system/lib/libc/musl/src/math/sincos.c @@ -13,6 +13,16 @@ #define _GNU_SOURCE #include "libm.h" +#ifdef __EMSCRIPTEN__ +#include + +// XXX Emscripten: Use the browser-optimized versions of sin and cos, since they are faster. +void sincos(double x, double *s, double *c) +{ + *s = sin(x); + *c = cos(x); +} +#else void sincos(double x, double *sin, double *cos) { double y[2], s, c; @@ -67,3 +77,4 @@ void sincos(double x, double *sin, double *cos) break; } } +#endif diff --git a/system/lib/libc/musl/src/math/sincosf.c b/system/lib/libc/musl/src/math/sincosf.c index f8ca7232cfb37..1d059de5f84bd 100644 --- a/system/lib/libc/musl/src/math/sincosf.c +++ b/system/lib/libc/musl/src/math/sincosf.c @@ -17,6 +17,10 @@ #define _GNU_SOURCE #include "libm.h" +#ifdef __EMSCRIPTEN__ +#include +#endif + /* Small multiples of pi/2 rounded to double precision. */ static const double s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ @@ -26,6 +30,11 @@ s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ void sincosf(float x, float *sin, float *cos) { +#ifdef __EMSCRIPTEN__ +// XXX Emscripten: Use the browser-optimized versions of sin and cos, since they are faster. + *sin = sinf(x); + *cos = cosf(x); +#else double y; float_t s, c; uint32_t ix; @@ -114,4 +123,5 @@ void sincosf(float x, float *sin, float *cos) *cos = s; break; } +#endif } diff --git a/system/lib/libc/musl/src/math/sincosl.c b/system/lib/libc/musl/src/math/sincosl.c index d3ac1c4c8c29e..3113e136cbf03 100644 --- a/system/lib/libc/musl/src/math/sincosl.c +++ b/system/lib/libc/musl/src/math/sincosl.c @@ -1,6 +1,18 @@ #define _GNU_SOURCE #include "libm.h" +#ifdef __EMSCRIPTEN__ +#include + +// XXX Emscripten: Use the browser-optimized versions of sin and cos, since they are faster. +void sincosl(long double x, long double *sin, long double *cos) +{ + *sin = sinl(x); + *cos = cosl(x); +} + +#else + #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 void sincosl(long double x, long double *sin, long double *cos) { @@ -58,3 +70,5 @@ void sincosl(long double x, long double *sin, long double *cos) } } #endif + +#endif From 696a0a560f7b6b9b542abb66dafeb888bcb0c23f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 15:05:53 -0800 Subject: [PATCH 05/11] make other.test_js_optimizer:registerizeHarder invariant to reorderings of sensitive variables --- tests/test_other.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index bd2598a368fdd..9b4313b8fd090 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1943,16 +1943,38 @@ def test_js_optimizer(self): print ' js' output = Popen(NODE_JS + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] - def check_js(js): + def check_js(js, expected): + if 'registerizeHarder' in passes: + # registerizeHarder is hard to test, as names vary by chance, nondeterminstically FIXME + def fix(src): + if type(src) is list: + return map(fix, src) + src = '\n'.join(filter(lambda line: 'var ' not in line, src.split('\n'))) # ignore vars + def reorder(func): + # emit EYE_ONE always before EYE_TWO, replaceing i1,i2 or i2,i1 + i1 = 'i1' + i2 = 'i2' + if i1 not in func or i2 not in func: return func + ok = func.index(i1) < func.index(i2) + if not ok: + i1 = 'i2' + i2 = 'i1' + func = func.replace(i1, 'EYE_ONE').replace(i2, 'EYE_TWO') + assert func.index('EYE_ONE') < func.index('EYE_TWO') + return func + src = 'function '.join(map(reorder, src.split('function '))) + return src + js = fix(js) + expected = fix(expected) self.assertIdentical(expected, js.replace('\r\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')) - check_js(output) + check_js(output, expected) if js_optimizer.use_native(passes): # test calling native def check_json(): Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), output_temp, 'receiveJSON'], stdin=PIPE, stdout=open(output_temp + '.js', 'w')).communicate() output = open(output_temp + '.js').read() - self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')) + check_js(output, expected) self.clear() input_temp = 'temp.js' @@ -1976,7 +1998,7 @@ def check_json(): print ' native (emitting JS)' output = Popen([js_optimizer.get_native_optimizer(), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] - check_js(output) + check_js(output, expected) def test_m_mm(self): open(os.path.join(self.get_dir(), 'foo.c'), 'w').write('''#include ''') From 0ba75bbb6b391ae268861e23681d5c8b98140eb1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 11:31:11 -0800 Subject: [PATCH 06/11] enable native optimizer by default --- tests/test_sanity.py | 64 ++++++++++++++++++++----------------------- tools/js_optimizer.py | 4 +-- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 02c0954bed90d..485a4a4af8b4e 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -619,7 +619,6 @@ def second_use(): def test_native_optimizer(self): restore() - Cache.erase() def build(): return self.check_working([EMCC, '-O2', 'tests/hello_world.c'], 'running js post-opts') @@ -633,12 +632,13 @@ def test(): # basic usage or lack of usage for native in [None, 0, 1]: print native + Cache.erase() try: if native is not None: os.environ['EMCC_NATIVE_OPTIMIZER'] = str(native) output = build() - assert ('js optimizer using native' in output) == (not not native) + assert ('js optimizer using native' in output) == (not not (native or native is None)) test() - if native: + if native or native is None: # None means use the default, which is to use the native optimizer assert 'building native optimizer' in output # compile again, no rebuild of optimizer output = build() @@ -653,42 +653,36 @@ def test(): Cache.erase() try: - os.environ['EMCC_NATIVE_OPTIMIZER'] = '1' - - try: - # break it - f = path_from_root('tools', 'optimizer', 'optimizer.cpp') - src = open(f).read() - bad = src.replace('main', '!waka waka<') - assert bad != src - open(f, 'w').write(bad) - # first try - output = build() - assert 'failed to build native optimizer' in output, output - assert 'js optimizer using native' not in output - test() # still works, without native optimizer - # second try, see previous failure - output = build() - assert 'failed to build native optimizer' not in output - assert 'seeing that optimizer could not be built' in output - test() # still works, without native optimizer - # clear cache, try again - Cache.erase() - output = build() - assert 'failed to build native optimizer' in output - test() # still works, without native optimizer - finally: - open(f, 'w').write(src) - + # break it + f = path_from_root('tools', 'optimizer', 'optimizer.cpp') + src = open(f).read() + bad = src.replace('main', '!waka waka<') + assert bad != src + open(f, 'w').write(bad) + # first try + output = build() + assert 'failed to build native optimizer' in output, output + assert 'js optimizer using native' not in output + test() # still works, without native optimizer + # second try, see previous failure + output = build() + assert 'failed to build native optimizer' not in output + assert 'seeing that optimizer could not be built' in output + test() # still works, without native optimizer + # clear cache, try again Cache.erase() - - # now it should work again output = build() - assert 'js optimizer using native' in output + assert 'failed to build native optimizer' in output test() # still works, without native optimizer - finally: - os.environ['EMCC_NATIVE_OPTIMIZER'] = '0' + open(f, 'w').write(src) + + Cache.erase() + + # now it should work again + output = build() + assert 'js optimizer using native' in output + test() # still works finally: del os.environ['EMCC_DEBUG'] diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index e95bc27999274..4f86b90e339da 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -25,14 +25,14 @@ def path_from_root(*pathelems): func_sig_json = re.compile('\["defun", ?"([_\w$]+)",') import_sig = re.compile('var ([_\w$]+) *=[^;]+;') -NATIVE_OPTIMIZER = os.environ.get('EMCC_NATIVE_OPTIMIZER') +NATIVE_OPTIMIZER = os.environ.get('EMCC_NATIVE_OPTIMIZER') or '1' # use native optimizer by default, unless disabled by EMCC_NATIVE_OPTIMIZER=0 in the env def get_native_optimizer(): if os.environ.get('EMCC_FAST_COMPILER') == '0': return None # need fastcomp for native optimizer FAIL_MARKER = shared.Cache.get_path('optimizer.building_failed') if os.path.exists(FAIL_MARKER): - shared.logging.debug('seeing that optimizer could not be built') + shared.logging.debug('seeing that optimizer could not be built (run emcc --clear-cache or erase "optimizer.building_failed" in cache dir to retry)') return None def get_optimizer(name, args): From 769d2866403f9b69681604bfba9cf14188459241 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 11:40:46 -0800 Subject: [PATCH 07/11] disable slow2asm legacy testing, and add a testing mode for the non-native js optimizer --- tests/runner.py | 2 +- tests/test_core.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 61d49d74e5c84..50d2b3369733d 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -50,7 +50,7 @@ def nonfastcomp(test): # Core test runner class, shared between normal tests and benchmarks checked_sanity = False -test_modes = ['default', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm3i', 'slow2', 'slow2asm'] +test_modes = ['default', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm3i', 'asm2nn', 'slow2'] test_index = 0 class RunnerCore(unittest.TestCase): diff --git a/tests/test_core.py b/tests/test_core.py index e49c6a737b10c..1c3a0b74163c0 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7270,8 +7270,8 @@ def setUp(self): asm3i = make_run("asm3i", compiler=CLANG, emcc_args=["-O3", '-s', 'EMTERPRETIFY=1']) # Legacy test modes - +asm2nn = make_run("asm2nn", compiler=CLANG, emcc_args=["-O2"], env={"EMCC_NATIVE_OPTIMIZER": "0"}) slow2 = make_run("slow2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0"], env={"EMCC_FAST_COMPILER": "0"}) -slow2asm = make_run("slow2asm", compiler=CLANG, emcc_args=["-O2"], env={"EMCC_FAST_COMPILER": "0"}) del T # T is just a shape for the specific subclasses, we don't test it itself From d5ed10589b309fb54b2bdd4bf3ddc3388bc68268 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 15:47:17 -0800 Subject: [PATCH 08/11] remove more useless subnodes in native optimizer --- tests/test_other.py | 23 +++++++++-------- tools/optimizer/optimizer.cpp | 30 +++++++++++++++++----- tools/test-js-optimizer-asm-regs-output.js | 15 +++++++++++ tools/test-js-optimizer-asm-regs.js | 17 ++++++++++++ 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index 9b4313b8fd090..a13de53a475f8 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1951,16 +1951,19 @@ def fix(src): return map(fix, src) src = '\n'.join(filter(lambda line: 'var ' not in line, src.split('\n'))) # ignore vars def reorder(func): - # emit EYE_ONE always before EYE_TWO, replaceing i1,i2 or i2,i1 - i1 = 'i1' - i2 = 'i2' - if i1 not in func or i2 not in func: return func - ok = func.index(i1) < func.index(i2) - if not ok: - i1 = 'i2' - i2 = 'i1' - func = func.replace(i1, 'EYE_ONE').replace(i2, 'EYE_TWO') - assert func.index('EYE_ONE') < func.index('EYE_TWO') + def swap(func, i1, i2): + # emit EYE_ONE always before EYE_TWO, replacing i1,i2 or i2,i1 etc + if i1 not in func or i2 not in func: return func + ok = func.index(i1) < func.index(i2) + if not ok: + temp = i1 + i1 = i2 + i2 = temp + func = func.replace(i1, 'EYE_ONE').replace(i2, 'EYE_TWO') + assert func.index('EYE_ONE') < func.index('EYE_TWO') + return func + func = swap(func, 'i1', 'i2') + func = swap(func, 'i4', 'i5') return func src = 'function '.join(map(reorder, src.split('function '))) return src diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 4e3475e37a234..3f83408c5f921 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -516,7 +516,8 @@ Ref makeAsmCoercion(Ref node, AsmType type) { // Checks bool isEmpty(Ref node) { - return node->size() == 2 && node[0] == TOPLEVEL && node[1]->size() == 0; + return (node->size() == 2 && node[0] == TOPLEVEL && node[1]->size() == 0) || + (node->size() > 0 && node[0] == BLOCK && (!node[1] || node[1]->size() == 0)); } bool commable(Ref node) { // TODO: hashing @@ -664,7 +665,6 @@ void clearUselessNodes(Ref arr) { void removeAllEmptySubNodes(Ref ast) { traversePre(ast, [](Ref node) { - int index = -1; if (node[0] == DEFUN) { clearEmptyNodes(node[3]); } else if (node[0] == BLOCK && node->size() > 1 && !!node[1]) { @@ -675,15 +675,31 @@ void removeAllEmptySubNodes(Ref ast) { }); } void removeAllUselessSubNodes(Ref ast) { - traversePre(ast, [](Ref node) { - int index = -1; - if (node[0] == DEFUN) { + traversePrePost(ast, [](Ref node) { + Ref type = node[0]; + if (type == DEFUN) { clearUselessNodes(node[3]); - } else if (node[0] == BLOCK && node->size() > 1 && !!node[1]) { + } else if (type == BLOCK && node->size() > 1 && !!node[1]) { clearUselessNodes(node[1]); - } else if (node[0] == SEQ && isEmpty(node[1])) { + } else if (type == SEQ && isEmpty(node[1])) { safeCopy(node, node[2]); } + }, [](Ref node) { + Ref type = node[0]; + if (type == IF) { + bool empty2 = isEmpty(node[2]), has3 = node->size() == 4 && !!node[3], empty3 = !has3 || isEmpty(node[3]); + if (!empty2 && empty3 && has3) { // empty else clauses + node->setSize(3); + } else if (empty2 && !empty3) { // empty if blocks + safeCopy(node, make2(IF, make2(UNARY_PREFIX, L_NOT, node[1]), node[3])); + } else if (empty2 && empty3) { + if (hasSideEffects(node[1])) { + safeCopy(node, make1(STAT, node[1])); + } else { + safeCopy(node, makeEmpty()); + } + } + } }); } diff --git a/tools/test-js-optimizer-asm-regs-output.js b/tools/test-js-optimizer-asm-regs-output.js index c75bbcf74dab3..ca2f6069f8bd7 100644 --- a/tools/test-js-optimizer-asm-regs-output.js +++ b/tools/test-js-optimizer-asm-regs-output.js @@ -106,5 +106,20 @@ function iffey() { function nops() { var i1 = 0; f(i1); + if (cheez) { + doIt(); + } else { + doIt(); + } + if (cheez) { + doIt(); + } + if (!cheez) { + doIt(); + } + if (!cheez) { + doIt(); + } + doIt(); } diff --git a/tools/test-js-optimizer-asm-regs.js b/tools/test-js-optimizer-asm-regs.js index 9c5b49fd13056..a4d1fb96b2a0f 100644 --- a/tools/test-js-optimizer-asm-regs.js +++ b/tools/test-js-optimizer-asm-regs.js @@ -111,6 +111,23 @@ function nops() { x | 0; ~x; f(x); + // vaccuming + if (cheez) { + doIt(); + } else { + doIt(); + } + if (cheez) { + doIt(); + } else {} + if (cheez) {} else { + doIt(); + } + if (cheez) {} else { + doIt(); + } + if (cheez) {} else {} + if (doIt()) {} else {} } // EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "_doit", "stackRestore", "switchey", "switchey2", "iffey", "nops"] From 6df14753bed2cb2410c5e6432564cb66943aa848 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 16:22:08 -0800 Subject: [PATCH 09/11] make other.test_emterpretify more tolerant of native optimizer variability --- tests/test_other.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index a13de53a475f8..a570324162cc7 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -4391,10 +4391,19 @@ def do_log_test(source, expected, func): assert func in pre, pre post = post.split('\n')[0] seen = int(post) - assert expected == seen, ['expect', expected, 'but see', seen] + assert expected == seen or seen in expected, ['expect', expected, 'but see', seen] do_log_test(path_from_root('tests', 'primes.cpp'), 86, 'main') - do_log_test(path_from_root('tests', 'fannkuch.cpp'), 234, 'fannkuch_worker') + do_log_test(path_from_root('tests', 'fannkuch.cpp'), range(234, 239), 'fannkuch_worker') + + # test non-native as well, registerizeHarder can be a little more efficient here + old_native = os.environ.get('EMCC_NATIVE_OPTIMIZER') + try: + os.environ['EMCC_NATIVE_OPTIMIZER'] = '0' + do_log_test(path_from_root('tests', 'fannkuch.cpp'), 234, 'fannkuch_worker') + finally: + if old_native: os.environ['EMCC_NATIVE_OPTIMIZER'] = old_native + else: del os.environ['EMCC_NATIVE_OPTIMIZER'] def test_emterpreter_swap_orig(self): Popen([PYTHON, EMCC, path_from_root('tests', 'fasta.cpp'), '-s', 'EMTERPRETIFY=1', '-s', 'SWAPPABLE_ASM_MODULE=1', '-O2']).communicate() From 0fb761bf49b5822d7114392691ed080c1f82f0e9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 16 Dec 2014 16:34:19 -0800 Subject: [PATCH 10/11] junction variable sorting, to make output deterministic --- tests/test_other.py | 25 +++---- tools/optimizer/optimizer.cpp | 4 +- ...st-js-optimizer-asm-regs-harder-output2.js | 70 +++++++++---------- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index a570324162cc7..3b513d30d8b02 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1944,6 +1944,7 @@ def test_js_optimizer(self): output = Popen(NODE_JS + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] def check_js(js, expected): + #print >> sys.stderr, 'chak\n==========================\n', js, '\n===========================\n' if 'registerizeHarder' in passes: # registerizeHarder is hard to test, as names vary by chance, nondeterminstically FIXME def fix(src): @@ -1951,19 +1952,18 @@ def fix(src): return map(fix, src) src = '\n'.join(filter(lambda line: 'var ' not in line, src.split('\n'))) # ignore vars def reorder(func): - def swap(func, i1, i2): + def swap(func, stuff): # emit EYE_ONE always before EYE_TWO, replacing i1,i2 or i2,i1 etc - if i1 not in func or i2 not in func: return func - ok = func.index(i1) < func.index(i2) - if not ok: - temp = i1 - i1 = i2 - i2 = temp - func = func.replace(i1, 'EYE_ONE').replace(i2, 'EYE_TWO') - assert func.index('EYE_ONE') < func.index('EYE_TWO') + for i in stuff: + if i not in func: return func + indexes = map(lambda i: [i, func.index(i)], stuff) + indexes.sort(lambda x, y: x[1] - y[1]) + for j in range(len(indexes)): + func = func.replace(indexes[j][0], 'STD_' + str(j)) return func - func = swap(func, 'i1', 'i2') - func = swap(func, 'i4', 'i5') + func = swap(func, ['i1', 'i2', 'i3']) + func = swap(func, ['i1', 'i2']) + func = swap(func, ['i4', 'i5']) return func src = 'function '.join(map(reorder, src.split('function '))) return src @@ -4391,10 +4391,11 @@ def do_log_test(source, expected, func): assert func in pre, pre post = post.split('\n')[0] seen = int(post) + print ' seen', seen assert expected == seen or seen in expected, ['expect', expected, 'but see', seen] do_log_test(path_from_root('tests', 'primes.cpp'), 86, 'main') - do_log_test(path_from_root('tests', 'fannkuch.cpp'), range(234, 239), 'fannkuch_worker') + do_log_test(path_from_root('tests', 'fannkuch.cpp'), 234, 'fannkuch_worker') # test non-native as well, registerizeHarder can be a little more efficient here old_native = os.environ.get('EMCC_NATIVE_OPTIMIZER') diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 3f83408c5f921..f8d41459ffcf3 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -3345,7 +3345,9 @@ void registerizeHarder(Ref ast) { } std::sort(sortedJunctionVariables.begin(), sortedJunctionVariables.end(), [&](const IString name1, const IString name2) { //return strcmp(name1.str, name2.str) > 0;// XXX junctionVariables[name1].conf.size() > junctionVariables[name2].conf.size(); - return junctionVariables[name1].conf.size() < junctionVariables[name2].conf.size(); + if (junctionVariables[name1].conf.size() < junctionVariables[name2].conf.size()) return true; + if (junctionVariables[name1].conf.size() == junctionVariables[name2].conf.size()) return name1 < name2; + return false; }); // We can now assign a register to each junction variable. diff --git a/tools/test-js-optimizer-asm-regs-harder-output2.js b/tools/test-js-optimizer-asm-regs-harder-output2.js index 2b1e102d4b209..f82c7e63abbc3 100644 --- a/tools/test-js-optimizer-asm-regs-harder-output2.js +++ b/tools/test-js-optimizer-asm-regs-harder-output2.js @@ -8,13 +8,13 @@ function asm(d1, i2) { d1 = d1 * 5; return d1; } -function _doit(i3, i2, i1) { - i3 = i3 | 0; - i2 = i2 | 0; +function _doit(i1, i2, i3) { i1 = i1 | 0; - i3 = STACKTOP; - _printf(__str | 0, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[(tempInt & 16777215) >> 2] = i2, HEAP32[(tempInt + 4 & 16777215) >> 2] = i1, tempInt)); - STACKTOP = i3; + i2 = i2 | 0; + i3 = i3 | 0; + i1 = STACKTOP; + _printf(__str | 0, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[(tempInt & 16777215) >> 2] = i2, HEAP32[(tempInt + 4 & 16777215) >> 2] = i3, tempInt)); + STACKTOP = i1; return 0 | 0; } function stackRestore(i1) { @@ -38,20 +38,20 @@ function switchey(d1, i2) { } function switchey2() { var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0; - i4 = STACKTOP; + i5 = STACKTOP; STACKTOP = STACKTOP + 8 | 0; i3 = 1; while (1) switch (i3 | 0) { case 1: - i5 = i4 | 0; - __ZN6RandomC1Ev(i5); + i4 = i5 | 0; + __ZN6RandomC1Ev(i4); i1 = 0; i2 = 0; i3 = 2; break; case 2: d7 = +__ZN6Random3getEf(8, +1); - d6 = +__ZN6Random3getEf(i5, +1); + d6 = +__ZN6Random3getEf(i4, +1); _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0); i2 = (d7 != d6 & 1) + i2 | 0; i1 = i1 + 1 | 0; @@ -64,26 +64,26 @@ function switchey2() { } case 3: _printf(16, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[CHECK_ALIGN_4(tempInt | 0) >> 2] = i2, tempInt) | 0); - STACKTOP = i4; + STACKTOP = i5; return 0; } return 0; } function iffey() { var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0; - i4 = STACKTOP; + i5 = STACKTOP; STACKTOP = STACKTOP + 8 | 0; i3 = 1; while (1) { if (i3 | 0) { - i5 = i4 | 0; - __ZN6RandomC1Ev(i5); + i4 = i5 | 0; + __ZN6RandomC1Ev(i4); i1 = 0; i2 = 0; i3 = 2; } else { d7 = +__ZN6Random3getEf(8, +1); - d6 = +__ZN6Random3getEf(i5, +1); + d6 = +__ZN6Random3getEf(i4, +1); _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0); i2 = (d7 != d6 & 1) + i2 | 0; i1 = i1 + 1 | 0; @@ -96,42 +96,42 @@ function iffey() { } return 0; } -function labelledJump(i2) { - i2 = i2 | 0; - var i1 = 0, i3 = 0; - i1 = 2; - if (i2) { +function labelledJump(i1) { + i1 = i1 | 0; + var i2 = 0, i3 = 0; + i2 = 2; + if (i1) { i1 = 17; i3 = 1; } if (i3 == 1) { - i2 = i1 + 1; + i1 = i1 + 1; } else { - i2 = i1 + 1; + i1 = i2 + 1; } - return i2; + return i1; } function linkedVars() { var i1 = 0, i2 = 0; while (1) { - i2 = 9; - i1 = 5; - while (i2 > 0 | i1 > 0) { - if (i2 < i1) { - i2 = i2 - 1; - } else { + i1 = 9; + i2 = 5; + while (i1 > 0 | i2 > 0) { + if (i1 < i2) { i1 = i1 - 1; + } else { + i2 = i2 - 1; } } - if (i2 < i1) { + if (i1 < i2) { break; } } - return i2 + i1; + return i1 + i2; } -function deadCondExpr(i2) { - i2 = i2 | 0; - var i1 = 0; - return i1 | 0; +function deadCondExpr(i1) { + i1 = i1 | 0; + var i2 = 0; + return i2 | 0; } From f13de3a6991da18d30c977d126d6675e1aaf4526 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Dec 2014 11:34:20 -0800 Subject: [PATCH 11/11] 1.28.2 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index 6a10ff7aa230f..b7825b8d76746 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.28.1 +1.28.2