From 2f64ad30aae875df325b02f36b4e55fb432dbdba Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 17 Dec 2014 11:08:54 -0800 Subject: [PATCH 01/75] Fix copy+pastos in the SIMD polyfill This allows fromFloat32x4 and fromInt32x4 to be added to the SIMD function import list. --- emscripten.py | 6 ++---- src/ecmascript_simd.js | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/emscripten.py b/emscripten.py index acfb42f2c5bfb..8501ab3d42984 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1103,11 +1103,9 @@ def make_emulated_param(i): 'splat', 'swizzle', 'shuffle', 'withX', 'withY', 'withZ', 'withW', 'load', 'store'] - # TODO: fromInt32x4 simdfloatfuncs = simdfuncs + ['div', 'min', 'max', 'minNum', 'maxNum', 'sqrt', - 'abs', 'fromInt32x4Bits']; - # TODO: fromFloat32x4 - simdintfuncs = simdfuncs + ['fromFloat32x4Bits', + 'abs', 'fromInt32x4', 'fromInt32x4Bits']; + simdintfuncs = simdfuncs + ['fromFloat32x4', 'fromFloat32x4Bits', 'shiftRightArithmeticByScalar', 'shiftRightLogicalByScalar', 'shiftLeftByScalar']; diff --git a/src/ecmascript_simd.js b/src/ecmascript_simd.js index 3b2737ef4cb65..b33d9e0900b55 100644 --- a/src/ecmascript_simd.js +++ b/src/ecmascript_simd.js @@ -254,7 +254,7 @@ if (typeof SIMD.float32x4.fromUnsignedInt32x4 === "undefined") { * @param {int32x4} t An instance of int32x4. * @return {float32x4} An unsigned integer to float conversion copy of t. */ - SIMD.float32x4.fromInt32x4 = function(t) { + SIMD.float32x4.fromUnsignedInt32x4 = function(t) { t = SIMD.int32x4(t); return SIMD.float32x4(t.x>>>0, t.y>>>0, t.z>>>0, t.w>>>0); } @@ -385,7 +385,7 @@ if (typeof SIMD.float64x2.fromUnsignedInt32x4 === "undefined") { * @param {int32x4} t An instance of int32x4. * @return {float64x2} A float64x2 with .x>>>0 and .y>>>0 from t */ - SIMD.float64x2.fromInt32x4 = function(t) { + SIMD.float64x2.fromUnsignedInt32x4 = function(t) { t = SIMD.int32x4(t); return SIMD.float64x2(t.x>>>0, t.y>>>0); } @@ -534,7 +534,7 @@ if (typeof SIMD.int32x4.fromFloat32x4ToUnsigned === "undefined") { * @param {float32x4} t An instance of float32x4. * @return {int32x4} with an unsigned integer to float conversion of t. */ - SIMD.int32x4.fromFloat32x4 = function(t) { + SIMD.int32x4.fromFloat32x4ToUnsigned = function(t) { t = SIMD.float32x4(t); return SIMD.int32x4(t.x>>>0, t.y>>>0, t.z>>>0, t.w>>>0); } @@ -556,7 +556,7 @@ if (typeof SIMD.int32x4.fromFloat64x2ToUnsigned === "undefined") { * @param {float64x2} t An instance of float64x2. * @return {int32x4} An int32x4 with .x>>>0 and .y>>>0 from t */ - SIMD.int32x4.fromFloat64x2 = function(t) { + SIMD.int32x4.fromFloat64x2ToUnsigned = function(t) { t = SIMD.float64x2(t); return SIMD.int32x4(t.x>>>0, t.y>>>0, 0, 0); } @@ -567,7 +567,7 @@ if (typeof SIMD.int32x4.fromInt16x8 === "undefined") { * @param {int16x8} t An instance of int16x8. * @return {int32x4} with the s0, s1, s2, and s3 from t, sign-extended */ - SIMD.int32x4.fromFloat32x4 = function(t) { + SIMD.int32x4.fromInt16x8 = function(t) { t = SIMD.int16x8(t); return SIMD.int32x4(t.s0, t.s1, t.s2, t.s3); } @@ -578,8 +578,8 @@ if (typeof SIMD.int32x4.fromUnsignedInt8x16 === "undefined") { * @param {int8x16} t An instance of int8x16. * @return {int32x4} with the s0, s1, s2, and s3 from t, zero-extended */ - SIMD.int32x4.fromFloat32x4 = function(t) { - t = SIMD.intint8x16(t); + SIMD.int32x4.fromUnsignedInt8x16 = function(t) { + t = SIMD.int8x16(t); return SIMD.int32x4(t.s0>>>0, t.s1>>>0, t.s2>>>0, t.s3>>>0); } } @@ -589,7 +589,7 @@ if (typeof SIMD.int32x4.fromUnsignedInt16x8 === "undefined") { * @param {int16x8} t An instance of int16x8. * @return {int32x4} with the s0, s1, s2, and s3 from t, zero-extended */ - SIMD.int32x4.fromFloat32x4 = function(t) { + SIMD.int32x4.fromUnsignedInt16x8 = function(t) { t = SIMD.int16x8(t); return SIMD.int32x4(t.s0>>>0, t.s1>>>0, t.s2>>>0, t.s3>>>0); } @@ -600,8 +600,8 @@ if (typeof SIMD.int32x4.fromInt8x16 === "undefined") { * @param {int8x16} t An instance of int8x16. * @return {int32x4} with the s0, s1, s2, and s3 from t */ - SIMD.int32x4.fromFloat32x4 = function(t) { - t = SIMD.intint8x16(t); + SIMD.int32x4.fromInt8x16 = function(t) { + t = SIMD.int8x16(t); return SIMD.int32x4(t.s0, t.s1, t.s2, t.s3); } } From 1c481d92052ad2566620d6f5585ab0acff9366c1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 Dec 2014 19:54:01 -0800 Subject: [PATCH 02/75] do not try to use native optimizer in other.test_js_optimizer if it is not available --- tests/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_other.py b/tests/test_other.py index 3b513d30d8b02..d6a0aa3c0dc41 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1972,7 +1972,7 @@ def swap(func, stuff): self.assertIdentical(expected, js.replace('\r\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')) check_js(output, expected) - if js_optimizer.use_native(passes): + if js_optimizer.use_native(passes) and js_optimizer.get_native_optimizer(): # 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() From 2f1938c53f8fd9a07dba8d5744c2fc456022f64c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 11:20:24 -0800 Subject: [PATCH 03/75] only show native optimizer compiler output if requested using 'g' --- tests/test_sanity.py | 77 +++++++++++++++++++++++++------------------ tools/js_optimizer.py | 29 +++++++++++----- 2 files changed, 65 insertions(+), 41 deletions(-) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 485a4a4af8b4e..25b0722e05682 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -631,12 +631,12 @@ def test(): # basic usage or lack of usage for native in [None, 0, 1]: - print native + print 'phase 1, part', 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 or native is None)) + assert ('js optimizer using native' in output) == (not not (native or native is None)), output test() if native or native is None: # None means use the default, which is to use the native optimizer assert 'building native optimizer' in output @@ -650,39 +650,52 @@ def test(): # force a build failure, see we fall back to non-native - Cache.erase() - 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) + for native in [1, 'g']: + print 'phase 2, part', native + Cache.erase() + os.environ['EMCC_NATIVE_OPTIMIZER'] = str(native) + + 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 + if native == 1: + assert 'to see compiler errors, build with EMCC_NATIVE_OPTIMIZER=g' in output + assert 'waka waka' not in output + else: + assert 'output from attempt' in output, output + assert 'waka waka' 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) - Cache.erase() + Cache.erase() - # now it should work again - output = build() - assert 'js optimizer using native' in output - test() # still works + # now it should work again + output = build() + assert 'js optimizer using native' in output + test() # still works + + finally: + del os.environ['EMCC_NATIVE_OPTIMIZER'] finally: del os.environ['EMCC_DEBUG'] diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 4f86b90e339da..034709007cbc2 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -35,8 +35,10 @@ def get_native_optimizer(): 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): + def get_optimizer(name, args, handle_build_errors=None): class NativeOptimizerCreationException(Exception): pass + outs = [] + errs = [] try: def create_optimizer(): shared.logging.debug('building native optimizer: ' + name) @@ -45,11 +47,13 @@ def create_optimizer(): for compiler in [shared.CLANG, 'g++', 'clang++']: # try our clang first, otherwise hope for a system compiler in the path shared.logging.debug(' using ' + compiler) try: - subprocess.Popen([compiler, - shared.path_from_root('tools', 'optimizer', 'parser.cpp'), - shared.path_from_root('tools', 'optimizer', 'simple_ast.cpp'), - shared.path_from_root('tools', 'optimizer', 'optimizer.cpp'), - '-O3', '-std=c++11', '-fno-exceptions', '-fno-rtti', '-o', output] + args).communicate() + out, err = subprocess.Popen([compiler, + shared.path_from_root('tools', 'optimizer', 'parser.cpp'), + shared.path_from_root('tools', 'optimizer', 'simple_ast.cpp'), + shared.path_from_root('tools', 'optimizer', 'optimizer.cpp'), + '-O3', '-std=c++11', '-fno-exceptions', '-fno-rtti', '-o', output] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() + outs.append(out) + errs.append(err) except OSError: if compiler == shared.CLANG: raise # otherwise, OSError is likely due to g++ or clang++ not being in the path if os.path.exists(output): return output @@ -57,15 +61,22 @@ def create_optimizer(): return shared.Cache.get(name, create_optimizer, extension='exe') except NativeOptimizerCreationException, e: shared.logging.debug('failed to build native optimizer') + handle_build_errors(outs, errs) open(FAIL_MARKER, 'w').write(':(') return None + def ignore_build_errors(outs, errs): + shared.logging.debug('to see compiler errors, build with EMCC_NATIVE_OPTIMIZER=g') + def show_build_errors(outs, errs): + for i in range(len(outs)): + shared.logging.debug('output from attempt ' + str(i) + ': ' + outs[i] + '\n===========\n' + errs[i]) + if NATIVE_OPTIMIZER == '1': - return get_optimizer('optimizer.exe', []) + return get_optimizer('optimizer.exe', [], ignore_build_errors) elif NATIVE_OPTIMIZER == '2': - return get_optimizer('optimizer.2.exe', ['-DNDEBUG']) + return get_optimizer('optimizer.2.exe', ['-DNDEBUG'], ignore_build_errors) elif NATIVE_OPTIMIZER == 'g': - return get_optimizer('optimizer.g.exe', ['-O0', '-g', '-fno-omit-frame-pointer']) + return get_optimizer('optimizer.g.exe', ['-O0', '-g', '-fno-omit-frame-pointer'], show_build_errors) # Check if we should run a pass or set of passes natively. if a set of passes, they must all be valid to run in the native optimizer at once. def use_native(x, source_map=False): From 74cb6b229d74c33cfb1e2fb63229c00bcce2036d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 18 Dec 2014 13:34:06 -0800 Subject: [PATCH 04/75] Put the SIMD object in the global namespace. This removes the var keyword from the polyfill's SIMD declaration. --- src/ecmascript_simd.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ecmascript_simd.js b/src/ecmascript_simd.js index b33d9e0900b55..f2c9ec682acf1 100644 --- a/src/ecmascript_simd.js +++ b/src/ecmascript_simd.js @@ -19,8 +19,11 @@ */ if (typeof SIMD === "undefined") { - // SIMD module. - var SIMD = {}; + // SIMD module. We don't use the var keyword here, so that we put the + // SIMD object in the global scope even if this polyfill code is included + // within some other scope. The theory is that we're anticipating a + // future where SIMD is predefined in the global scope. + SIMD = {}; } // private stuff. From 9a055400a97bcc6fbb59cc9a35d8ce72d8eb9b19 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 14:16:41 -0800 Subject: [PATCH 05/75] make ports including message less annoying --- tests/test_sanity.py | 5 ----- tools/system_libs.py | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 25b0722e05682..8b1d39393ec92 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -568,7 +568,6 @@ def test_emcc_ports(self): # using ports - INCLUDING_MESSAGE = 'including port' RETRIEVING_MESSAGE = 'retrieving port' BUILDING_MESSAGE = 'building port' @@ -586,14 +585,12 @@ def test_emcc_ports(self): # Building a file that doesn't need ports should not trigger anything output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp')]) - assert INCLUDING_MESSAGE not in output assert RETRIEVING_MESSAGE not in output assert BUILDING_MESSAGE not in output assert not os.path.exists(PORTS_DIR) # Building a file that need a port does trigger stuff output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) - assert INCLUDING_MESSAGE in output, output assert RETRIEVING_MESSAGE in output, output assert BUILDING_MESSAGE in output, output assert os.path.exists(PORTS_DIR) @@ -601,7 +598,6 @@ def test_emcc_ports(self): def second_use(): # Using it again avoids retrieve and build output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) - assert INCLUDING_MESSAGE in output, output assert RETRIEVING_MESSAGE not in output, output assert BUILDING_MESSAGE not in output, output @@ -610,7 +606,6 @@ def second_use(): # if the version isn't sufficient, we retrieve and rebuild open(os.path.join(PORTS_DIR, 'sdl2', 'SDL2-master', 'version.txt'), 'w').write('1') # current is >= 2, so this is too old output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) - assert INCLUDING_MESSAGE in output, output assert RETRIEVING_MESSAGE in output, output assert BUILDING_MESSAGE in output, output assert os.path.exists(PORTS_DIR) diff --git a/tools/system_libs.py b/tools/system_libs.py index ca2a6d7ed1608..d73cd79a9d4b1 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -713,7 +713,7 @@ def fetch_project(name, url, expected_version): fullname = os.path.join(Ports.get_dir(), name) if name not in Ports.name_cache: # only mention each port once in log - logging.warning('including port: ' + name) + logging.debug('including port: ' + name) logging.debug(' (at ' + fullname + ')') Ports.name_cache.add(name) From 7e73a083aa09c59063834a91b88209f503c41764 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 14:28:46 -0800 Subject: [PATCH 06/75] add emscripten system builder tool --- embuilder.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 embuilder.py diff --git a/embuilder.py b/embuilder.py new file mode 100644 index 0000000000000..bdfb432b217f5 --- /dev/null +++ b/embuilder.py @@ -0,0 +1,115 @@ +''' +Tool to manage building of various useful things, such as libc, libc++, native optimizer, as well as fetch and build ports like zlib and sdl2 +''' + +import os, sys +import tools.shared as shared + +if len(sys.argv) < 2 or sys.argv[1] in ['-v', '-help', '--help', '-?', '?']: + print ''' +Emscripten System Builder Tool +============================== + +You can use this tool to manually build parts of the emscripten system +environment. In general emcc will build them automatically on demand, so +you do not strictly need to use this tool, but it gives you more control +over the process (in particular, if emcc does this automatically, and you +are running multiple build commands in parallel, confusion can occur). + +Usage: + + embuilder.py OPERATION TASK1 [TASK2..] + +Available operations and tasks: + + build libc + libcxx + libcxxabi + gl + struct_info + native_optimizer + zlib + sdl2 + sdl2-image +''' + sys.exit(1) + +temp_files = shared.configuration.get_temp_files() + +def build(src, result_libs, args=[]): + temp = temp_files.get('.cpp').name + open(temp, 'w').write(src) + temp_js = temp_files.get('.js').name + shared.Building.emcc(temp, args, output_filename=temp_js) + assert os.path.exists(temp_js), 'failed to build file' + for lib in result_libs: + assert os.path.exists(shared.Cache.get_path(lib)), 'not seeing that requested library %s has been built' % lib + +operation = sys.argv[1] + +if operation == 'build': + for what in sys.argv[2:]: + shared.logging.info('building and verifying ' + what) + if what == 'libc': + build(''' + #include + #include + int main() { + return int(malloc(10)) + int(strchr("str", 'c')); + } + ''', ['libc.bc', 'libcextra.bc']) + elif what == 'libcxx': + build(''' + #include + int main() { + std::cout << "hello"; + return 0; + } + ''', ['libcxx.bc']) + elif what == 'libcxxabi': + build(''' + struct X { int x; virtual void a() {} }; + struct Y : X { int y; virtual void a() { y = 10; }}; + int main(int argc, char **argv) { + Y* y = dynamic_cast((X*)argv[1]); + y->a(); + return y->y; + } + ''', ['libcxxabi.bc']) + elif what == 'gl': + build(''' + extern "C" { extern void* emscripten_GetProcAddress(const char *x); } + int main() { + return int(emscripten_GetProcAddress("waka waka")); + } + ''', ['gl.bc']) + elif what == 'struct_info': + build(''' + int main() {} + ''', ['struct_info.compiled.json']) + elif what == 'native_optimizer': + build(''' + int main() {} + ''', ['optimizer.exe'], ['-O2']) + elif what == 'zlib': + build(''' + int main() {} + ''', [os.path.join('ports-builds', 'zlib', 'libz.a')], ['-s', 'USE_ZLIB=1']) + elif what == 'sdl2': + build(''' + int main() {} + ''', [os.path.join('ports-builds', 'sdl2', 'libsdl2.bc')], ['-s', 'USE_SDL=2']) + elif what == 'sdl2-image': + build(''' + int main() {} + ''', [os.path.join('ports-builds', 'sdl2-image', 'libsdl2_image.bc')], ['-s', 'USE_SDL=2', '-s', 'USE_SDL_IMAGE=2']) + else: + shared.logging.error('unfamiliar build target: ' + what) + sys.exit(1) + + shared.logging.info('...success') + +else: + shared.logging.error('unfamiliar operation: ' + operation) + sys.exit(1) + From f84d67bc826bf3fa1c01fb7cbf893c4637bd27b9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 14:30:55 -0800 Subject: [PATCH 07/75] make embuilder.py runnable --- embuilder.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 embuilder.py diff --git a/embuilder.py b/embuilder.py old mode 100644 new mode 100755 index bdfb432b217f5..99182db7ae4e2 --- a/embuilder.py +++ b/embuilder.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python2 + ''' Tool to manage building of various useful things, such as libc, libc++, native optimizer, as well as fetch and build ports like zlib and sdl2 ''' From 5e89a03ab34a2bd7edb7471ce6bd0a28c2a848e9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 14:55:01 -0800 Subject: [PATCH 08/75] update cashew --- tools/optimizer/parser.cpp | 3 +-- tools/optimizer/parser.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/optimizer/parser.cpp b/tools/optimizer/parser.cpp index a650f4bd7bb1e..915ece8363084 100644 --- a/tools/optimizer/parser.cpp +++ b/tools/optimizer/parser.cpp @@ -85,8 +85,7 @@ IString TOPLEVEL("toplevel"), THROW("throw"), SET("="); -IStringSet keywords("var function if else do while for break continue return switch case default throw try catch finally true false null new"), - allOperators(". ! ~ - + * / % + - << >> >>> < <= > >= == != & ^ | ? : = ,"); +IStringSet keywords("var function if else do while for break continue return switch case default throw try catch finally true false null new"); const char *OPERATOR_INITS = "+-*/%<>&^|~=!,?:.", *SEPARATORS = "([;{}"; diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index 4ed8523c104d5..a555efc9aa104 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -94,7 +94,7 @@ extern IString TOPLEVEL, THROW, SET; -extern IStringSet keywords, allOperators; +extern IStringSet keywords; extern const char *OPERATOR_INITS, *SEPARATORS; @@ -672,7 +672,7 @@ class Parser { // we are the toplevel. sort it all out // collapse right to left, highest priority first //dumpParts(parts, 0); - for (auto ops : operatorClasses) { + for (auto& ops : operatorClasses) { if (ops.rtl) { // right to left for (int i = parts.size()-1; i >= 0; i--) { From 0ee1fc15fd77074f7aa8d98044aa9a3dd5456a57 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 15:52:39 -0800 Subject: [PATCH 09/75] embuilder test, and fix return code when showing help --- embuilder.py | 2 +- tests/test_sanity.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/embuilder.py b/embuilder.py index 99182db7ae4e2..7d5ba2be174d6 100755 --- a/embuilder.py +++ b/embuilder.py @@ -34,7 +34,7 @@ sdl2 sdl2-image ''' - sys.exit(1) + sys.exit(0) temp_files = shared.configuration.get_temp_files() diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 8b1d39393ec92..8636a13a11e77 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -695,3 +695,33 @@ def test(): finally: del os.environ['EMCC_DEBUG'] + def test_embuilder(self): + restore() + + for command, expected, success, result_libs in [ + ([PYTHON, 'embuilder.py'], ['Emscripten System Builder Tool', 'build libc', 'native_optimizer'], True, []), + ([PYTHON, 'embuilder.py', 'build', 'waka'], 'ERROR', False, []), + ([PYTHON, 'embuilder.py', 'build', 'libc'], ['building and verifying libc', 'success'], True, ['libc.bc']), + ([PYTHON, 'embuilder.py', 'build', 'libcxx'], ['success'], True, ['libcxx.bc']), + ([PYTHON, 'embuilder.py', 'build', 'libcxxabi'], ['success'], True, ['libcxxabi.bc']), + ([PYTHON, 'embuilder.py', 'build', 'gl'], ['success'], True, ['gl.bc']), + ([PYTHON, 'embuilder.py', 'build', 'struct_info'], ['success'], True, ['struct_info.compiled.json']), + ([PYTHON, 'embuilder.py', 'build', 'native_optimizer'], ['success'], True, ['optimizer.exe']), + ([PYTHON, 'embuilder.py', 'build', 'zlib'], ['building and verifying zlib', 'success'], True, [os.path.join('ports-builds', 'zlib', 'libz.a')]), + ([PYTHON, 'embuilder.py', 'build', 'sdl2'], ['success'], True, [os.path.join('ports-builds', 'sdl2', 'libsdl2.bc')]), + ([PYTHON, 'embuilder.py', 'build', 'sdl2-image'], ['success'], True, [os.path.join('ports-builds', 'sdl2-image', 'libsdl2_image.bc')]), + ]: + print command + Cache.erase() + + proc = Popen(command, stdout=PIPE, stderr=STDOUT) + out, err = proc.communicate() + assert (proc.returncode == 0) == success, out + if type(expected) == str: expected = [expected] + for ex in expected: + print ' seek', ex + assert ex in out, out + for lib in result_libs: + print ' verify', lib + assert os.path.exists(Cache.get_path(lib)) + From 278626d78831678fd15684568dbcf155f9637e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:29:11 -0500 Subject: [PATCH 10/75] Visual Studio C++11 support does not allow unrestricted unions, so move the string form outside the union. --- tools/optimizer/simple_ast.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index b757c1a267d9e..29003b5ec86fd 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -79,8 +79,8 @@ struct Value { typedef std::vector ArrayStorage; typedef std::unordered_map ObjectStorage; + IString str; union { // TODO: optimize - IString str; double num; ArrayStorage *arr; bool boo; From e301f390a8250719bbb4453bbba34a2e670a70c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:33:27 -0500 Subject: [PATCH 11/75] Visual Studio does not support C99, so implement snprintf emulation for it. --- tools/optimizer/simple_ast.h | 2 ++ tools/optimizer/snprintf.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tools/optimizer/snprintf.h diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 29003b5ec86fd..aa6a622a95ee8 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -15,6 +15,8 @@ #include "parser.h" +#include "snprintf.h" + #define err(str) fprintf(stderr, str "\n"); #define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__); #define printErr err diff --git a/tools/optimizer/snprintf.h b/tools/optimizer/snprintf.h new file mode 100644 index 0000000000000..2792a23a23fb7 --- /dev/null +++ b/tools/optimizer/snprintf.h @@ -0,0 +1,32 @@ +#include + +// Visual Studio does not support C99, so emulate snprintf support for it manually. + +#ifdef _MSC_VER + +#define snprintf c99_snprintf + +inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +inline int c99_snprintf(char* str, size_t size, const char* format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(str, size, format, ap); + va_end(ap); + + return count; +} +#endif From a0b399ec694c5ce45e1ae5bfb55d6e5c8cfdb464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:35:46 -0500 Subject: [PATCH 12/75] Fix Visual Studio build error C3493: 'MIN_COST' cannot be implicitly captured because no default capture mode has been specified. --- tools/optimizer/optimizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index f8d41459ffcf3..5d80e51fbe349 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -1981,9 +1981,9 @@ void simplifyExpressions(Ref ast) { // expensive | cheap can be turned into cheap ? 1 : expensive, // so that we can avoid the expensive computation, if it has no side effects. auto conditionalize = [&emitsBoolean](Ref ast) { - const int MIN_COST = 7; traversePre(ast, [&emitsBoolean](Ref node) { - if (node[0] == BINARY && (node[1] == OR || node[1] == AND) && node[3][0] != NUM && node[2][0] != NUM) { + const int MIN_COST = 7; + if (node[0] == BINARY && (node[1] == OR || node[1] == AND) && node[3][0] != NUM && node[2][0] != NUM) { // logical operator on two non-numerical values Ref left = node[2]; Ref right = node[3]; From e87c00e2ecf3e7152d39dff444125fb7fe3a70cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:39:16 -0500 Subject: [PATCH 13/75] Avoid the use of C99 variable length arrays, which is not supported by Visual Studio. --- tools/optimizer/optimizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 5d80e51fbe349..2dab942d7aa0d 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2223,7 +2223,7 @@ void optimizeFrounds(Ref ast) { const char* getRegPrefix(AsmType type) { switch (type) { - case ASM_INT: return"i"; break; + case ASM_INT: return "i"; break; case ASM_DOUBLE: return "d"; break; case ASM_FLOAT: return "f"; break; case ASM_FLOAT32X4: return "F4"; break; @@ -2236,7 +2236,7 @@ const char* getRegPrefix(AsmType type) { IString getRegName(AsmType type, int num) { const char* str = getRegPrefix(type); - int size = strlen(str) + int(ceil(log10(num))) + 3; + const int size = 256; char temp[size]; int written = sprintf(temp, "%s%d", str, num); assert(written < size); From 5c9907debd1b11c770579585b424d6e9dc4751fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:40:13 -0500 Subject: [PATCH 14/75] Fix Visual Studio build warning C4099: 'Ref' : type name first seen using 'class' now seen using 'struct' --- tools/optimizer/simple_ast.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index aa6a622a95ee8..4f9e4a8f32dcd 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -23,7 +23,7 @@ using namespace cashew; -class Ref; +struct Ref; struct Value; void dump(const char *str, Ref node, bool pretty=false); From d94e9336d1f40b8ad16148f5543ca48d4875f3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:54:04 -0500 Subject: [PATCH 15/75] Remove default value of a lambda parameter which Visual Studio does not accept (Section 5.1.2 paragraph 5: Default arguments (8.3.6) shall not be specified in the parameter-declaration-clause of a lambda-declarator) --- tools/optimizer/optimizer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 2dab942d7aa0d..3077263a7d11d 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2596,7 +2596,7 @@ void registerizeHarder(Ref ast) { std::function joinJunction; - auto markJunction = [&](int id=-1) { + auto markJunction = [&](int id) { // Mark current traversal location as a junction. // This makes a new basic block exiting at this position. if (id < 0) { @@ -2751,7 +2751,7 @@ void registerizeHarder(Ref ast) { // Traverse each node type according to its particular control-flow semantics. // TODO: switchify this if (type == DEFUN) { - int jEntry = markJunction(); + int jEntry = markJunction(-1); assert(jEntry == ENTRY_JUNCTION); int jExit = addJunction(); assert(jExit == EXIT_JUNCTION); @@ -2763,7 +2763,7 @@ void registerizeHarder(Ref ast) { isInExpr++; buildFlowGraph(node[1]); isInExpr--; - int jEnter = markJunction(); + int jEnter = markJunction(-1); int jExit = addJunction(); if (!!node[2]) { // Detect and mark "if (label == N) { }". @@ -2795,7 +2795,7 @@ void registerizeHarder(Ref ast) { } } else { buildFlowGraph(node[1]); - int jEnter = markJunction(); + int jEnter = markJunction(-1); int jExit = addJunction(); if (!!node[2]) { buildFlowGraph(node[2]); @@ -2812,7 +2812,7 @@ void registerizeHarder(Ref ast) { // Special-case "while (1) {}" to use fewer junctions, // since emscripten generates a lot of these. if (isTrueNode(node[1])) { - int jLoop = markJunction(); + int jLoop = markJunction(-1); int jExit = addJunction(); pushActiveLabels(jLoop, jExit); buildFlowGraph(node[2]); @@ -2820,7 +2820,7 @@ void registerizeHarder(Ref ast) { joinJunction(jLoop, false); setJunction(jExit, false); } else { - int jCond = markJunction(); + int jCond = markJunction(-1); int jLoop = addJunction(); int jExit = addJunction(); isInExpr++; @@ -2845,7 +2845,7 @@ void registerizeHarder(Ref ast) { popActiveLabels(); joinJunction(jExit, false); } else if (isTrueNode(node[1])) { - int jLoop = markJunction(); + int jLoop = markJunction(-1); int jExit = addJunction(); pushActiveLabels(jLoop, jExit); buildFlowGraph(node[2]); @@ -2853,7 +2853,7 @@ void registerizeHarder(Ref ast) { joinJunction(jLoop, false); setJunction(jExit, false); } else { - int jLoop = markJunction(); + int jLoop = markJunction(-1); int jCond = addJunction(); int jCondExit = addJunction(); int jExit = addJunction(); @@ -2901,7 +2901,7 @@ void registerizeHarder(Ref ast) { buildFlowGraph(node[1]); isInExpr--; Ref condition = lookThroughCasts(node[1]); - int jCheckExit = markJunction(); + int jCheckExit = markJunction(-1); int jExit = addJunction(); pushActiveLabels(-1, jExit); bool hasDefault = false; From 3df6809700c081970fd15e6b97a94f7b9e3328f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:57:31 -0500 Subject: [PATCH 16/75] Remove uses of unrestricted unions when building with MSVC. --- tools/optimizer/parser.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index a555efc9aa104..308cc9c323835 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -167,10 +167,14 @@ class Parser { }; struct Frag { +#ifndef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf union { +#endif IString str; double num; +#ifndef _MSC_VER }; +#endif int size; FragType type; @@ -598,10 +602,14 @@ class Parser { struct ExpressionElement { bool isNode; - union { +#ifndef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + union { +#endif NodeRef node; IString op; +#ifndef _MSC_VER }; +#endif ExpressionElement(NodeRef n) : isNode(true), node(n) {} ExpressionElement(IString o) : isNode(false), op(o) {} From 85fe841c0f28647ed1d0c36d07b0f6c5f5a94823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 16:58:43 -0500 Subject: [PATCH 17/75] Add missing include header for std::max. --- tools/optimizer/simple_ast.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 4f9e4a8f32dcd..dd7654f4c6865 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include From 6e11e547556ee391dd11665c90acbbf35cb5bfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:00:43 -0500 Subject: [PATCH 18/75] Remove the use of ISO 646 'ism which Visual Studio does not support. --- tools/optimizer/simple_ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index 8aba0b17594c2..4d7a9b9cb859d 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -110,7 +110,7 @@ struct StackedStack { // a stack, on the stack } }; -#define visitable(node) (node->isArray() and node->size() > 0) +#define visitable(node) (node->isArray() && node->size() > 0) #define TRAV_STACK 40 From 14844f9daae24a13a7657732e68c742c29ed4f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:17:36 -0500 Subject: [PATCH 19/75] Clean up build warnings C4018 signed/unsigned mismatch in '<'. --- tools/optimizer/optimizer.cpp | 116 ++++++++++++++++----------------- tools/optimizer/parser.h | 12 ++-- tools/optimizer/simple_ast.cpp | 8 +-- tools/optimizer/simple_ast.h | 16 ++--- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 3077263a7d11d..b3332a5473d10 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -20,7 +20,7 @@ Ref doc, extraInfo; template int indexOf(T list, V value) { - for (int i = 0; i < list.size(); i++) { + for (size_t i = 0; i < list.size(); i++) { if (list[i] == value) return i; } return -1; @@ -144,7 +144,7 @@ struct AsmData { // process initial params Ref stats = func[3]; - int i = 0; + size_t i = 0; while (i < stats->size()) { Ref node = stats[i]; if (node[0] != STAT || node[1][0] != ASSIGN || node[1][2][0] != NAME) break; @@ -163,7 +163,7 @@ struct AsmData { while (i < stats->size()) { Ref node = stats[i]; if (node[0] != VAR) break; - for (int j = 0; j < node[1]->size(); j++) { + for (size_t j = 0; j < node[1]->size(); j++) { Ref v = node[1][j]; IString& name = v[0]->getIString(); Ref value = v[1]; @@ -202,7 +202,7 @@ struct AsmData { void denormalize() { Ref stats = func[3]; // Remove var definitions, if any - for (int i = 0; i < stats->size(); i++) { + for (size_t i = 0; i < stats->size(); i++) { if (stats[i][0] == VAR) { stats[i] = makeEmpty(); } else { @@ -215,13 +215,13 @@ struct AsmData { varDefs->push_back(makeAsmVarDef(v, locals[v].type)); } // each param needs a line; reuse emptyNodes as much as we can - int numParams = params.size(); - int emptyNodes = 0; + size_t numParams = params.size(); + size_t emptyNodes = 0; while (emptyNodes < stats->size()) { if (!isEmpty(stats[emptyNodes])) break; emptyNodes++; } - int neededEmptyNodes = numParams + (varDefs->size() ? 1 : 0); // params plus one big var if there are vars + size_t neededEmptyNodes = numParams + (varDefs->size() ? 1 : 0); // params plus one big var if there are vars if (neededEmptyNodes > emptyNodes) { stats->insert(0, neededEmptyNodes - emptyNodes); } else if (neededEmptyNodes < emptyNodes) { @@ -272,7 +272,7 @@ struct AsmData { void deleteVar(IString name) { locals.erase(name); - for (int i = 0; i < vars.size(); i++) { + for (size_t i = 0; i < vars.size(); i++) { if (vars[i] == name) { vars.erase(vars.begin() + i); break; @@ -639,7 +639,7 @@ void safeCopy(Ref target, Ref source) { // safely copy source onto target, even void clearEmptyNodes(Ref arr) { int skip = 0; - for (int i = 0; i < arr->size(); i++) { + for (size_t i = 0; i < arr->size(); i++) { if (skip) { arr[i-skip] = arr[i]; } @@ -651,7 +651,7 @@ void clearEmptyNodes(Ref arr) { } void clearUselessNodes(Ref arr) { int skip = 0; - for (int i = 0; i < arr->size(); i++) { + for (size_t i = 0; i < arr->size(); i++) { Ref curr = arr[i]; if (skip) { arr[i-skip] = curr; @@ -711,7 +711,7 @@ Ref unVarify(Ref vars) { // transform var x=1, y=2 etc. into (x=1, y=2), i.e., t } else { ret->push_back(makeArray()); Ref curr = ret[1]; - for (int i = 0; i < vars->size()-1; i++) { + for (size_t i = 0; i+1 < vars->size(); i++) { curr->push_back(makeString(SEQ)); curr->push_back(make3(ASSIGN, &(arena.alloc())->setBool(true), makeName(vars[i][0]->getIString()), vars[i][1])); if (i != vars->size()-2) { @@ -931,7 +931,7 @@ void eliminate(Ref ast, bool memSafe=false) { Ref type = node[0]; if (type == VAR) { Ref node1 = node[1]; - for (int i = 0; i < node1->size(); i++) { + for (size_t i = 0; i < node1->size(); i++) { Ref node1i = node1[i]; IString name = node1i[0]->getIString(); Ref value; @@ -1093,7 +1093,7 @@ void eliminate(Ref ast, bool memSafe=false) { temp.push_back(name); \ } \ } \ - for (int i = 0; i < temp.size(); i++) { \ + for (size_t i = 0; i < temp.size(); i++) { \ tracked.erase(temp[i]); \ } \ }; @@ -1110,7 +1110,7 @@ void eliminate(Ref ast, bool memSafe=false) { temp.push_back(name); } } - for (int i = 0; i < temp.size(); i++) { + for (size_t i = 0; i < temp.size(); i++) { tracked.erase(temp[i]); } }; @@ -1181,7 +1181,7 @@ void eliminate(Ref ast, bool memSafe=false) { } } else if (type == VAR) { Ref vars = node[1]; - for (int i = 0; i < vars->size(); i++) { + for (size_t i = 0; i < vars->size(); i++) { IString name = vars[i][0]->getIString(); Ref value; if (vars[i]->size() > 1 && !!(value = vars[i][1])) { @@ -1231,7 +1231,7 @@ void eliminate(Ref ast, bool memSafe=false) { } else if (type == CALL) { traverseInOrder(node[1], false, true); Ref args = node[2]; - for (int i = 0; i < args->size(); i++) { + for (size_t i = 0; i < args->size(); i++) { traverseInOrder(args[i], false, false); } if (callHasSideEffects(node)) { @@ -1262,7 +1262,7 @@ void eliminate(Ref ast, bool memSafe=false) { } else if (type == BLOCK) { Ref stats = getStatements(node); if (!!stats) { - for (int i = 0; i < stats->size(); i++) { + for (size_t i = 0; i < stats->size(); i++) { traverseInOrder(stats[i], false, false); } } @@ -1293,11 +1293,11 @@ void eliminate(Ref ast, bool memSafe=false) { traverseInOrder(node[1], false, false); Tracked originalTracked = tracked; Ref cases = node[2]; - for (int i = 0; i < cases->size(); i++) { + for (size_t i = 0; i < cases->size(); i++) { Ref c = cases[i]; assert(c[0]->isNull() || c[0][0] == NUM || (c[0][0] == UNARY_PREFIX && c[0][2][0] == NUM)); Ref stats = c[1]; - for (int j = 0; j < stats->size(); j++) { + for (size_t j = 0; j < stats->size(); j++) { traverseInOrder(stats[j], false, false); } // We cannot track from one switch case into another, undo all new trackings TODO: general framework here, use in if-else as well @@ -1356,10 +1356,10 @@ void eliminate(Ref ast, bool memSafe=false) { } if (!stats) return; tracked.clear(); - for (int i = 0; i < stats->size(); i++) { + for (size_t i = 0; i < stats->size(); i++) { Ref node = deStat(stats[i]); Ref type = node[0]; - if (type == RETURN && i < stats->size()-1) { + if (type == RETURN && i+1 < stats->size()) { stats->setSize(i+1); // remove any code after a return } // Check for things that affect elimination @@ -1421,7 +1421,7 @@ void eliminate(Ref ast, bool memSafe=false) { Ref assigns = ifFalse[1]; clearEmptyNodes(assigns); std::vector loopers, helpers; - for (int i = 0; i < assigns->size(); i++) { + for (size_t i = 0; i < assigns->size(); i++) { if (assigns[i][0] == STAT && assigns[i][1][0] == ASSIGN) { Ref assign = assigns[i][1]; if (assign[1]->isBool(true) && assign[2][0] == NAME && assign[3][0] == NAME) { @@ -1436,7 +1436,7 @@ void eliminate(Ref ast, bool memSafe=false) { } } // remove loop vars that are used in the rest of the else - for (int i = 0; i < assigns->size(); i++) { + for (size_t i = 0; i < assigns->size(); i++) { if (assigns[i][0] == STAT && assigns[i][1][0] == ASSIGN) { Ref assign = assigns[i][1]; if (!(assign[1]->isBool(true) && assign[2][0] == NAME && assign[3][0] == NAME) || indexOf(loopers, assign[2][1]->getIString()) < 0) { @@ -1466,12 +1466,12 @@ void eliminate(Ref ast, bool memSafe=false) { } }); if (loopers.size() == 0) return; - for (int l = 0; l < loopers.size(); l++) { + for (size_t l = 0; l < loopers.size(); l++) { IString looper = loopers[l]; IString helper = helpers[l]; // the remaining issue is whether loopers are used after the assignment to helper and before the last line (where we assign to it) int found = -1; - for (int i = stats->size()-2; i >= 0; i--) { + for (int i = (int)stats->size()-2; i >= 0; i--) { Ref curr = stats[i]; if (curr[0] == STAT && curr[1][0] == ASSIGN) { Ref currAssign = curr[1]; @@ -1494,8 +1494,8 @@ void eliminate(Ref ast, bool memSafe=false) { int firstLooperUsage = -1; int lastLooperUsage = -1; int firstHelperUsage = -1; - for (int i = found+1; i < stats->size(); i++) { - Ref curr = i < stats->size()-1 ? stats[i] : last[1]; // on the last line, just look in the condition + for (int i = found+1; i < (int)stats->size(); i++) { + Ref curr = i < (int)stats->size()-1 ? stats[i] : last[1]; // on the last line, just look in the condition traversePre(curr, [&](Ref node) { if (node[0] == NAME) { if (node[1] == looper) { @@ -1509,7 +1509,7 @@ void eliminate(Ref ast, bool memSafe=false) { } if (firstLooperUsage >= 0) { // the looper is used, we cannot simply merge the two variables - if ((firstHelperUsage < 0 || firstHelperUsage > lastLooperUsage) && lastLooperUsage+1 < stats->size() && triviallySafeToMove(stats[found], asmData) && + if ((firstHelperUsage < 0 || firstHelperUsage > lastLooperUsage) && lastLooperUsage+1 < (int)stats->size() && triviallySafeToMove(stats[found], asmData) && seenUses[helper] == namings[helper]) { // the helper is not used, or it is used after the last use of the looper, so they do not overlap, // and the last looper usage is not on the last line (where we could not append after it), and the @@ -1523,7 +1523,7 @@ void eliminate(Ref ast, bool memSafe=false) { IString temp(strdupe((std::string(looper.c_str()) + "$looptemp").c_str())); assert(!asmData.isLocal(temp)); for (int i = firstLooperUsage; i <= lastLooperUsage; i++) { - Ref curr = i < stats->size()-1 ? stats[i] : last[1]; // on the last line, just look in the condition + Ref curr = i < (int)stats->size()-1 ? stats[i] : last[1]; // on the last line, just look in the condition std::function looperToLooptemp = [&](Ref node) { if (node[0] == NAME) { @@ -1544,13 +1544,13 @@ void eliminate(Ref ast, bool memSafe=false) { } } } - for (int l = 0; l < helpers.size(); l++) { - for (int k = 0; k < helpers.size(); k++) { + for (size_t l = 0; l < helpers.size(); l++) { + for (size_t k = 0; k < helpers.size(); k++) { if (l != k && helpers[l] == helpers[k]) return; // it is complicated to handle a shared helper, abort } } // hurrah! this is safe to do - for (int l = 0; l < loopers.size(); l++) { + for (size_t l = 0; l < loopers.size(); l++) { IString looper = loopers[l]; IString helper = helpers[l]; varsToRemove[helper] = 2; @@ -1571,7 +1571,7 @@ void eliminate(Ref ast, bool memSafe=false) { last->pop_back(); } else { Ref elseStats = getStatements(last[3]); - for (int i = 0; i < elseStats->size(); i++) { + for (size_t i = 0; i < elseStats->size(); i++) { Ref stat = deStat(elseStats[i]); if (stat[0] == ASSIGN && stat[2][0] == NAME) { if (indexOf(loopers, stat[2][1]->getIString()) >= 0) { @@ -2089,7 +2089,7 @@ void simplifyIfs(Ref ast) { if (stats->size() > 1) { // try to commaify - turn everything between the ifs into a comma operator inside the second if bool ok = true; - for (int i = 0; i < stats->size()-1; i++) { + for (size_t i = 0; i+1 < stats->size(); i++) { Ref curr = deStat(stats[i]); if (!commable(curr)) ok = false; } @@ -2154,7 +2154,7 @@ void simplifyIfs(Ref ast) { if (node[0] == WHILE) inLoop++; Ref stats = getStatements(node); if (!!stats && stats->size() > 0) { - for (int i = 0; i < stats->size()-1; i++) { + for (int i = 0; i < (int)stats->size()-1; i++) { Ref pre = stats[i]; Ref post = stats[i+1]; if (pre[0] == IF && pre->size() > 3 && !!pre[3] && post[0] == IF && (post->size() <= 3 || !post[3])) { @@ -2349,7 +2349,7 @@ void registerize(Ref ast) { } else if (type == SWITCH) { traversePrePostConditional(node[1], possibilifier, [](Ref node){}); Ref cases = node[2]; - for (int i = 0; i < cases->size(); i++) { + for (size_t i = 0; i < cases->size(); i++) { level++; traversePrePostConditional(cases[i][1], possibilifier, [](Ref node){}); purgeLevel(); @@ -2419,7 +2419,7 @@ void registerize(Ref ast) { } else { // when the relevant loop is exited, we will free the register int relevantLoop = optimizables.has(name) ? (optimizableLoops[name] ? optimizableLoops[name] : 1) : 1; - if (loopRegs.size() <= relevantLoop+1) loopRegs.resize(relevantLoop+1); + if ((int)loopRegs.size() <= relevantLoop+1) loopRegs.resize(relevantLoop+1); loopRegs[relevantLoop].push_back(reg); } } @@ -2445,7 +2445,7 @@ void registerize(Ref ast) { Ref type = node[0]; if (LOOP.has(type)) { // Free registers that were locked to this loop - if (loopRegs.size() > loops && loopRegs[loops].size() > 0) { + if ((int)loopRegs.size() > loops && loopRegs[loops].size() > 0) { for (auto loopReg : loopRegs[loops]) { freeRegsClasses[regTypes[loopReg]].push_back(loopReg); } @@ -2755,7 +2755,7 @@ void registerizeHarder(Ref ast) { assert(jEntry == ENTRY_JUNCTION); int jExit = addJunction(); assert(jExit == EXIT_JUNCTION); - for (int i = 0; i < node[3]->size(); i++) { + for (size_t i = 0; i < node[3]->size(); i++) { buildFlowGraph(node[3][i]); } joinJunction(jExit, false); @@ -2905,7 +2905,7 @@ void registerizeHarder(Ref ast) { int jExit = addJunction(); pushActiveLabels(-1, jExit); bool hasDefault = false; - for (int i = 0; i < node[2]->size(); i++) { + for (size_t i = 0; i < node[2]->size(); i++) { setJunction(jCheckExit, false); // All case clauses are either 'default' or a numeric literal. if (!node[2][i][0]) { @@ -2916,7 +2916,7 @@ void registerizeHarder(Ref ast) { addBlockLabel(lookThroughCasts(node[2][i][0])); } } - for (int j = 0; j < node[2][i][1]->size(); j++) { + for (size_t j = 0; j < node[2][i][1]->size(); j++) { buildFlowGraph(node[2][i][1][j]); } // Control flow will never actually reach the end of the case body. @@ -2958,7 +2958,7 @@ void registerizeHarder(Ref ast) { addUseNode(node); } else if (type == BLOCK || type == TOPLEVEL) { if (!!node[1]) { - for (int i = 0; i < node[1]->size(); i++) { + for (size_t i = 0; i < node[1]->size(); i++) { buildFlowGraph(node[1][i]); } } @@ -2977,7 +2977,7 @@ void registerizeHarder(Ref ast) { isInExpr++; buildFlowGraph(node[1]); if (!!node[2]) { - for (int i = 0; i < node[2]->size(); i++) { + for (size_t i = 0; i < node[2]->size(); i++) { buildFlowGraph(node[2][i]); } } @@ -3020,7 +3020,7 @@ void registerizeHarder(Ref ast) { typedef std::pair Jump; std::vector labelledJumps; - for (int i = 0; i < blocks.size(); i++) { + for (size_t i = 0; i < blocks.size(); i++) { Block* block = blocks[i]; // Does it have any labels as preconditions to its entry? for (auto labelVal : block->labels) { @@ -3050,7 +3050,7 @@ void registerizeHarder(Ref ast) { // If label is assigned a non-zero value elsewhere in the block // then all bets are off. This can happen e.g. due to outlining // saving/restoring label to the stack. - for (int j = 0; j < block->nodes.size() - 1; j++) { + for (size_t j = 0; j < block->nodes.size() - 1; j++) { if (block->nodes[j][0] == ASSIGN && block->nodes[j][2][1] == LABEL) { if (block->nodes[j][3][0] != NUM || block->nodes[j][3][1]->getNumber() != 0) { labelledBlocks.clear(); @@ -3077,7 +3077,7 @@ void registerizeHarder(Ref ast) { block->nodes.insert(block->nodes.begin(), makeName(LABEL)); block->isexpr.insert(block->isexpr.begin(), 1); } - for (int i = 0; i < labelledJumps.size(); i++) { + for (size_t i = 0; i < labelledJumps.size(); i++) { auto labelVal = labelledJumps[i].first; auto block = labelledJumps[i].second; Block* targetBlock = labelledBlocks[labelVal->getNumber()]; @@ -3302,7 +3302,7 @@ void registerizeHarder(Ref ast) { junctionVariables[name].conf.reserve(asmData.locals.size()); }; - for (int i = 0; i < junctions.size(); i++) { + for (size_t i = 0; i < junctions.size(); i++) { Junction& junc = junctions[i]; for (auto name : junc.live) { if (junctionVariables.count(name) == 0) initializeJunctionVariable(name); @@ -3378,7 +3378,7 @@ void registerizeHarder(Ref ast) { } return true; }; - for (int i = 0; i < sortedJunctionVariables.size(); i++) { + for (size_t i = 0; i < sortedJunctionVariables.size(); i++) { IString name = sortedJunctionVariables[i]; // It may already be assigned due to linked-variable propagation. if (junctionVariables[name].reg > 0) { @@ -3404,7 +3404,7 @@ void registerizeHarder(Ref ast) { // that all inter-block variables are in a good state thanks to // junction variable consistency. - for (int i = 0; i < blocks.size(); i++) { + for (size_t i = 0; i < blocks.size(); i++) { Block* block = blocks[i]; if (block->nodes.size() == 0) continue; Junction& jEnter = junctions[block->entry]; @@ -3450,7 +3450,7 @@ void registerizeHarder(Ref ast) { } std::vector> freeRegsByType; freeRegsByType.resize(freeRegsByTypePre.size()); - for (int j = 0; j < freeRegsByTypePre.size(); j++) { + for (size_t j = 0; j < freeRegsByTypePre.size(); j++) { for (auto pair : freeRegsByTypePre[j]) { freeRegsByType[j].push_back(pair.first); } @@ -3516,7 +3516,7 @@ void registerizeHarder(Ref ast) { } } // If we managed to create any "x=x" assignments, remove them. - for (int j = 0; j < maybeRemoveNodes.size(); j++) { + for (size_t j = 0; j < maybeRemoveNodes.size(); j++) { Ref node = maybeRemoveNodes[j].second; if (node[2][1] == node[3][1]) { if (block->isexpr[maybeRemoveNodes[j].first]) { @@ -3532,7 +3532,7 @@ void registerizeHarder(Ref ast) { StringSet paramRegs; if (!!fun[2]) { - for (int i = 0; i < fun[2]->size(); i++) { + for (size_t i = 0; i < fun[2]->size(); i++) { auto& allRegs = allRegsByType[asmData.getType(fun[2][i]->getIString())]; fun[2][i]->setString(allRegs[junctionVariables[fun[2][i]->getIString()].reg]); paramRegs.insert(fun[2][i]->getIString()); @@ -3546,7 +3546,7 @@ void registerizeHarder(Ref ast) { asmData.params.clear(); asmData.vars.clear(); for (int i = 1; i < nextReg; i++) { - for (int type = 0; type < allRegsByType.size(); type++) { + for (size_t type = 0; type < allRegsByType.size(); type++) { if (allRegsByType[type].count(i) > 0) { IString reg = allRegsByType[type][i]; if (!paramRegs.has(reg)) { @@ -3577,11 +3577,11 @@ void ensureMinifiedNames(int n) { // make sure the nth index in minifiedNames ex static int VALID_MIN_INITS_LEN = strlen(VALID_MIN_INITS); static int VALID_MIN_LATERS_LEN = strlen(VALID_MIN_LATERS); - while (minifiedNames.size() < n+1) { + while ((int)minifiedNames.size() < n+1) { // generate the current name std::string name; name += VALID_MIN_INITS[minifiedState[0]]; - for (int i = 1; i < minifiedState.size(); i++) { + for (size_t i = 1; i < minifiedState.size(); i++) { name += VALID_MIN_LATERS[minifiedState[i]]; } IString str(strdupe(name.c_str())); // leaked! @@ -3666,7 +3666,7 @@ void minifyLocals(Ref ast) { assert(!!fun[1]); } if (!!fun[2]) { - for (int i = 0; i < fun[2]->size(); i++) { + for (size_t i = 0; i < fun[2]->size(); i++) { IString minified = getNextMinifiedName(); newNames[fun[2][i]->getIString()] = minified; fun[2][i]->setString(minified); @@ -3685,7 +3685,7 @@ void minifyLocals(Ref ast) { node[1]->setString(minified); } } else if (type == VAR) { - for (int i = 0; i < node[1]->size(); i++) { + for (size_t i = 0; i < node[1]->size(); i++) { Ref defn = node[1][i]; IString name = defn[0]->getIString(); if (!(newNames.has(name))) { @@ -3765,7 +3765,7 @@ void asmLastOpts(Ref ast) { int me = parent->indexOf(node); if (me < 0) return; // not always directly on a stats, could be in a label for example parent->insert(me+1, lastStats->size()-1); - for (int i = 0; i < lastStats->size()-1; i++) { + for (size_t i = 0; i+1 < lastStats->size(); i++) { parent[me+1+i] = lastStats[i]; } } diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index 308cc9c323835..386dc899acd33 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -687,11 +687,11 @@ class Parser { if (parts[i].isNode) continue; IString op = parts[i].getOp(); if (!ops.ops.has(op)) continue; - if (ops.type == OperatorClass::Binary && i > 0 && i < parts.size()-1) { + if (ops.type == OperatorClass::Binary && i > 0 && i < (int)parts.size()-1) { parts[i] = Builder::makeBinary(parts[i-1].getNode(), op, parts[i+1].getNode()); parts.erase(parts.begin() + i + 1); parts.erase(parts.begin() + i - 1); - } else if (ops.type == OperatorClass::Prefix && i < parts.size()-1) { + } else if (ops.type == OperatorClass::Prefix && i < (int)parts.size()-1) { if (i > 0 && parts[i-1].isNode) continue; // cannot apply prefix operator if it would join two nodes parts[i] = Builder::makePrefix(op, parts[i+1].getNode()); parts.erase(parts.begin() + i + 1); @@ -700,7 +700,7 @@ class Parser { // ^ //dumpParts(parts, i); if (op != COLON) continue; - assert(i < parts.size()-1 && i >= 3); + assert(i < (int)parts.size()-1 && i >= 3); if (parts[i-2].getOp() != QUESTION) continue; // e.g. x ? y ? 1 : 0 : 2 parts[i-3] = Builder::makeConditional(parts[i-3].getNode(), parts[i-1].getNode(), parts[i+1].getNode()); parts.erase(parts.begin() + i - 2, parts.begin() + i + 2); @@ -709,16 +709,16 @@ class Parser { } } else { // left to right - for (int i = 0; i < parts.size(); i++) { + for (int i = 0; i < (int)parts.size(); i++) { if (parts[i].isNode) continue; IString op = parts[i].getOp(); if (!ops.ops.has(op)) continue; - if (ops.type == OperatorClass::Binary && i > 0 && i < parts.size()-1) { + if (ops.type == OperatorClass::Binary && i > 0 && i < (int)parts.size()-1) { parts[i] = Builder::makeBinary(parts[i-1].getNode(), op, parts[i+1].getNode()); parts.erase(parts.begin() + i + 1); parts.erase(parts.begin() + i - 1); i--; - } else if (ops.type == OperatorClass::Prefix && i < parts.size()-1) { + } else if (ops.type == OperatorClass::Prefix && i < (int)parts.size()-1) { if (i > 0 && parts[i-1].isNode) continue; // cannot apply prefix operator if it would join two nodes parts[i] = Builder::makePrefix(op, parts[i+1].getNode()); parts.erase(parts.begin() + i + 1); diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index 4d7a9b9cb859d..14280b8358314 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -122,7 +122,7 @@ void traversePre(Ref node, std::function visit) { stack.push_back({ node, 0 }); while (stack.size() > 0) { TraverseInfo& top = stack.back(); - if (top.index < top.node->size()) { + if (top.index < (int)top.node->size()) { Ref sub = top.node[top.index]; top.index++; if (visitable(sub)) { @@ -143,7 +143,7 @@ void traversePrePost(Ref node, std::function visitPre, std::function stack.push_back({ node, 0 }); while (stack.size() > 0) { TraverseInfo& top = stack.back(); - if (top.index < top.node->size()) { + if (top.index < (int)top.node->size()) { Ref sub = top.node[top.index]; top.index++; if (visitable(sub)) { @@ -166,7 +166,7 @@ void traversePrePostConditional(Ref node, std::function visitPre, st stack.push_back({ node, 0 }); while (stack.size() > 0) { TraverseInfo& top = stack.back(); - if (top.index < top.node->size()) { + if (top.index < (int)top.node->size()) { Ref sub = top.node[top.index]; top.index++; if (visitable(sub)) { @@ -187,7 +187,7 @@ void traverseFunctions(Ref ast, std::function visit) { if (!ast || ast->size() == 0) return; if (ast[0] == TOPLEVEL) { Ref stats = ast[1]; - for (int i = 0; i < stats->size(); i++) { + for (size_t i = 0; i < stats->size(); i++) { Ref curr = stats[i]; if (curr[0] == DEFUN) visit(curr); } diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index dd7654f4c6865..d9e1eaae46e3b 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -698,7 +698,7 @@ struct JSPrinter { void printStats(Ref stats) { bool first = true; - for (int i = 0; i < stats->size(); i++) { + for (size_t i = 0; i < stats->size(); i++) { Ref curr = stats[i]; if (!isNothing(curr)) { if (first) first = false; @@ -731,7 +731,7 @@ struct JSPrinter { emit(node[1]->getCString()); emit('('); Ref args = node[2]; - for (int i = 0; i < args->size(); i++) { + for (size_t i = 0; i < args->size(); i++) { if (i > 0) (pretty ? emit(", ") : emit(',')); emit(args[i]->getCString()); } @@ -993,7 +993,7 @@ struct JSPrinter { printChild(node[1], node, 0); emit('('); Ref args = node[2]; - for (int i = 0; i < args->size(); i++) { + for (size_t i = 0; i < args->size(); i++) { if (i > 0) (pretty ? emit(", ") : emit(',')); printChild(args[i], node, 0); } @@ -1023,7 +1023,7 @@ struct JSPrinter { emit('{'); newline(); Ref cases = node[2]; - for (int i = 0; i < cases->size(); i++) { + for (size_t i = 0; i < cases->size(); i++) { Ref c = cases[i]; if (!c[0]) { emit("default:"); @@ -1057,7 +1057,7 @@ struct JSPrinter { void printVar(Ref node) { emit("var "); Ref args = node[1]; - for (int i = 0; i < args->size(); i++) { + for (size_t i = 0; i < args->size(); i++) { if (i > 0) (pretty ? emit(", ") : emit(',')); emit(args[i][0]->getCString()); if (args[i]->size() > 1) { @@ -1165,7 +1165,7 @@ struct JSPrinter { void printArray(Ref node) { emit('['); Ref args = node[1]; - for (int i = 0; i < args->size(); i++) { + for (size_t i = 0; i < args->size(); i++) { if (i > 0) (pretty ? emit(", ") : emit(',')); print(args[i]); } @@ -1177,7 +1177,7 @@ struct JSPrinter { indent++; newline(); Ref args = node[1]; - for (int i = 0; i < args->size(); i++) { + for (size_t i = 0; i < args->size(); i++) { if (i > 0) { pretty ? emit(", ") : emit(','); newline(); @@ -1388,7 +1388,7 @@ class ValueBuilder { assert(switch_[0] == SWITCH); assert(code[0] == BLOCK); if (!explicitBlock) { - for (int i = 0; i < code[1]->size(); i++) { + for (size_t i = 0; i < code[1]->size(); i++) { switch_[2]->back()->back()->push_back(code[1][i]); } } else { From 768db6652ec01ebfbf12c4104d711499a77f094d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:18:59 -0500 Subject: [PATCH 20/75] Add CMakeLists.txt for building native optimizer. --- tools/optimizer/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tools/optimizer/CMakeLists.txt diff --git a/tools/optimizer/CMakeLists.txt b/tools/optimizer/CMakeLists.txt new file mode 100644 index 0000000000000..e9a62ad264147 --- /dev/null +++ b/tools/optimizer/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +project(asmjs_optimizer) + +file(GLOB sourceFiles *.cpp) +file(GLOB headerFiles *.h) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${cFlags}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cFlags}") + +add_executable(optimizer ${sourceFiles} ${headerFiles}) From 38c15f09fe156965ca4f28a0960b73526ae9d2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:19:24 -0500 Subject: [PATCH 21/75] Pass proper C++11 build flags to native optimizer CMake script. --- tools/optimizer/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/optimizer/CMakeLists.txt b/tools/optimizer/CMakeLists.txt index e9a62ad264147..7f01126a271ab 100644 --- a/tools/optimizer/CMakeLists.txt +++ b/tools/optimizer/CMakeLists.txt @@ -5,6 +5,16 @@ project(asmjs_optimizer) file(GLOB sourceFiles *.cpp) file(GLOB headerFiles *.h) +if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER MATCHES ".*(gcc|clang|emcc).*" OR CMAKE_C_COMPILER_ID MATCHES ".*(GCC|Clang|emcc).*") + set(IS_GCC_LIKE TRUE) +else() + set(IS_GCC_LIKE FALSE) +endif() + +if (IS_GCC_LIKE) + set(cFlags "-std=c++11 -fno-exceptions -fno-rtti") +endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${cFlags}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cFlags}") From 4799ff7bc9338490efb1356b30578e71e5607941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:19:45 -0500 Subject: [PATCH 22/75] Clean up Visual Studio build warnings in native optimizer CMakeLists.txt. --- tools/optimizer/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/optimizer/CMakeLists.txt b/tools/optimizer/CMakeLists.txt index 7f01126a271ab..f7f2d08220b80 100644 --- a/tools/optimizer/CMakeLists.txt +++ b/tools/optimizer/CMakeLists.txt @@ -15,6 +15,10 @@ if (IS_GCC_LIKE) set(cFlags "-std=c++11 -fno-exceptions -fno-rtti") endif() +if (MSVC) + set(cFlags "${cFlags} -D_CRT_SECURE_NO_WARNINGS=1") +endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${cFlags}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cFlags}") From e4b477f5b8aca563f9d256cdf5ad1705ec1a23d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:20:37 -0500 Subject: [PATCH 23/75] Remove unreferenced local variable in optimizer.cpp. --- tools/optimizer/optimizer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index b3332a5473d10..4e0688622e6d6 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2277,7 +2277,6 @@ void registerize(Ref ast) { removeAllUselessSubNodes(fun); // vacuum? StringTypeMap regTypes; // reg name -> type auto getNewRegName = [&](int num, IString name) { - const char *str; AsmType type = asmData.getType(name); IString ret = getRegName(type, num); assert(!allVars.has(ret) || asmData.isLocal(ret)); // register must not shadow non-local name From 2d10a049eaed1ed835f595eb2392a6c63135bf7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 17:23:42 -0500 Subject: [PATCH 24/75] Clean up warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning). --- tools/optimizer/simple_ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index 14280b8358314..857eba0def5c2 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -16,7 +16,7 @@ bool Ref::operator==(const char *str) { } bool Ref::operator!=(const char *str) { - return get()->isString() ? strcmp(get()->str.str, str) : true; + return get()->isString() ? !!strcmp(get()->str.str, str) : true; } bool Ref::operator==(const IString &str) { From 5491943068d0004a21b5d15cb9421391c88b70fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 18:30:09 -0500 Subject: [PATCH 25/75] Retain IString str; inside the anonymous union in struct Value on non-MSVC compilers. --- tools/optimizer/simple_ast.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index d9e1eaae46e3b..dcde53572c0d8 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -82,8 +82,13 @@ struct Value { typedef std::vector ArrayStorage; typedef std::unordered_map ObjectStorage; +#ifdef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf IString str; +#endif union { // TODO: optimize +#ifndef _MSC_VER + IString str; +#endif double num; ArrayStorage *arr; bool boo; From f4e6c9654194030b656e1ae6901b3d672e1f5d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 18 Dec 2014 18:58:53 -0500 Subject: [PATCH 26/75] Document how to build native optimizer with CMake in embuilder.py. --- embuilder.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embuilder.py b/embuilder.py index 7d5ba2be174d6..931c655d413df 100755 --- a/embuilder.py +++ b/embuilder.py @@ -33,6 +33,16 @@ zlib sdl2 sdl2-image + +It is also possible to build native_optimizer manually by using CMake. To +do that, run + + 1. cd $EMSCRIPTEN/tools/optimizer + 2. cmake . -DCMAKE_BUILD_TYPE=Release + 3. make (or mingw32-make/vcbuild/msbuild on Windows) + +and set up the location to the native optimizer in ~/.emscripten + ''' sys.exit(0) From a56e635043a67f0ef6eb0e1c7ed38d90dc31986f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 18 Dec 2014 16:34:23 -0800 Subject: [PATCH 27/75] avoid some compilation warnings, and assert on expected integers being integers; fixes #3089 --- tools/optimizer/optimizer.cpp | 14 +++++++------- tools/optimizer/simple_ast.h | 7 +++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 4e0688622e6d6..4b9dd84113baa 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2123,7 +2123,7 @@ void simplifyIfs(Ref ast) { traversePre(func, [&labelAssigns, &abort](Ref node) { if (node[0] == ASSIGN && node[2][0] == NAME && node[2][1] == LABEL) { if (node[3][0] == NUM) { - int value = node[3][1]->getNumber(); + int value = node[3][1]->getInteger(); labelAssigns[value] = labelAssigns[value] + 1; } else { // label is assigned a dynamic value (like from indirectbr), we cannot do anything @@ -2139,7 +2139,7 @@ void simplifyIfs(Ref ast) { if (node[0] == BINARY && node[1] == EQ && node[2][0] == BINARY && node[2][1] == OR && node[2][2][0] == NAME && node[2][2][1] == LABEL) { if (node[3][0] == NUM) { - int value = node[3][1]->getNumber(); + int value = node[3][1]->getInteger(); labelChecks[value] = labelChecks[value] + 1; } else { // label is checked vs a dynamic value (like from indirectbr), we cannot do anything @@ -2164,7 +2164,7 @@ void simplifyIfs(Ref ast) { postCond[2][2][0] == NAME && postCond[2][2][1] == LABEL && postCond[2][3][0] == NUM && postCond[2][3][1]->getNumber() == 0 && postCond[3][0] == NUM) { - double postValue = postCond[3][1]->getNumber(); + int postValue = postCond[3][1]->getInteger(); Ref preElse = pre[3]; if (labelAssigns[postValue] == 1 && labelChecks[postValue] == 1 && preElse[0] == BLOCK && preElse->size() >= 2 && preElse[1]->size() == 1) { Ref preStat = preElse[1][0]; @@ -2687,7 +2687,7 @@ void registerizeHarder(Ref ast) { IString name = node[1]->getIString(); if (asmData.isLocal(name)) { nextBasicBlock->nodes.push_back(node); - nextBasicBlock->isexpr.push_back(isInExpr); + nextBasicBlock->isexpr.push_back(bool(isInExpr)); if (nextBasicBlock->kill.count(name) == 0) { nextBasicBlock->use[name] = 1; } @@ -2702,7 +2702,7 @@ void registerizeHarder(Ref ast) { IString name = node[2][1]->getIString(); if (asmData.isLocal(name)) { nextBasicBlock->nodes.push_back(node); - nextBasicBlock->isexpr.push_back(isInExpr); + nextBasicBlock->isexpr.push_back(bool(isInExpr)); nextBasicBlock->kill.insert(name); } }; @@ -2720,7 +2720,7 @@ void registerizeHarder(Ref ast) { auto addBlockLabel = [&](Ref node) { assert(nextBasicBlock->nodes.size() == 0); // 'cant add label to an in-progress basic block') if (node[0] == NUM) { - nextBasicBlock->labels.insert(node[1]->getNumber()); + nextBasicBlock->labels.insert(node[1]->getInteger()); } }; @@ -3079,7 +3079,7 @@ void registerizeHarder(Ref ast) { for (size_t i = 0; i < labelledJumps.size(); i++) { auto labelVal = labelledJumps[i].first; auto block = labelledJumps[i].second; - Block* targetBlock = labelledBlocks[labelVal->getNumber()]; + Block* targetBlock = labelledBlocks[labelVal->getInteger()]; if (targetBlock) { // Redirect its exit to entry of the target block. junctions[block->exit].inblocks.erase(block->id); diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index dcde53572c0d8..5f8cc587b1828 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -199,6 +199,13 @@ struct Value { return boo; } + int getInteger() { // convenience function to get a known integer + assert(fmod(getNumber(), 1) == 0); + int ret = int(getNumber()); + assert(double(ret) == getNumber()); // no loss in conversion + return ret; + } + Value& operator=(const Value& other) { free(); switch (other.type) { From 46252990230e78ef9594b568f7327707c055caa3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 18 Dec 2014 17:05:30 -0800 Subject: [PATCH 28/75] Fix _mm_ucomile_ss and _mm_ucomilt_ss Implement proper NaN handling for _mm_ucomile_ss and _mm_ucomilt_ss and enable their tests. --- system/include/emscripten/xmmintrin.h | 4 ++-- tests/test_sse1.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/system/include/emscripten/xmmintrin.h b/system/include/emscripten/xmmintrin.h index 55ae928c8adba..96a9ed2c87a00 100644 --- a/system/include/emscripten/xmmintrin.h +++ b/system/include/emscripten/xmmintrin.h @@ -553,13 +553,13 @@ _mm_ucomigt_ss(__m128 __a, __m128 __b) static __inline__ int __attribute__((__always_inline__)) _mm_ucomile_ss(__m128 __a, __m128 __b) { - return __a[0] <= __b[0]; + return !(__a[0] > __b[0]); } static __inline__ int __attribute__((__always_inline__)) _mm_ucomilt_ss(__m128 __a, __m128 __b) { - return __a[0] < __b[0]; + return !(__a[0] >= __b[0]); } static __inline__ int __attribute__((__always_inline__)) diff --git a/tests/test_sse1.cpp b/tests/test_sse1.cpp index 2fd2e937bd93f..87680279bc0d7 100644 --- a/tests/test_sse1.cpp +++ b/tests/test_sse1.cpp @@ -270,10 +270,12 @@ int main() // exception when one of the input operands is either a QNaN or a SNaN. #ifndef __EMSCRIPTEN__ // TODO: Fix ucomi support in SSE to treat NaNs properly. Assert(_mm_ucomieq_ss(a, b) == 0); Assert(_mm_ucomieq_ss(a, a) == 1); Assert(_mm_ucomieq_ss(a, nan1) == 1); +#endif Assert(_mm_ucomige_ss(a, b) == 0); Assert(_mm_ucomige_ss(a, a) == 1); Assert(_mm_ucomige_ss(a, nan1) == 0); Assert(_mm_ucomigt_ss(b, a) == 1); Assert(_mm_ucomigt_ss(a, a) == 0); Assert(_mm_ucomigt_ss(a, nan1) == 0); Assert(_mm_ucomile_ss(b, a) == 0); Assert(_mm_ucomile_ss(a, a) == 1); Assert(_mm_ucomile_ss(a, nan1) == 1); Assert(_mm_ucomilt_ss(a, b) == 1); Assert(_mm_ucomilt_ss(a, a) == 0); Assert(_mm_ucomilt_ss(a, nan1) == 1); +#ifndef __EMSCRIPTEN__ // TODO: Fix ucomi support in SSE to treat NaNs properly. Assert(_mm_ucomineq_ss(a, b) == 1); Assert(_mm_ucomineq_ss(a, a) == 0); Assert(_mm_ucomineq_ss(a, nan1) == 0); #endif From 812a76939c614dd7233ab474a6d70d19c914ddca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 10:27:34 -0500 Subject: [PATCH 29/75] Clean up Visual Studio int to bool cast warnings. --- tools/optimizer/optimizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 4b9dd84113baa..7af9c5f51fa7a 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2687,7 +2687,7 @@ void registerizeHarder(Ref ast) { IString name = node[1]->getIString(); if (asmData.isLocal(name)) { nextBasicBlock->nodes.push_back(node); - nextBasicBlock->isexpr.push_back(bool(isInExpr)); + nextBasicBlock->isexpr.push_back(isInExpr != 0); if (nextBasicBlock->kill.count(name) == 0) { nextBasicBlock->use[name] = 1; } @@ -2702,7 +2702,7 @@ void registerizeHarder(Ref ast) { IString name = node[2][1]->getIString(); if (asmData.isLocal(name)) { nextBasicBlock->nodes.push_back(node); - nextBasicBlock->isexpr.push_back(bool(isInExpr)); + nextBasicBlock->isexpr.push_back(isInExpr != 0); nextBasicBlock->kill.insert(name); } }; From 775009c3ac61d76f8687a211eb3f0121a43acedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 10:36:34 -0500 Subject: [PATCH 30/75] Fix file reading to string on Windows by using binary read mode to avoid the return value from ftell() to differ from the number of bytes read by fread() due to length mismatches caused by \r\n vs \n conversion when reading in ascii mode. --- tools/optimizer/optimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 7af9c5f51fa7a..66ded7d1485a9 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -3829,7 +3829,7 @@ int main(int argc, char **argv) { } // Read input file - FILE *f = fopen(argv[1], "r"); + FILE *f = fopen(argv[1], "rb"); assert(f); fseek(f, 0, SEEK_END); int size = ftell(f); From 2bb3bcfbbf18c2516e17675da782bd903e633fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 10:38:54 -0500 Subject: [PATCH 31/75] Add support for reading the location of the native optimizer from EMSCRIPTEN_NATIVE_OPTIMIZER environment variable. --- tools/js_optimizer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 034709007cbc2..2db839e29208a 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -30,6 +30,8 @@ def path_from_root(*pathelems): def get_native_optimizer(): if os.environ.get('EMCC_FAST_COMPILER') == '0': return None # need fastcomp for native optimizer + if len(os.environ.get('EMSCRIPTEN_NATIVE_OPTIMIZER')) > 0: return os.environ.get('EMSCRIPTEN_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 (run emcc --clear-cache or erase "optimizer.building_failed" in cache dir to retry)') From 21e5be3156c17e93856d6208aa4de25e568d2ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 10:52:42 -0500 Subject: [PATCH 32/75] Allow specifying EMSCRIPTEN_NATIVE_OPTIMIZER in .emscripten to configure the location of the native optimizer. --- tools/js_optimizer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 2db839e29208a..c9b1dab49566c 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -30,7 +30,10 @@ def path_from_root(*pathelems): def get_native_optimizer(): if os.environ.get('EMCC_FAST_COMPILER') == '0': return None # need fastcomp for native optimizer - if len(os.environ.get('EMSCRIPTEN_NATIVE_OPTIMIZER')) > 0: return os.environ.get('EMSCRIPTEN_NATIVE_OPTIMIZER') + # Allow users to override the location of the optimizer executable by setting an environment variable EMSCRIPTEN_NATIVE_OPTIMIZER=/path/to/optimizer(.exe) + if os.environ.get('EMSCRIPTEN_NATIVE_OPTIMIZER') and len(os.environ.get('EMSCRIPTEN_NATIVE_OPTIMIZER')) > 0: return os.environ.get('EMSCRIPTEN_NATIVE_OPTIMIZER') + # Also, allow specifying the location of the optimizer in .emscripten configuration file under EMSCRIPTEN_NATIVE_OPTIMIZER='/path/to/optimizer' + if hasattr(shared, 'EMSCRIPTEN_NATIVE_OPTIMIZER') and len(shared.EMSCRIPTEN_NATIVE_OPTIMIZER) > 0: return shared.EMSCRIPTEN_NATIVE_OPTIMIZER FAIL_MARKER = shared.Cache.get_path('optimizer.building_failed') if os.path.exists(FAIL_MARKER): From bc934c00e9e3d17754b1c2cae4afb16c79379b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 10:54:56 -0500 Subject: [PATCH 33/75] Add a note comment to .emscripten template to remind to escape backslashes on Windows. --- tools/settings_template_readonly.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py index efaec8a3a11f2..31cf664ce0911 100644 --- a/tools/settings_template_readonly.py +++ b/tools/settings_template_readonly.py @@ -2,6 +2,8 @@ # Note: If you put paths relative to the home directory, do not forget os.path.expanduser +# Note: On Windows, remember to escape backslashes! I.e. EMSCRIPTEN_ROOT='c:\emscripten\' is not valid, but EMSCRIPTEN_ROOT='c:\\emscripten\\' and EMSCRIPTEN_ROOT='c:/emscripten/' are. + import os # this helps projects using emscripten find it From b6ba01012d79157dfd5d34394d9e4be54934e7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 10:57:16 -0500 Subject: [PATCH 34/75] Add a note to .emscripten config file on how to configure native optimizer location. --- tools/settings_template_readonly.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py index 31cf664ce0911..e4cb193314d2a 100644 --- a/tools/settings_template_readonly.py +++ b/tools/settings_template_readonly.py @@ -13,6 +13,10 @@ # If not specified, defaults to sys.executable. #PYTHON = 'python' +# Add this if you have manually built the JS optimizer executable (in Emscripten/tools/optimizer) and want to run it from a custom location. +# Alternatively, you can set this as the environment variable EMSCRIPTEN_NATIVE_OPTIMIZER. +# EMSCRIPTEN_NATIVE_OPTIMIZER='/path/to/custom/optimizer(.exe)' + # See below for notes on which JS engine(s) you need NODE_JS = os.path.expanduser(os.getenv('NODE') or '{{{ NODE }}}') # executable SPIDERMONKEY_ENGINE = [os.path.expanduser(os.getenv('SPIDERMONKEY') or 'js')] # executable From 27bd1042c162b1733f22b80027a1b0e7da8d6703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 11:19:03 -0500 Subject: [PATCH 35/75] Remove use of C++11 struct initializer lists to enable building JS optimizer with Visual Studio 2012 that does not support those. --- tools/optimizer/optimizer.cpp | 10 ++++++---- tools/optimizer/simple_ast.cpp | 14 ++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 66ded7d1485a9..1f0e9c37faf14 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -108,6 +108,8 @@ Ref make3(IString type, Ref a, Ref b, Ref c); struct AsmData { struct Local { + Local(){} + Local(AsmType type, bool param):type(type), param(param) {} AsmType type; bool param; // false if a var }; @@ -154,7 +156,7 @@ struct AsmData { if (index < 0) break; // not an assign into a parameter, but a global IString& str = name->getIString(); if (locals.count(str) > 0) break; // already done that param, must be starting function body - locals[str] = { detectType(node[3]), true }; + locals[str] = Local(detectType(node[3]), true); params.push_back(str); stats[i] = makeEmpty(); i++; @@ -168,7 +170,7 @@ struct AsmData { IString& name = v[0]->getIString(); Ref value = v[1]; if (locals.count(name) == 0) { - locals[name] = { detectType(value, nullptr, true), false }; + locals[name] = Local(detectType(value, nullptr, true), false); vars.push_back(name); v->setSize(1); // make an un-assigning var } else { @@ -262,11 +264,11 @@ struct AsmData { } void addParam(IString name, AsmType type) { - locals[name] = { type, true }; + locals[name] = Local(type, true); params.push_back(name); } void addVar(IString name, AsmType type) { - locals[name] = { type, false }; + locals[name] = Local(type, false); vars.push_back(name); } diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index 857eba0def5c2..24e229853cf4a 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -61,6 +61,8 @@ void dump(const char *str, Ref node, bool pretty) { // Traversals struct TraverseInfo { + TraverseInfo(){} + TraverseInfo(Ref node, int index):node(node), index(index){} Ref node; int index; }; @@ -119,7 +121,7 @@ void traversePre(Ref node, std::function visit) { if (!visitable(node)) return; visit(node); StackedStack stack; - stack.push_back({ node, 0 }); + stack.push_back(TraverseInfo(node, 0)); while (stack.size() > 0) { TraverseInfo& top = stack.back(); if (top.index < (int)top.node->size()) { @@ -127,7 +129,7 @@ void traversePre(Ref node, std::function visit) { top.index++; if (visitable(sub)) { visit(sub); - stack.push_back({ sub, 0 }); + stack.push_back(TraverseInfo(sub, 0)); } } else { stack.pop_back(); @@ -140,7 +142,7 @@ void traversePrePost(Ref node, std::function visitPre, std::function if (!visitable(node)) return; visitPre(node); StackedStack stack; - stack.push_back({ node, 0 }); + stack.push_back(TraverseInfo(node, 0)); while (stack.size() > 0) { TraverseInfo& top = stack.back(); if (top.index < (int)top.node->size()) { @@ -148,7 +150,7 @@ void traversePrePost(Ref node, std::function visitPre, std::function top.index++; if (visitable(sub)) { visitPre(sub); - stack.push_back({ sub, 0 }); + stack.push_back(TraverseInfo(sub, 0)); } } else { visitPost(top.node); @@ -163,7 +165,7 @@ void traversePrePostConditional(Ref node, std::function visitPre, st if (!visitable(node)) return; if (!visitPre(node)) return; StackedStack stack; - stack.push_back({ node, 0 }); + stack.push_back(TraverseInfo(node, 0)); while (stack.size() > 0) { TraverseInfo& top = stack.back(); if (top.index < (int)top.node->size()) { @@ -171,7 +173,7 @@ void traversePrePostConditional(Ref node, std::function visitPre, st top.index++; if (visitable(sub)) { if (visitPre(sub)) { - stack.push_back({ sub, 0 }); + stack.push_back(TraverseInfo(sub, 0)); } } } else { From c9f016aacf40d24a08d07a5f2f5a5b213041e348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 11:37:07 -0500 Subject: [PATCH 36/75] Fix warning from Visual Studio 2013 static code analyzer: curr may be 0. Operator new will instead throw an exception on failure. --- tools/optimizer/istring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/istring.h b/tools/optimizer/istring.h index bc525b50667ed..e795297385c08 100644 --- a/tools/optimizer/istring.h +++ b/tools/optimizer/istring.h @@ -121,7 +121,7 @@ class IStringSet : public std::unordered_set { IStringSet() {} IStringSet(const char *init) { // comma-delimited list int size = strlen(init); - char *curr = (char*)malloc(size+1); // leaked! + char *curr = new char[size+1]; // leaked! strcpy(curr, init); while (1) { char *end = strchr(curr, ' '); From a2d32b606d4a26ab29b8f463c5300b3beeb21db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 11:41:29 -0500 Subject: [PATCH 37/75] Fix static code analysis diagnostic found by cppcheck 1.67: [simple_ast.h:575]: (error) Common realloc mistake: 'buffer' nulled but not freed upon failure. --- tools/optimizer/simple_ast.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 5f8cc587b1828..9c4153da25ada 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -572,7 +572,13 @@ struct JSPrinter { if (!buffer) { buffer = (char*)malloc(size); } else { - buffer = (char*)realloc(buffer, size); + char *buf = (char*)realloc(buffer, size); + if (!buf) { + free(buffer); + printf("Out of memory allocating %d bytes for output buffer!", size); + assert(0); + } + buffer = buf; } } } From 25d507ebc622f45c0cdfdc010b171f7de406f863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 12:01:06 -0500 Subject: [PATCH 38/75] Make struct Frag ctor from string explicit for good form. --- tools/optimizer/parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index 386dc899acd33..ea133aa23888b 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -178,7 +178,7 @@ class Parser { int size; FragType type; - Frag(char* src) { + explicit Frag(char* src) { assert(!isSpace(*src)); char *start = src; if (isIdentInit(*src)) { From 3a573a3601d178aea2238886eb1673f59bbfd422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 12:14:11 -0500 Subject: [PATCH 39/75] Visual Studio 2013 and older do not support new C++11 functionality on strtod for parsing numbers as hex strings ("0x..."), so explicitly parse hex string numbers using strtoul instead, which supports hex strings in C++03 already. --- tools/optimizer/parser.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index ea133aa23888b..e427a0b0e1f95 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -203,7 +203,14 @@ class Parser { src = end+1; type = STRING; } else if (isDigit(*src) || (src[0] == '.' && isDigit(src[1]))) { - num = strtod(start, &src); + if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) { + // Explicitly parse hex numbers of form "0x...", because strtod + // supports hex number strings only in C++11, and Visual Studio 2013 does + // not yet support that functionality. + num = (double)strtoul(start, &src, 0); + } else { + num = strtod(start, &src); + } assert(src > start); type = NUMBER; } else if (hasChar(OPERATOR_INITS, *src)) { From d25cd57e42c515b410647f307aa93f611593137c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 12:39:24 -0500 Subject: [PATCH 40/75] Add an assert() to expose a failing condition on Windows during simplifyOps run. --- tools/optimizer/optimizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 1f0e9c37faf14..754e99c9e2973 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -1702,6 +1702,7 @@ void simplifyExpressions(Ref ast) { }; traversePrePost(ast, process, [&stack](Ref Node) { + assert(!stack.empty()); stack.pop_back(); }); } From c4da42a90bbbf2f1fa16e648b5df87885c6897db Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 10:29:59 -0800 Subject: [PATCH 41/75] standardize some whitespace --- tools/optimizer/optimizer.cpp | 4 ++-- tools/optimizer/simple_ast.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 754e99c9e2973..f898166a18ee1 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -108,8 +108,8 @@ Ref make3(IString type, Ref a, Ref b, Ref c); struct AsmData { struct Local { - Local(){} - Local(AsmType type, bool param):type(type), param(param) {} + Local() {} + Local(AsmType type, bool param) : type(type), param(param) {} AsmType type; bool param; // false if a var }; diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index 24e229853cf4a..dca58cb27efd9 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -61,8 +61,8 @@ void dump(const char *str, Ref node, bool pretty) { // Traversals struct TraverseInfo { - TraverseInfo(){} - TraverseInfo(Ref node, int index):node(node), index(index){} + TraverseInfo() {} + TraverseInfo(Ref node, int index) : node(node), index(index) {} Ref node; int index; }; From 43beb95a2bfa6c22c8e91ed849d8976cfca213f4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 10:32:58 -0800 Subject: [PATCH 42/75] add assert; fixes #3092 --- tools/optimizer/optimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index f898166a18ee1..bd4c3152a9aac 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -1960,7 +1960,7 @@ void simplifyExpressions(Ref ast) { switch(asmData.getType(v.c_str())) { case ASM_INT: correctType = preciseF32 ? ASM_FLOAT : ASM_DOUBLE; break; case ASM_FLOAT: case ASM_DOUBLE: correctType = ASM_INT; break; - default: {} // pass + default: assert(0); } asmData.setType(v.c_str(), correctType); } From d04756fd97c4977754c7d1dc133b629e13db6a1b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 11:41:22 -0800 Subject: [PATCH 43/75] fix hex parsing; fixes 3a573a3601d178aea2238886eb1673f59bbfd422 --- tools/optimizer/parser.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index e427a0b0e1f95..ff615218150e9 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -207,7 +207,15 @@ class Parser { // Explicitly parse hex numbers of form "0x...", because strtod // supports hex number strings only in C++11, and Visual Studio 2013 does // not yet support that functionality. - num = (double)strtoul(start, &src, 0); + src += 2; + num = 0; + while (1) { + if (*src >= '0' && *src <= '9') { num *= 16; num += *src - '0'; } + else if (*src >= 'a' && *src <= 'f') { num *= 16; num += *src - 'a' + 10; } + else if (*src >= 'A' && *src <= 'F') { num *= 16; num += *src - 'F' + 10; } + else break; + src++; + } } else { num = strtod(start, &src); } @@ -822,7 +830,7 @@ class Parser { for (int i = 0; i < (curr - allSource); i++) printf(" "); printf("^\n=============\n"); */ - printf("%s:\n==========\n", where); + fprintf(stderr, "%s:\n==========\n", where); int newlinesLeft = 2; int charsLeft = 200; while (*curr) { @@ -832,9 +840,9 @@ class Parser { } charsLeft--; if (charsLeft == 0) break; - printf("%c", *curr++); + fprintf(stderr, "%c", *curr++); } - printf("\n\n"); + fprintf(stderr, "\n\n"); } public: From 164d9060052a027b008ed34e0ac620cdadbc689e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 11:53:49 -0800 Subject: [PATCH 44/75] update cashew and add testing for the now fixed #3094 --- tools/optimizer/optimizer.cpp | 2 +- tools/optimizer/simple_ast.cpp | 2 -- tools/optimizer/simple_ast.h | 4 ++++ tools/test-js-optimizer-asm-pre-output.js | 1 + tools/test-js-optimizer-asm-pre-output2.js | 1 + tools/test-js-optimizer-asm-pre.js | 4 +++- 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index bd4c3152a9aac..463bbe74b68b6 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -1701,7 +1701,7 @@ void simplifyExpressions(Ref ast) { } }; - traversePrePost(ast, process, [&stack](Ref Node) { + traversePrePost(ast, process, [&stack](Ref node) { assert(!stack.empty()); stack.pop_back(); }); diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index dca58cb27efd9..c2170bf3cd9b5 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -157,7 +157,6 @@ void traversePrePost(Ref node, std::function visitPre, std::function stack.pop_back(); } } - visitPost(node); } // Traverse, calling visitPre before the children and visitPost after. If pre returns false, do not traverse children @@ -181,7 +180,6 @@ void traversePrePostConditional(Ref node, std::function visitPre, st stack.pop_back(); } } - visitPost(node); } // Traverses all the top-level functions in the document diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 9c4153da25ada..e47ae03dbb2a4 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -755,6 +755,10 @@ struct JSPrinter { } emit(')'); space(); + if (node->size() == 3 || node[3]->size() == 0) { + emit("{}"); + return; + } emit('{'); indent++; newline(); diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js index f0fcd43b2ae5c..5ba72dd342823 100644 --- a/tools/test-js-optimizer-asm-pre-output.js +++ b/tools/test-js-optimizer-asm-pre-output.js @@ -602,4 +602,5 @@ function bignum() { HEAP32[20] = -1515870811; if (($2814 | 0) < 0) return; } +function empty() {} diff --git a/tools/test-js-optimizer-asm-pre-output2.js b/tools/test-js-optimizer-asm-pre-output2.js index 2711d862bf071..2652ee8846091 100644 --- a/tools/test-js-optimizer-asm-pre-output2.js +++ b/tools/test-js-optimizer-asm-pre-output2.js @@ -602,4 +602,5 @@ function bignum() { HEAP32[20] = -1515870811; if (($2814 | 0) < 0) return; } +function empty() {} diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js index f93b1fbdc39d7..f9c6bc12ec32b 100644 --- a/tools/test-js-optimizer-asm-pre.js +++ b/tools/test-js-optimizer-asm-pre.js @@ -613,4 +613,6 @@ function bignum() { HEAP32[20] = 2779096485 | 0; if (!(($2814 | 0) >= 0)) return; } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "rett", "ret2t", "retf", "i32_8", "tempDoublePtr", "boxx", "_main", "badf", "badf2", "fcomp", "conditionalizeMe", "bignum"] +function empty() { +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "rett", "ret2t", "retf", "i32_8", "tempDoublePtr", "boxx", "_main", "badf", "badf2", "fcomp", "conditionalizeMe", "bignum", "empty"] From d9a99cbd83eebcb8f34f4dd878b2999d525ce540 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 14:17:42 -0800 Subject: [PATCH 45/75] add musl complex component; fixes #3091 --- system/lib/libc/musl/src/complex/__cexp.c | 87 +++++++++++++ system/lib/libc/musl/src/complex/__cexpf.c | 68 ++++++++++ system/lib/libc/musl/src/complex/cabs.c | 6 + system/lib/libc/musl/src/complex/cabsf.c | 6 + system/lib/libc/musl/src/complex/cabsl.c | 13 ++ system/lib/libc/musl/src/complex/cacos.c | 11 ++ system/lib/libc/musl/src/complex/cacosf.c | 9 ++ system/lib/libc/musl/src/complex/cacosh.c | 9 ++ system/lib/libc/musl/src/complex/cacoshf.c | 7 + system/lib/libc/musl/src/complex/cacoshl.c | 14 ++ system/lib/libc/musl/src/complex/cacosl.c | 16 +++ system/lib/libc/musl/src/complex/carg.c | 6 + system/lib/libc/musl/src/complex/cargf.c | 6 + system/lib/libc/musl/src/complex/cargl.c | 13 ++ system/lib/libc/musl/src/complex/casin.c | 16 +++ system/lib/libc/musl/src/complex/casinf.c | 14 ++ system/lib/libc/musl/src/complex/casinh.c | 9 ++ system/lib/libc/musl/src/complex/casinhf.c | 7 + system/lib/libc/musl/src/complex/casinhl.c | 14 ++ system/lib/libc/musl/src/complex/casinl.c | 20 +++ system/lib/libc/musl/src/complex/catan.c | 119 +++++++++++++++++ system/lib/libc/musl/src/complex/catanf.c | 115 +++++++++++++++++ system/lib/libc/musl/src/complex/catanh.c | 9 ++ system/lib/libc/musl/src/complex/catanhf.c | 7 + system/lib/libc/musl/src/complex/catanhl.c | 14 ++ system/lib/libc/musl/src/complex/catanl.c | 126 ++++++++++++++++++ system/lib/libc/musl/src/complex/ccos.c | 8 ++ system/lib/libc/musl/src/complex/ccosf.c | 6 + system/lib/libc/musl/src/complex/ccosh.c | 140 ++++++++++++++++++++ system/lib/libc/musl/src/complex/ccoshf.c | 90 +++++++++++++ system/lib/libc/musl/src/complex/ccoshl.c | 7 + system/lib/libc/musl/src/complex/ccosl.c | 13 ++ system/lib/libc/musl/src/complex/cexp.c | 83 ++++++++++++ system/lib/libc/musl/src/complex/cexpf.c | 83 ++++++++++++ system/lib/libc/musl/src/complex/cexpl.c | 7 + system/lib/libc/musl/src/complex/cimag.c | 6 + system/lib/libc/musl/src/complex/cimagf.c | 6 + system/lib/libc/musl/src/complex/cimagl.c | 6 + system/lib/libc/musl/src/complex/clog.c | 14 ++ system/lib/libc/musl/src/complex/clogf.c | 12 ++ system/lib/libc/musl/src/complex/clogl.c | 18 +++ system/lib/libc/musl/src/complex/conj.c | 6 + system/lib/libc/musl/src/complex/conjf.c | 6 + system/lib/libc/musl/src/complex/conjl.c | 6 + system/lib/libc/musl/src/complex/cpow.c | 8 ++ system/lib/libc/musl/src/complex/cpowf.c | 6 + system/lib/libc/musl/src/complex/cpowl.c | 13 ++ system/lib/libc/musl/src/complex/cproj.c | 8 ++ system/lib/libc/musl/src/complex/cprojf.c | 8 ++ system/lib/libc/musl/src/complex/cprojl.c | 15 +++ system/lib/libc/musl/src/complex/creal.c | 6 + system/lib/libc/musl/src/complex/crealf.c | 6 + system/lib/libc/musl/src/complex/creall.c | 6 + system/lib/libc/musl/src/complex/csin.c | 9 ++ system/lib/libc/musl/src/complex/csinf.c | 7 + system/lib/libc/musl/src/complex/csinh.c | 141 +++++++++++++++++++++ system/lib/libc/musl/src/complex/csinhf.c | 90 +++++++++++++ system/lib/libc/musl/src/complex/csinhl.c | 7 + system/lib/libc/musl/src/complex/csinl.c | 14 ++ system/lib/libc/musl/src/complex/csqrt.c | 100 +++++++++++++++ system/lib/libc/musl/src/complex/csqrtf.c | 82 ++++++++++++ system/lib/libc/musl/src/complex/csqrtl.c | 7 + system/lib/libc/musl/src/complex/ctan.c | 9 ++ system/lib/libc/musl/src/complex/ctanf.c | 7 + system/lib/libc/musl/src/complex/ctanh.c | 127 +++++++++++++++++++ system/lib/libc/musl/src/complex/ctanhf.c | 66 ++++++++++ system/lib/libc/musl/src/complex/ctanhl.c | 7 + system/lib/libc/musl/src/complex/ctanl.c | 14 ++ system/lib/libcextra.symbols | 68 ++++++++++ tests/test_core.py | 28 ++++ tools/system_libs.py | 70 ++++++++++ 71 files changed, 2187 insertions(+) create mode 100644 system/lib/libc/musl/src/complex/__cexp.c create mode 100644 system/lib/libc/musl/src/complex/__cexpf.c create mode 100644 system/lib/libc/musl/src/complex/cabs.c create mode 100644 system/lib/libc/musl/src/complex/cabsf.c create mode 100644 system/lib/libc/musl/src/complex/cabsl.c create mode 100644 system/lib/libc/musl/src/complex/cacos.c create mode 100644 system/lib/libc/musl/src/complex/cacosf.c create mode 100644 system/lib/libc/musl/src/complex/cacosh.c create mode 100644 system/lib/libc/musl/src/complex/cacoshf.c create mode 100644 system/lib/libc/musl/src/complex/cacoshl.c create mode 100644 system/lib/libc/musl/src/complex/cacosl.c create mode 100644 system/lib/libc/musl/src/complex/carg.c create mode 100644 system/lib/libc/musl/src/complex/cargf.c create mode 100644 system/lib/libc/musl/src/complex/cargl.c create mode 100644 system/lib/libc/musl/src/complex/casin.c create mode 100644 system/lib/libc/musl/src/complex/casinf.c create mode 100644 system/lib/libc/musl/src/complex/casinh.c create mode 100644 system/lib/libc/musl/src/complex/casinhf.c create mode 100644 system/lib/libc/musl/src/complex/casinhl.c create mode 100644 system/lib/libc/musl/src/complex/casinl.c create mode 100644 system/lib/libc/musl/src/complex/catan.c create mode 100644 system/lib/libc/musl/src/complex/catanf.c create mode 100644 system/lib/libc/musl/src/complex/catanh.c create mode 100644 system/lib/libc/musl/src/complex/catanhf.c create mode 100644 system/lib/libc/musl/src/complex/catanhl.c create mode 100644 system/lib/libc/musl/src/complex/catanl.c create mode 100644 system/lib/libc/musl/src/complex/ccos.c create mode 100644 system/lib/libc/musl/src/complex/ccosf.c create mode 100644 system/lib/libc/musl/src/complex/ccosh.c create mode 100644 system/lib/libc/musl/src/complex/ccoshf.c create mode 100644 system/lib/libc/musl/src/complex/ccoshl.c create mode 100644 system/lib/libc/musl/src/complex/ccosl.c create mode 100644 system/lib/libc/musl/src/complex/cexp.c create mode 100644 system/lib/libc/musl/src/complex/cexpf.c create mode 100644 system/lib/libc/musl/src/complex/cexpl.c create mode 100644 system/lib/libc/musl/src/complex/cimag.c create mode 100644 system/lib/libc/musl/src/complex/cimagf.c create mode 100644 system/lib/libc/musl/src/complex/cimagl.c create mode 100644 system/lib/libc/musl/src/complex/clog.c create mode 100644 system/lib/libc/musl/src/complex/clogf.c create mode 100644 system/lib/libc/musl/src/complex/clogl.c create mode 100644 system/lib/libc/musl/src/complex/conj.c create mode 100644 system/lib/libc/musl/src/complex/conjf.c create mode 100644 system/lib/libc/musl/src/complex/conjl.c create mode 100644 system/lib/libc/musl/src/complex/cpow.c create mode 100644 system/lib/libc/musl/src/complex/cpowf.c create mode 100644 system/lib/libc/musl/src/complex/cpowl.c create mode 100644 system/lib/libc/musl/src/complex/cproj.c create mode 100644 system/lib/libc/musl/src/complex/cprojf.c create mode 100644 system/lib/libc/musl/src/complex/cprojl.c create mode 100644 system/lib/libc/musl/src/complex/creal.c create mode 100644 system/lib/libc/musl/src/complex/crealf.c create mode 100644 system/lib/libc/musl/src/complex/creall.c create mode 100644 system/lib/libc/musl/src/complex/csin.c create mode 100644 system/lib/libc/musl/src/complex/csinf.c create mode 100644 system/lib/libc/musl/src/complex/csinh.c create mode 100644 system/lib/libc/musl/src/complex/csinhf.c create mode 100644 system/lib/libc/musl/src/complex/csinhl.c create mode 100644 system/lib/libc/musl/src/complex/csinl.c create mode 100644 system/lib/libc/musl/src/complex/csqrt.c create mode 100644 system/lib/libc/musl/src/complex/csqrtf.c create mode 100644 system/lib/libc/musl/src/complex/csqrtl.c create mode 100644 system/lib/libc/musl/src/complex/ctan.c create mode 100644 system/lib/libc/musl/src/complex/ctanf.c create mode 100644 system/lib/libc/musl/src/complex/ctanh.c create mode 100644 system/lib/libc/musl/src/complex/ctanhf.c create mode 100644 system/lib/libc/musl/src/complex/ctanhl.c create mode 100644 system/lib/libc/musl/src/complex/ctanl.c diff --git a/system/lib/libc/musl/src/complex/__cexp.c b/system/lib/libc/musl/src/complex/__cexp.c new file mode 100644 index 0000000000000..05ac28c75c627 --- /dev/null +++ b/system/lib/libc/musl/src/complex/__cexp.c @@ -0,0 +1,87 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_exp.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t k = 1799; /* constant for reduction */ +static const double kln2 = 1246.97177782734161156; /* k * ln2 */ + +/* + * Compute exp(x), scaled to avoid spurious overflow. An exponent is + * returned separately in 'expt'. + * + * Input: ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91 + * Output: 2**1023 <= y < 2**1024 + */ +static double __frexp_exp(double x, int *expt) +{ + double exp_x; + uint32_t hx; + + /* + * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to + * minimize |exp(kln2) - 2**k|. We also scale the exponent of + * exp_x to MAX_EXP so that the result can be multiplied by + * a tiny number without losing accuracy due to denormalization. + */ + exp_x = exp(x - kln2); + GET_HIGH_WORD(hx, exp_x); + *expt = (hx >> 20) - (0x3ff + 1023) + k; + SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20)); + return exp_x; +} + +/* + * __ldexp_cexp(x, expt) compute exp(x) * 2**expt. + * It is intended for large arguments (real part >= ln(DBL_MAX)) + * where care is needed to avoid overflow. + * + * The present implementation is narrowly tailored for our hyperbolic and + * exponential functions. We assume expt is small (0 or -1), and the caller + * has filtered out very large x, for which overflow would be inevitable. + */ +double complex __ldexp_cexp(double complex z, int expt) +{ + double x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = creal(z); + y = cimag(z); + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + + /* + * Arrange so that scale1 * scale2 == 2**expt. We use this to + * compensate for scalbn being horrendously slow. + */ + half_expt = expt / 2; + INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0); + half_expt = expt - half_expt; + INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0); + + return CMPLX(cos(y) * exp_x * scale1 * scale2, sin(y) * exp_x * scale1 * scale2); +} diff --git a/system/lib/libc/musl/src/complex/__cexpf.c b/system/lib/libc/musl/src/complex/__cexpf.c new file mode 100644 index 0000000000000..69b54045afd4a --- /dev/null +++ b/system/lib/libc/musl/src/complex/__cexpf.c @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_expf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t k = 235; /* constant for reduction */ +static const float kln2 = 162.88958740F; /* k * ln2 */ + +/* + * See __cexp.c for details. + * + * Input: ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7 + * Output: 2**127 <= y < 2**128 + */ +static float __frexp_expf(float x, int *expt) +{ + float exp_x; + uint32_t hx; + + exp_x = expf(x - kln2); + GET_FLOAT_WORD(hx, exp_x); + *expt = (hx >> 23) - (0x7f + 127) + k; + SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23)); + return exp_x; +} + +float complex __ldexp_cexpf(float complex z, int expt) +{ + float x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = crealf(z); + y = cimagf(z); + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + + half_expt = expt / 2; + SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23); + half_expt = expt - half_expt; + SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23); + + return CMPLXF(cosf(y) * exp_x * scale1 * scale2, + sinf(y) * exp_x * scale1 * scale2); +} diff --git a/system/lib/libc/musl/src/complex/cabs.c b/system/lib/libc/musl/src/complex/cabs.c new file mode 100644 index 0000000000000..f61d364e47d26 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cabs.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double cabs(double complex z) +{ + return hypot(creal(z), cimag(z)); +} diff --git a/system/lib/libc/musl/src/complex/cabsf.c b/system/lib/libc/musl/src/complex/cabsf.c new file mode 100644 index 0000000000000..30b25c70315dd --- /dev/null +++ b/system/lib/libc/musl/src/complex/cabsf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float cabsf(float complex z) +{ + return hypotf(crealf(z), cimagf(z)); +} diff --git a/system/lib/libc/musl/src/complex/cabsl.c b/system/lib/libc/musl/src/complex/cabsl.c new file mode 100644 index 0000000000000..40a067c1c59f1 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cabsl.c @@ -0,0 +1,13 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cabsl(long double complex z) +{ + return cabs(z); +} +#else +long double cabsl(long double complex z) +{ + return hypotl(creall(z), cimagl(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/cacos.c b/system/lib/libc/musl/src/complex/cacos.c new file mode 100644 index 0000000000000..27c356364c8c6 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cacos.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME: Hull et al. "Implementing the complex arcsine and arccosine functions using exception handling" 1997 + +/* acos(z) = pi/2 - asin(z) */ + +double complex cacos(double complex z) +{ + z = casin(z); + return CMPLX(M_PI_2 - creal(z), -cimag(z)); +} diff --git a/system/lib/libc/musl/src/complex/cacosf.c b/system/lib/libc/musl/src/complex/cacosf.c new file mode 100644 index 0000000000000..11852659523a4 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cacosf.c @@ -0,0 +1,9 @@ +#include "libm.h" + +// FIXME + +float complex cacosf(float complex z) +{ + z = casinf(z); + return CMPLXF((float)M_PI_2 - crealf(z), -cimagf(z)); +} diff --git a/system/lib/libc/musl/src/complex/cacosh.c b/system/lib/libc/musl/src/complex/cacosh.c new file mode 100644 index 0000000000000..8c68cb01fd603 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cacosh.c @@ -0,0 +1,9 @@ +#include "libm.h" + +/* acosh(z) = i acos(z) */ + +double complex cacosh(double complex z) +{ + z = cacos(z); + return CMPLX(-cimag(z), creal(z)); +} diff --git a/system/lib/libc/musl/src/complex/cacoshf.c b/system/lib/libc/musl/src/complex/cacoshf.c new file mode 100644 index 0000000000000..ade01c0907c83 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cacoshf.c @@ -0,0 +1,7 @@ +#include "libm.h" + +float complex cacoshf(float complex z) +{ + z = cacosf(z); + return CMPLXF(-cimagf(z), crealf(z)); +} diff --git a/system/lib/libc/musl/src/complex/cacoshl.c b/system/lib/libc/musl/src/complex/cacoshl.c new file mode 100644 index 0000000000000..65342557f9a54 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cacoshl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cacoshl(long double complex z) +{ + return cacosh(z); +} +#else +long double complex cacoshl(long double complex z) +{ + z = cacosl(z); + return CMPLXL(-cimagl(z), creall(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/cacosl.c b/system/lib/libc/musl/src/complex/cacosl.c new file mode 100644 index 0000000000000..7fd4a2f6b4424 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cacosl.c @@ -0,0 +1,16 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cacosl(long double complex z) +{ + return cacos(z); +} +#else +// FIXME +#define PI_2 1.57079632679489661923132169163975144L +long double complex cacosl(long double complex z) +{ + z = casinl(z); + return CMPLXL(PI_2 - creall(z), -cimagl(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/carg.c b/system/lib/libc/musl/src/complex/carg.c new file mode 100644 index 0000000000000..d2d1b4623a7fc --- /dev/null +++ b/system/lib/libc/musl/src/complex/carg.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double carg(double complex z) +{ + return atan2(cimag(z), creal(z)); +} diff --git a/system/lib/libc/musl/src/complex/cargf.c b/system/lib/libc/musl/src/complex/cargf.c new file mode 100644 index 0000000000000..ce183c4b335be --- /dev/null +++ b/system/lib/libc/musl/src/complex/cargf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float cargf(float complex z) +{ + return atan2f(cimagf(z), crealf(z)); +} diff --git a/system/lib/libc/musl/src/complex/cargl.c b/system/lib/libc/musl/src/complex/cargl.c new file mode 100644 index 0000000000000..e0d504782f1fc --- /dev/null +++ b/system/lib/libc/musl/src/complex/cargl.c @@ -0,0 +1,13 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cargl(long double complex z) +{ + return carg(z); +} +#else +long double cargl(long double complex z) +{ + return atan2l(cimagl(z), creall(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/casin.c b/system/lib/libc/musl/src/complex/casin.c new file mode 100644 index 0000000000000..dfdda988bafcd --- /dev/null +++ b/system/lib/libc/musl/src/complex/casin.c @@ -0,0 +1,16 @@ +#include "libm.h" + +// FIXME + +/* asin(z) = -i log(i z + sqrt(1 - z*z)) */ + +double complex casin(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = CMPLX(1.0 - (x - y)*(x + y), -2.0*x*y); + return clog(CMPLX(-y, x) + csqrt(w)); +} diff --git a/system/lib/libc/musl/src/complex/casinf.c b/system/lib/libc/musl/src/complex/casinf.c new file mode 100644 index 0000000000000..93f0e335092b0 --- /dev/null +++ b/system/lib/libc/musl/src/complex/casinf.c @@ -0,0 +1,14 @@ +#include "libm.h" + +// FIXME + +float complex casinf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = CMPLXF(1.0 - (x - y)*(x + y), -2.0*x*y); + return clogf(CMPLXF(-y, x) + csqrtf(w)); +} diff --git a/system/lib/libc/musl/src/complex/casinh.c b/system/lib/libc/musl/src/complex/casinh.c new file mode 100644 index 0000000000000..b57fe8c40ba3b --- /dev/null +++ b/system/lib/libc/musl/src/complex/casinh.c @@ -0,0 +1,9 @@ +#include "libm.h" + +/* asinh(z) = -i asin(i z) */ + +double complex casinh(double complex z) +{ + z = casin(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/system/lib/libc/musl/src/complex/casinhf.c b/system/lib/libc/musl/src/complex/casinhf.c new file mode 100644 index 0000000000000..a11bf902d86f9 --- /dev/null +++ b/system/lib/libc/musl/src/complex/casinhf.c @@ -0,0 +1,7 @@ +#include "libm.h" + +float complex casinhf(float complex z) +{ + z = casinf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/system/lib/libc/musl/src/complex/casinhl.c b/system/lib/libc/musl/src/complex/casinhl.c new file mode 100644 index 0000000000000..714f189359071 --- /dev/null +++ b/system/lib/libc/musl/src/complex/casinhl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex casinhl(long double complex z) +{ + return casinh(z); +} +#else +long double complex casinhl(long double complex z) +{ + z = casinl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/casinl.c b/system/lib/libc/musl/src/complex/casinl.c new file mode 100644 index 0000000000000..0916c60f2a6b3 --- /dev/null +++ b/system/lib/libc/musl/src/complex/casinl.c @@ -0,0 +1,20 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex casinl(long double complex z) +{ + return casin(z); +} +#else +// FIXME +long double complex casinl(long double complex z) +{ + long double complex w; + long double x, y; + + x = creall(z); + y = cimagl(z); + w = CMPLXL(1.0 - (x - y)*(x + y), -2.0*x*y); + return clogl(CMPLXL(-y, x) + csqrtl(w)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/catan.c b/system/lib/libc/musl/src/complex/catan.c new file mode 100644 index 0000000000000..39ce6cf2ff6fc --- /dev/null +++ b/system/lib/libc/musl/src/complex/catan.c @@ -0,0 +1,119 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catan.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * double complex catan(); + * double complex z, w; + * + * w = catan (z); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * catan(z) = -i catanh(iz). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include "libm.h" + +#define MAXNUM 1.0e308 + +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; + +static double _redupi(double x) +{ + double t; + long i; + + t = x/M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +double complex catan(double complex z) +{ + double complex w; + double a, t, x, x2, y; + + x = creal(z); + y = cimag(z); + + if (x == 0.0 && y > 1.0) + goto ovrf; + + x2 = x * x; + a = 1.0 - x2 - (y * y); + if (a == 0.0) + goto ovrf; + + t = 0.5 * atan2(2.0 * x, a); + w = _redupi(t); + + t = y - 1.0; + a = x2 + (t * t); + if (a == 0.0) + goto ovrf; + + t = y + 1.0; + a = (x2 + t * t)/a; + w = w + (0.25 * log(a)) * I; + return w; + +ovrf: + // FIXME + w = MAXNUM + MAXNUM * I; + return w; +} diff --git a/system/lib/libc/musl/src/complex/catanf.c b/system/lib/libc/musl/src/complex/catanf.c new file mode 100644 index 0000000000000..8533bde397fba --- /dev/null +++ b/system/lib/libc/musl/src/complex/catanf.c @@ -0,0 +1,115 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catanf.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * float complex catanf(); + * float complex z, w; + * + * w = catanf( z ); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-6 5.2e-8 + */ + +#include "libm.h" + +#define MAXNUMF 1.0e38F + +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; + +static float _redupif(float xx) +{ + float x, t; + long i; + + x = xx; + t = x/(float)M_PI; + if (t >= 0.0f) + t += 0.5f; + else + t -= 0.5f; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +float complex catanf(float complex z) +{ + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + if ((x == 0.0f) && (y > 1.0f)) + goto ovrf; + + x2 = x * x; + a = 1.0f - x2 - (y * y); + if (a == 0.0f) + goto ovrf; + + t = 0.5f * atan2f(2.0f * x, a); + w = _redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + if (a == 0.0f) + goto ovrf; + + t = y + 1.0f; + a = (x2 + (t * t))/a; + w = w + (0.25f * logf (a)) * I; + return w; + +ovrf: + // FIXME + w = MAXNUMF + MAXNUMF * I; + return w; +} diff --git a/system/lib/libc/musl/src/complex/catanh.c b/system/lib/libc/musl/src/complex/catanh.c new file mode 100644 index 0000000000000..e248d9b934135 --- /dev/null +++ b/system/lib/libc/musl/src/complex/catanh.c @@ -0,0 +1,9 @@ +#include "libm.h" + +/* atanh = -i atan(i z) */ + +double complex catanh(double complex z) +{ + z = catan(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/system/lib/libc/musl/src/complex/catanhf.c b/system/lib/libc/musl/src/complex/catanhf.c new file mode 100644 index 0000000000000..4a5eb04079b9d --- /dev/null +++ b/system/lib/libc/musl/src/complex/catanhf.c @@ -0,0 +1,7 @@ +#include "libm.h" + +float complex catanhf(float complex z) +{ + z = catanf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/system/lib/libc/musl/src/complex/catanhl.c b/system/lib/libc/musl/src/complex/catanhl.c new file mode 100644 index 0000000000000..a5dd538e44535 --- /dev/null +++ b/system/lib/libc/musl/src/complex/catanhl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex catanhl(long double complex z) +{ + return catanh(z); +} +#else +long double complex catanhl(long double complex z) +{ + z = catanl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/catanl.c b/system/lib/libc/musl/src/complex/catanl.c new file mode 100644 index 0000000000000..5ace7704fdc08 --- /dev/null +++ b/system/lib/libc/musl/src/complex/catanl.c @@ -0,0 +1,126 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catanl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * long double complex catanl(); + * long double complex z, w; + * + * w = catanl( z ); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex catanl(long double complex z) +{ + return catan(z); +} +#else +static const long double PIL = 3.141592653589793238462643383279502884197169L; +static const long double DP1 = 3.14159265358979323829596852490908531763125L; +static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L; +static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L; + +static long double redupil(long double x) +{ + long double t; + long i; + + t = x / PIL; + if (t >= 0.0L) + t += 0.5L; + else + t -= 0.5L; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +long double complex catanl(long double complex z) +{ + long double complex w; + long double a, t, x, x2, y; + + x = creall(z); + y = cimagl(z); + + if ((x == 0.0L) && (y > 1.0L)) + goto ovrf; + + x2 = x * x; + a = 1.0L - x2 - (y * y); + if (a == 0.0L) + goto ovrf; + + t = atan2l(2.0L * x, a) * 0.5L; + w = redupil(t); + + t = y - 1.0L; + a = x2 + (t * t); + if (a == 0.0L) + goto ovrf; + + t = y + 1.0L; + a = (x2 + (t * t)) / a; + w = w + (0.25L * logl(a)) * I; + return w; + +ovrf: + // FIXME + w = LDBL_MAX + LDBL_MAX * I; + return w; +} +#endif diff --git a/system/lib/libc/musl/src/complex/ccos.c b/system/lib/libc/musl/src/complex/ccos.c new file mode 100644 index 0000000000000..645aec29a9dc0 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ccos.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* cos(z) = cosh(i z) */ + +double complex ccos(double complex z) +{ + return ccosh(CMPLX(-cimag(z), creal(z))); +} diff --git a/system/lib/libc/musl/src/complex/ccosf.c b/system/lib/libc/musl/src/complex/ccosf.c new file mode 100644 index 0000000000000..9a67241f1cfb4 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ccosf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex ccosf(float complex z) +{ + return ccoshf(CMPLXF(-cimagf(z), crealf(z))); +} diff --git a/system/lib/libc/musl/src/complex/ccosh.c b/system/lib/libc/musl/src/complex/ccosh.c new file mode 100644 index 0000000000000..401f3c604237c --- /dev/null +++ b/system/lib/libc/musl/src/complex/ccosh.c @@ -0,0 +1,140 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ccosh.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic cosine of a complex argument z = x + i y. + * + * cosh(z) = cosh(x+iy) + * = cosh(x) cos(y) + i sinh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "libm.h" + +static const double huge = 0x1p1023; + +double complex ccosh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return CMPLX(cosh(x), x * y); + if (ix < 0x40360000) /* small x: normal case */ + return CMPLX(cosh(x) * cos(y), sinh(x) * sin(y)); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return CMPLX(h * cos(y), copysign(h, x) * sin(y)); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return CMPLX(creal(z), cimag(z) * copysign(1, x)); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return CMPLX(h * h * cos(y), h * sin(y)); + } + } + + /* + * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return CMPLX(y - y, copysign(0, x * (y - y))); + + /* + * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0. + * + * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0. + * The sign of 0 in the result is unspecified. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return CMPLX(x * x, copysign(0, x) * y); + return CMPLX(x * x, copysign(0, (x + x) * y)); + } + + /* + * cosh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * cosh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return CMPLX(y - y, x * (y - y)); + + /* + * cosh(+-Inf + I NaN) = +Inf + I d(NaN). + * + * cosh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return CMPLX(x * x, x * (y - y)); + return CMPLX((x * x) * cos(y), x * sin(y)); + } + + /* + * cosh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * cosh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * cosh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return CMPLX((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/system/lib/libc/musl/src/complex/ccoshf.c b/system/lib/libc/musl/src/complex/ccoshf.c new file mode 100644 index 0000000000000..90acfe05829f3 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ccoshf.c @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ccoshf.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic cosine of a complex argument. See s_ccosh.c for details. + */ + +#include "libm.h" + +static const float huge = 0x1p127; + +float complex ccoshf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return CMPLXF(coshf(x), x * y); + if (ix < 0x41100000) /* small x: normal case */ + return CMPLXF(coshf(x) * cosf(y), sinhf(x) * sinf(y)); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return CMPLXF(h * cosf(y), copysignf(h, x) * sinf(y)); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return CMPLXF(crealf(z), cimagf(z) * copysignf(1, x)); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return CMPLXF(h * h * cosf(y), h * sinf(y)); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return CMPLXF(y - y, copysignf(0, x * (y - y))); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return CMPLXF(x * x, copysignf(0, x) * y); + return CMPLXF(x * x, copysignf(0, (x + x) * y)); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return CMPLXF(y - y, x * (y - y)); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return CMPLXF(x * x, x * (y - y)); + return CMPLXF((x * x) * cosf(y), x * sinf(y)); + } + + return CMPLXF((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/system/lib/libc/musl/src/complex/ccoshl.c b/system/lib/libc/musl/src/complex/ccoshl.c new file mode 100644 index 0000000000000..9b2aed9ef16c4 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ccoshl.c @@ -0,0 +1,7 @@ +#include "libm.h" + +//FIXME +long double complex ccoshl(long double complex z) +{ + return ccosh(z); +} diff --git a/system/lib/libc/musl/src/complex/ccosl.c b/system/lib/libc/musl/src/complex/ccosl.c new file mode 100644 index 0000000000000..d787047fec8d5 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ccosl.c @@ -0,0 +1,13 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex ccosl(long double complex z) +{ + return ccos(z); +} +#else +long double complex ccosl(long double complex z) +{ + return ccoshl(CMPLXL(-cimagl(z), creall(z))); +} +#endif diff --git a/system/lib/libc/musl/src/complex/cexp.c b/system/lib/libc/musl/src/complex/cexp.c new file mode 100644 index 0000000000000..5118e00ea5b74 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cexp.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexp.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t +exp_ovfl = 0x40862e42, /* high bits of MAX_EXP * ln2 ~= 710 */ +cexp_ovfl = 0x4096b8e4; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +double complex cexp(double complex z) +{ + double x, y, exp_x; + uint32_t hx, hy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hy, ly, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if ((hy | ly) == 0) + return CMPLX(exp(x), y); + EXTRACT_WORDS(hx, lx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if (((hx & 0x7fffffff) | lx) == 0) + return CMPLX(cos(y), sin(y)); + + if (hy >= 0x7ff00000) { + if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLX(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLX(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLX(x, y - y); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 709.7 and 1454.3, so we must scale to avoid + * overflow in exp(x). + */ + return __ldexp_cexp(z, 0); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = exp(x); + return CMPLX(exp_x * cos(y), exp_x * sin(y)); + } +} diff --git a/system/lib/libc/musl/src/complex/cexpf.c b/system/lib/libc/musl/src/complex/cexpf.c new file mode 100644 index 0000000000000..1a09964cbb52d --- /dev/null +++ b/system/lib/libc/musl/src/complex/cexpf.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexpf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t +exp_ovfl = 0x42b17218, /* MAX_EXP * ln2 ~= 88.722839355 */ +cexp_ovfl = 0x43400074; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +float complex cexpf(float complex z) +{ + float x, y, exp_x; + uint32_t hx, hy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hy, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if (hy == 0) + return CMPLXF(expf(x), y); + GET_FLOAT_WORD(hx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if ((hx & 0x7fffffff) == 0) + return CMPLXF(cosf(y), sinf(y)); + + if (hy >= 0x7f800000) { + if ((hx & 0x7fffffff) != 0x7f800000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLXF(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLXF(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLXF(x, y - y); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 88.7 and 192, so we must scale to avoid + * overflow in expf(x). + */ + return __ldexp_cexpf(z, 0); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = expf(x); + return CMPLXF(exp_x * cosf(y), exp_x * sinf(y)); + } +} diff --git a/system/lib/libc/musl/src/complex/cexpl.c b/system/lib/libc/musl/src/complex/cexpl.c new file mode 100644 index 0000000000000..a27f85c052c1b --- /dev/null +++ b/system/lib/libc/musl/src/complex/cexpl.c @@ -0,0 +1,7 @@ +#include "libm.h" + +//FIXME +long double complex cexpl(long double complex z) +{ + return cexp(z); +} diff --git a/system/lib/libc/musl/src/complex/cimag.c b/system/lib/libc/musl/src/complex/cimag.c new file mode 100644 index 0000000000000..00955641b14a9 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cimag.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double (cimag)(double complex z) +{ + return cimag(z); +} diff --git a/system/lib/libc/musl/src/complex/cimagf.c b/system/lib/libc/musl/src/complex/cimagf.c new file mode 100644 index 0000000000000..f7bcd76e439fe --- /dev/null +++ b/system/lib/libc/musl/src/complex/cimagf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float (cimagf)(float complex z) +{ + return cimagf(z); +} diff --git a/system/lib/libc/musl/src/complex/cimagl.c b/system/lib/libc/musl/src/complex/cimagl.c new file mode 100644 index 0000000000000..9ec24eeeafc56 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cimagl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +long double (cimagl)(long double complex z) +{ + return cimagl(z); +} diff --git a/system/lib/libc/musl/src/complex/clog.c b/system/lib/libc/musl/src/complex/clog.c new file mode 100644 index 0000000000000..12aae9c7e9a02 --- /dev/null +++ b/system/lib/libc/musl/src/complex/clog.c @@ -0,0 +1,14 @@ +#include "libm.h" + +// FIXME + +/* log(z) = log(|z|) + i arg(z) */ + +double complex clog(double complex z) +{ + double r, phi; + + r = cabs(z); + phi = carg(z); + return CMPLX(log(r), phi); +} diff --git a/system/lib/libc/musl/src/complex/clogf.c b/system/lib/libc/musl/src/complex/clogf.c new file mode 100644 index 0000000000000..e9b32e6087bf2 --- /dev/null +++ b/system/lib/libc/musl/src/complex/clogf.c @@ -0,0 +1,12 @@ +#include "libm.h" + +// FIXME + +float complex clogf(float complex z) +{ + float r, phi; + + r = cabsf(z); + phi = cargf(z); + return CMPLXF(logf(r), phi); +} diff --git a/system/lib/libc/musl/src/complex/clogl.c b/system/lib/libc/musl/src/complex/clogl.c new file mode 100644 index 0000000000000..18f16088d7a31 --- /dev/null +++ b/system/lib/libc/musl/src/complex/clogl.c @@ -0,0 +1,18 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex clogl(long double complex z) +{ + return clog(z); +} +#else +// FIXME +long double complex clogl(long double complex z) +{ + long double r, phi; + + r = cabsl(z); + phi = cargl(z); + return CMPLXL(logl(r), phi); +} +#endif diff --git a/system/lib/libc/musl/src/complex/conj.c b/system/lib/libc/musl/src/complex/conj.c new file mode 100644 index 0000000000000..0b3f5f46306c7 --- /dev/null +++ b/system/lib/libc/musl/src/complex/conj.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double complex conj(double complex z) +{ + return CMPLX(creal(z), -cimag(z)); +} diff --git a/system/lib/libc/musl/src/complex/conjf.c b/system/lib/libc/musl/src/complex/conjf.c new file mode 100644 index 0000000000000..9af6b2c3b4549 --- /dev/null +++ b/system/lib/libc/musl/src/complex/conjf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex conjf(float complex z) +{ + return CMPLXF(crealf(z), -cimagf(z)); +} diff --git a/system/lib/libc/musl/src/complex/conjl.c b/system/lib/libc/musl/src/complex/conjl.c new file mode 100644 index 0000000000000..67f11b9dde8ee --- /dev/null +++ b/system/lib/libc/musl/src/complex/conjl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +long double complex conjl(long double complex z) +{ + return CMPLXL(creall(z), -cimagl(z)); +} diff --git a/system/lib/libc/musl/src/complex/cpow.c b/system/lib/libc/musl/src/complex/cpow.c new file mode 100644 index 0000000000000..f863588fe7881 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cpow.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* pow(z, c) = exp(c log(z)), See C99 G.6.4.1 */ + +double complex cpow(double complex z, double complex c) +{ + return cexp(c * clog(z)); +} diff --git a/system/lib/libc/musl/src/complex/cpowf.c b/system/lib/libc/musl/src/complex/cpowf.c new file mode 100644 index 0000000000000..53c65dcb1112a --- /dev/null +++ b/system/lib/libc/musl/src/complex/cpowf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex cpowf(float complex z, float complex c) +{ + return cexpf(c * clogf(z)); +} diff --git a/system/lib/libc/musl/src/complex/cpowl.c b/system/lib/libc/musl/src/complex/cpowl.c new file mode 100644 index 0000000000000..c1a80a7b255bd --- /dev/null +++ b/system/lib/libc/musl/src/complex/cpowl.c @@ -0,0 +1,13 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cpowl(long double complex z, long double complex c) +{ + return cpow(z, c); +} +#else +long double complex cpowl(long double complex z, long double complex c) +{ + return cexpl(c * clogl(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/cproj.c b/system/lib/libc/musl/src/complex/cproj.c new file mode 100644 index 0000000000000..15f358a14f045 --- /dev/null +++ b/system/lib/libc/musl/src/complex/cproj.c @@ -0,0 +1,8 @@ +#include "libm.h" + +double complex cproj(double complex z) +{ + if (isinf(creal(z)) || isinf(cimag(z))) + return CMPLX(INFINITY, copysign(0.0, creal(z))); + return z; +} diff --git a/system/lib/libc/musl/src/complex/cprojf.c b/system/lib/libc/musl/src/complex/cprojf.c new file mode 100644 index 0000000000000..653be5e87cfcb --- /dev/null +++ b/system/lib/libc/musl/src/complex/cprojf.c @@ -0,0 +1,8 @@ +#include "libm.h" + +float complex cprojf(float complex z) +{ + if (isinf(crealf(z)) || isinf(cimagf(z))) + return CMPLXF(INFINITY, copysignf(0.0, crealf(z))); + return z; +} diff --git a/system/lib/libc/musl/src/complex/cprojl.c b/system/lib/libc/musl/src/complex/cprojl.c new file mode 100644 index 0000000000000..6731aaa2aaaeb --- /dev/null +++ b/system/lib/libc/musl/src/complex/cprojl.c @@ -0,0 +1,15 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cprojl(long double complex z) +{ + return cproj(z); +} +#else +long double complex cprojl(long double complex z) +{ + if (isinf(creall(z)) || isinf(cimagl(z))) + return CMPLXL(INFINITY, copysignl(0.0, creall(z))); + return z; +} +#endif diff --git a/system/lib/libc/musl/src/complex/creal.c b/system/lib/libc/musl/src/complex/creal.c new file mode 100644 index 0000000000000..f6703040d06fd --- /dev/null +++ b/system/lib/libc/musl/src/complex/creal.c @@ -0,0 +1,6 @@ +#include + +double (creal)(double complex z) +{ + return creal(z); +} diff --git a/system/lib/libc/musl/src/complex/crealf.c b/system/lib/libc/musl/src/complex/crealf.c new file mode 100644 index 0000000000000..5dc3ff1d3099d --- /dev/null +++ b/system/lib/libc/musl/src/complex/crealf.c @@ -0,0 +1,6 @@ +#include + +float (crealf)(float complex z) +{ + return crealf(z); +} diff --git a/system/lib/libc/musl/src/complex/creall.c b/system/lib/libc/musl/src/complex/creall.c new file mode 100644 index 0000000000000..fd9dc3470c253 --- /dev/null +++ b/system/lib/libc/musl/src/complex/creall.c @@ -0,0 +1,6 @@ +#include + +long double (creall)(long double complex z) +{ + return creall(z); +} diff --git a/system/lib/libc/musl/src/complex/csin.c b/system/lib/libc/musl/src/complex/csin.c new file mode 100644 index 0000000000000..ad8ae67ad99a5 --- /dev/null +++ b/system/lib/libc/musl/src/complex/csin.c @@ -0,0 +1,9 @@ +#include "libm.h" + +/* sin(z) = -i sinh(i z) */ + +double complex csin(double complex z) +{ + z = csinh(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/system/lib/libc/musl/src/complex/csinf.c b/system/lib/libc/musl/src/complex/csinf.c new file mode 100644 index 0000000000000..60b3cbaa8681a --- /dev/null +++ b/system/lib/libc/musl/src/complex/csinf.c @@ -0,0 +1,7 @@ +#include "libm.h" + +float complex csinf(float complex z) +{ + z = csinhf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/system/lib/libc/musl/src/complex/csinh.c b/system/lib/libc/musl/src/complex/csinh.c new file mode 100644 index 0000000000000..0f8035d1ca41f --- /dev/null +++ b/system/lib/libc/musl/src/complex/csinh.c @@ -0,0 +1,141 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csinh.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic sine of a complex argument z = x + i y. + * + * sinh(z) = sinh(x+iy) + * = sinh(x) cos(y) + i cosh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "libm.h" + +static const double huge = 0x1p1023; + +double complex csinh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return CMPLX(sinh(x), y); + if (ix < 0x40360000) /* small x: normal case */ + return CMPLX(sinh(x) * cos(y), cosh(x) * sin(y)); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return CMPLX(copysign(h, x) * cos(y), h * sin(y)); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return CMPLX(creal(z) * copysign(1, x), cimag(z)); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return CMPLX(h * cos(y), h * h * sin(y)); + } + } + + /* + * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN). + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return CMPLX(copysign(0, x * (y - y)), y - y); + + /* + * sinh(+-Inf +- I 0) = +-Inf + I +-0. + * + * sinh(NaN +- I 0) = d(NaN) + I +-0. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return CMPLX(x, y); + return CMPLX(x, copysign(0, y)); + } + + /* + * sinh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * sinh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return CMPLX(y - y, x * (y - y)); + + /* + * sinh(+-Inf + I NaN) = +-Inf + I d(NaN). + * The sign of Inf in the result is unspecified. Choice = normally + * the same as d(NaN). + * + * sinh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return CMPLX(x * x, x * (y - y)); + return CMPLX(x * cos(y), INFINITY * sin(y)); + } + + /* + * sinh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * sinh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * sinh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return CMPLX((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/system/lib/libc/musl/src/complex/csinhf.c b/system/lib/libc/musl/src/complex/csinhf.c new file mode 100644 index 0000000000000..49697f02f4a35 --- /dev/null +++ b/system/lib/libc/musl/src/complex/csinhf.c @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csinhf.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic sine of a complex argument z. See s_csinh.c for details. + */ + +#include "libm.h" + +static const float huge = 0x1p127; + +float complex csinhf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return CMPLXF(sinhf(x), y); + if (ix < 0x41100000) /* small x: normal case */ + return CMPLXF(sinhf(x) * cosf(y), coshf(x) * sinf(y)); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return CMPLXF(copysignf(h, x) * cosf(y), h * sinf(y)); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return CMPLXF(crealf(z) * copysignf(1, x), cimagf(z)); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return CMPLXF(h * cosf(y), h * h * sinf(y)); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return CMPLXF(copysignf(0, x * (y - y)), y - y); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return CMPLXF(x, y); + return CMPLXF(x, copysignf(0, y)); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return CMPLXF(y - y, x * (y - y)); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return CMPLXF(x * x, x * (y - y)); + return CMPLXF(x * cosf(y), INFINITY * sinf(y)); + } + + return CMPLXF((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/system/lib/libc/musl/src/complex/csinhl.c b/system/lib/libc/musl/src/complex/csinhl.c new file mode 100644 index 0000000000000..c566653b3356f --- /dev/null +++ b/system/lib/libc/musl/src/complex/csinhl.c @@ -0,0 +1,7 @@ +#include "libm.h" + +//FIXME +long double complex csinhl(long double complex z) +{ + return csinh(z); +} diff --git a/system/lib/libc/musl/src/complex/csinl.c b/system/lib/libc/musl/src/complex/csinl.c new file mode 100644 index 0000000000000..4e9f86c3ae4dc --- /dev/null +++ b/system/lib/libc/musl/src/complex/csinl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex csinl(long double complex z) +{ + return csin(z); +} +#else +long double complex csinl(long double complex z) +{ + z = csinhl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/system/lib/libc/musl/src/complex/csqrt.c b/system/lib/libc/musl/src/complex/csqrt.c new file mode 100644 index 0000000000000..8a2ba60801223 --- /dev/null +++ b/system/lib/libc/musl/src/complex/csqrt.c @@ -0,0 +1,100 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrt.c */ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */ +#define THRESH 0x1.a827999fcef32p+1022 + +double complex csqrt(double complex z) +{ + double complex result; + double a, b; + double t; + int scale; + + a = creal(z); + b = cimag(z); + + /* Handle special cases. */ + if (z == 0) + return CMPLX(0, b); + if (isinf(b)) + return CMPLX(INFINITY, b); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return CMPLX(a, t); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return CMPLX(fabs(b - b), copysign(a, b)); + else + return CMPLX(a, copysign(b - b, b)); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabs(a) >= THRESH || fabs(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + result = CMPLX(t, b / (2 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + result = CMPLX(fabs(b) / (2 * t), copysign(t, b)); + } + + /* Rescale. */ + if (scale) + result *= 2; + return result; +} diff --git a/system/lib/libc/musl/src/complex/csqrtf.c b/system/lib/libc/musl/src/complex/csqrtf.c new file mode 100644 index 0000000000000..ab5102f035b9e --- /dev/null +++ b/system/lib/libc/musl/src/complex/csqrtf.c @@ -0,0 +1,82 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrtf.c */ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +float complex csqrtf(float complex z) +{ + float a = crealf(z), b = cimagf(z); + double t; + + /* Handle special cases. */ + if (z == 0) + return CMPLXF(0, b); + if (isinf(b)) + return CMPLXF(INFINITY, b); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return CMPLXF(a, t); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrtf(inf + NaN i) = inf + NaN i + * csqrtf(inf + y i) = inf + 0 i + * csqrtf(-inf + NaN i) = NaN +- inf i + * csqrtf(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return CMPLXF(fabsf(b - b), copysignf(a, b)); + else + return CMPLXF(a, copysignf(b - b, b)); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* + * We compute t in double precision to avoid overflow and to + * provide correct rounding in nearly all cases. + * This is Algorithm 312, CACM vol 10, Oct 1967. + */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + return CMPLXF(t, b / (2.0 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + return CMPLXF(fabsf(b) / (2.0 * t), copysignf(t, b)); + } +} diff --git a/system/lib/libc/musl/src/complex/csqrtl.c b/system/lib/libc/musl/src/complex/csqrtl.c new file mode 100644 index 0000000000000..0600ef3bebcd3 --- /dev/null +++ b/system/lib/libc/musl/src/complex/csqrtl.c @@ -0,0 +1,7 @@ +#include "libm.h" + +//FIXME +long double complex csqrtl(long double complex z) +{ + return csqrt(z); +} diff --git a/system/lib/libc/musl/src/complex/ctan.c b/system/lib/libc/musl/src/complex/ctan.c new file mode 100644 index 0000000000000..c09263744b869 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ctan.c @@ -0,0 +1,9 @@ +#include "libm.h" + +/* tan(z) = -i tanh(i z) */ + +double complex ctan(double complex z) +{ + z = ctanh(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/system/lib/libc/musl/src/complex/ctanf.c b/system/lib/libc/musl/src/complex/ctanf.c new file mode 100644 index 0000000000000..009b1921ba356 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ctanf.c @@ -0,0 +1,7 @@ +#include "libm.h" + +float complex ctanf(float complex z) +{ + z = ctanhf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/system/lib/libc/musl/src/complex/ctanh.c b/system/lib/libc/musl/src/complex/ctanh.c new file mode 100644 index 0000000000000..0461050d73301 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ctanh.c @@ -0,0 +1,127 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic tangent of a complex argument z = x + i y. + * + * The algorithm is from: + * + * W. Kahan. Branch Cuts for Complex Elementary Functions or Much + * Ado About Nothing's Sign Bit. In The State of the Art in + * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987. + * + * Method: + * + * Let t = tan(x) + * beta = 1/cos^2(y) + * s = sinh(x) + * rho = cosh(x) + * + * We have: + * + * tanh(z) = sinh(z) / cosh(z) + * + * sinh(x) cos(y) + i cosh(x) sin(y) + * = --------------------------------- + * cosh(x) cos(y) + i sinh(x) sin(y) + * + * cosh(x) sinh(x) / cos^2(y) + i tan(y) + * = ------------------------------------- + * 1 + sinh^2(x) / cos^2(y) + * + * beta rho s + i t + * = ---------------- + * 1 + beta s^2 + * + * Modifications: + * + * I omitted the original algorithm's handling of overflow in tan(x) after + * verifying with nearpi.c that this can't happen in IEEE single or double + * precision. I also handle large x differently. + */ + +#include "libm.h" + +double complex ctanh(double complex z) +{ + double x, y; + double t, beta, s, rho, denom; + uint32_t hx, ix, lx; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; + + /* + * ctanh(NaN + i 0) = NaN + i 0 + * + * ctanh(NaN + i y) = NaN + i NaN for y != 0 + * + * The imaginary part has the sign of x*sin(2*y), but there's no + * special effort to get this right. + * + * ctanh(+-Inf +- i Inf) = +-1 +- 0 + * + * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite + * + * The imaginary part of the sign is unspecified. This special + * case is only needed to avoid a spurious invalid exception when + * y is infinite. + */ + if (ix >= 0x7ff00000) { + if ((ix & 0xfffff) | lx) /* x is NaN */ + return CMPLX(x, (y == 0 ? y : x * y)); + SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ + return CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))); + } + + /* + * ctanh(x + i NAN) = NaN + i NaN + * ctanh(x +- i Inf) = NaN + i NaN + */ + if (!isfinite(y)) + return CMPLX(y - y, y - y); + + /* + * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the + * approximation sinh^2(huge) ~= exp(2*huge) / 4. + * We use a modified formula to avoid spurious overflow. + */ + if (ix >= 0x40360000) { /* x >= 22 */ + double exp_mx = exp(-fabs(x)); + return CMPLX(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_mx); + } + + /* Kahan's algorithm */ + t = tan(y); + beta = 1.0 + t * t; /* = 1 / cos^2(y) */ + s = sinh(x); + rho = sqrt(1 + s * s); /* = cosh(x) */ + denom = 1 + beta * s * s; + return CMPLX((beta * rho * s) / denom, t / denom); +} diff --git a/system/lib/libc/musl/src/complex/ctanhf.c b/system/lib/libc/musl/src/complex/ctanhf.c new file mode 100644 index 0000000000000..a7e1a5fc0dccf --- /dev/null +++ b/system/lib/libc/musl/src/complex/ctanhf.c @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanhf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic tangent of a complex argument z. See s_ctanh.c for details. + */ + +#include "libm.h" + +float complex ctanhf(float complex z) +{ + float x, y; + float t, beta, s, rho, denom; + uint32_t hx, ix; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + + if (ix >= 0x7f800000) { + if (ix & 0x7fffff) + return CMPLXF(x, (y == 0 ? y : x * y)); + SET_FLOAT_WORD(x, hx - 0x40000000); + return CMPLXF(x, copysignf(0, isinf(y) ? y : sinf(y) * cosf(y))); + } + + if (!isfinite(y)) + return CMPLXF(y - y, y - y); + + if (ix >= 0x41300000) { /* x >= 11 */ + float exp_mx = expf(-fabsf(x)); + return CMPLXF(copysignf(1, x), 4 * sinf(y) * cosf(y) * exp_mx * exp_mx); + } + + t = tanf(y); + beta = 1.0 + t * t; + s = sinhf(x); + rho = sqrtf(1 + s * s); + denom = 1 + beta * s * s; + return CMPLXF((beta * rho * s) / denom, t / denom); +} diff --git a/system/lib/libc/musl/src/complex/ctanhl.c b/system/lib/libc/musl/src/complex/ctanhl.c new file mode 100644 index 0000000000000..89a75d1334670 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ctanhl.c @@ -0,0 +1,7 @@ +#include "libm.h" + +//FIXME +long double complex ctanhl(long double complex z) +{ + return ctanh(z); +} diff --git a/system/lib/libc/musl/src/complex/ctanl.c b/system/lib/libc/musl/src/complex/ctanl.c new file mode 100644 index 0000000000000..ac1c3e0ad86d7 --- /dev/null +++ b/system/lib/libc/musl/src/complex/ctanl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex ctanl(long double complex z) +{ + return ctan(z); +} +#else +long double complex ctanl(long double complex z) +{ + z = ctanhl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols index 15983edf3f54c..e08f7f185cff0 100644 --- a/system/lib/libcextra.symbols +++ b/system/lib/libcextra.symbols @@ -253,3 +253,71 @@ T strcoll T __strcoll_l W strcoll_l + T cabs + T cabsf + T cabsl + T cacos + T cacosf + T cacosh + T cacoshf + T cacoshl + T cacosl + T carg + T cargf + T cargl + T casin + T casinf + T casinh + T casinhf + T casinhl + T casinl + T catan + T catanf + T catanh + T catanhf + T catanhl + T catanl + T ccos + T ccosf + T ccosh + T ccoshf + T ccoshl + T ccosl + T __cexp + T cexp + T __cexpf + T cexpf + T cexpl + T cimag + T cimagf + T cimagl + T clog + T clogf + T clogl + T conj + T conjf + T conjl + T cpow + T cpowf + T cpowl + T cproj + T cprojf + T cprojl + T creal + T crealf + T creall + T csin + T csinf + T csinh + T csinhf + T csinhl + T csinl + T csqrt + T csqrtf + T csqrtl + T ctan + T ctanf + T ctanh + T ctanhf + T ctanhl + T ctanl diff --git a/tests/test_core.py b/tests/test_core.py index 1c3a0b74163c0..9a4e2548261fb 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1688,6 +1688,34 @@ def test_polymorph(self): self.do_run_from_file(src, output) + def test_complex(self): + self.do_run(r''' +#include +#include + +int main(int argc, char**argv) +{ + float complex z1 = 1.0 + 3.0 * I; + printf("value = real %.2f imag %.2f\n",creal(z1),cimag(z1)); + float abs_value = cabsf(z1); + printf("abs = %.2f\n",abs_value); + float complex z2 = conjf(z1); + printf("value = real %.2f imag %.2f\n",creal(z2),cimag(z2)); + float complex z3 = cexpf(z1); + printf("value = real %.2f imag %.2f\n",creal(z3),cimag(z3)); + float complex z4 = conj(z1); + printf("value = real %.2f imag %.2f\n",creal(z4),cimag(z4)); + float complex z5 = cargf(z1); + printf("value = real %.2f imag %.2f\n",creal(z5),cimag(z5)); + return 0; +} +''', '''value = real 1.00 imag 3.00 +abs = 3.16 +value = real 1.00 imag -3.00 +value = real -2.69 imag 0.38 +value = real 1.00 imag -3.00 +value = real 1.25 imag 0.00''', force_c=True) + def test_segfault(self): if self.emcc_args is None: return self.skip('SAFE_HEAP without ta2 means we check types too, which hide segfaults') diff --git a/tools/system_libs.py b/tools/system_libs.py index d73cd79a9d4b1..4bc8b40303849 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -447,6 +447,76 @@ def create_libcextra(): 'wcstod.c', 'wcstol.c', ]], + ['complex', [ + 'cabs.c', + 'cabsf.c', + 'cabsl.c', + 'cacos.c', + 'cacosf.c', + 'cacosh.c', + 'cacoshf.c', + 'cacoshl.c', + 'cacosl.c', + 'carg.c', + 'cargf.c', + 'cargl.c', + 'casin.c', + 'casinf.c', + 'casinh.c', + 'casinhf.c', + 'casinhl.c', + 'casinl.c', + 'catan.c', + 'catanf.c', + 'catanh.c', + 'catanhf.c', + 'catanhl.c', + 'catanl.c', + 'ccos.c', + 'ccosf.c', + 'ccosh.c', + 'ccoshf.c', + 'ccoshl.c', + 'ccosl.c', + '__cexp.c', + 'cexp.c', + '__cexpf.c', + 'cexpf.c', + 'cexpl.c', + 'cimag.c', + 'cimagf.c', + 'cimagl.c', + 'clog.c', + 'clogf.c', + 'clogl.c', + 'conj.c', + 'conjf.c', + 'conjl.c', + 'cpow.c', + 'cpowf.c', + 'cpowl.c', + 'cproj.c', + 'cprojf.c', + 'cprojl.c', + 'creal.c', + 'crealf.c', + 'creall.c', + 'csin.c', + 'csinf.c', + 'csinh.c', + 'csinhf.c', + 'csinhl.c', + 'csinl.c', + 'csqrt.c', + 'csqrtf.c', + 'csqrtl.c', + 'ctan.c', + 'ctanf.c', + 'ctanh.c', + 'ctanhf.c', + 'ctanhl.c', + 'ctanl.c' + ]], ['string', [ 'bcmp.c', 'bcopy.c', From a77edbee9c6dacebb92578d1fc0d35cb6e7fe363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 19:10:32 -0500 Subject: [PATCH 46/75] Fix printNum() in native optimizer to print a double when exponent >= 100. Fixes #3095. --- tools/optimizer/simple_ast.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index e47ae03dbb2a4..3b3425d7e0bc5 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -876,11 +876,16 @@ struct JSPrinter { if (num < 10) { test[1] = '0' + num; test[2] = 0; - } else { - assert(num < 100); + } else if (num < 100) { test[1] = '0' + (num / 10); test[2] = '0' + (num % 10); test[3] = 0; + } else { + assert(num < 1000); + test[1] = '0' + (num / 100); + test[2] = '0' + (num % 100) / 10; + test[3] = '0' + (num % 10); + test[4] = 0; } } } From c20f31cec020cc587df23b269a5165e203b1925b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 19 Dec 2014 19:18:14 -0500 Subject: [PATCH 47/75] Add test for JS optimizer reading and writing LDBL_MAX (1.7976931348623157e308). --- tools/test-js-optimizer-output.js | 4 +++- tools/test-js-optimizer.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/test-js-optimizer-output.js b/tools/test-js-optimizer-output.js index 570fbaa2b0b95..f418360b5c143 100644 --- a/tools/test-js-optimizer-output.js +++ b/tools/test-js-optimizer-output.js @@ -300,4 +300,6 @@ function asmy() { print("fleefl"); } } - +function dblMax() { + var x = +1.7976931348623157e+308; +} diff --git a/tools/test-js-optimizer.js b/tools/test-js-optimizer.js index 3dc99779263e1..e717cc6ba0fbf 100644 --- a/tools/test-js-optimizer.js +++ b/tools/test-js-optimizer.js @@ -402,4 +402,7 @@ function asmy() { print('fleefl'); } } +function dblMax() { + var x = +1.7976931348623157E+308; +} // EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths", "hoisting", "demangle", "lua", "moreLabels", "notComps", "tricky", "asmy"] From 33a2f0bbe39fa792d0aae64a06346c8878488622 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 17:19:25 -0800 Subject: [PATCH 48/75] truncate extra digits on doubles --- tools/optimizer/simple_ast.h | 3 ++- tools/test-js-optimizer-asm-last-output.js | 1 + tools/test-js-optimizer-asm-last-output2.js | 1 + tools/test-js-optimizer-asm-last.js | 1 + tools/test-js-optimizer-asm-lastOpts-output.js | 1 + tools/test-js-optimizer-asm-lastOpts-output2.js | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 3b3425d7e0bc5..44436cebd8772 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -868,7 +868,8 @@ struct JSPrinter { char *end = strchr(buffer, 0); end--; char *test = end; - while (*test == '0' && test > buffer) test--; + // remove zeros, and also doubles can use at most 24 digits, we can truncate any extras even if not zero + while ((*test == '0' || test - buffer > 24) && test > buffer) test--; int num = end - test; if (num >= 3) { test++; diff --git a/tools/test-js-optimizer-asm-last-output.js b/tools/test-js-optimizer-asm-last-output.js index 220407f422768..bee401e5df96e 100644 --- a/tools/test-js-optimizer-asm-last-output.js +++ b/tools/test-js-optimizer-asm-last-output.js @@ -32,6 +32,7 @@ function finall(x) { a = -0xde0b6b000000000; a = 1.1234567890123457e+21; f(g() | 0); + x = 1.7976931348623157e+308; return 12.0e10; } function looop() { diff --git a/tools/test-js-optimizer-asm-last-output2.js b/tools/test-js-optimizer-asm-last-output2.js index ee736a4e71a11..1173ccdb48b92 100644 --- a/tools/test-js-optimizer-asm-last-output2.js +++ b/tools/test-js-optimizer-asm-last-output2.js @@ -32,6 +32,7 @@ function finall(x) { a = -999999984306749440; a = 1123456789012345651200.0; f(g() | 0); + x = 1797693134862315708145274e284; return 12.0e10; } function looop() { diff --git a/tools/test-js-optimizer-asm-last.js b/tools/test-js-optimizer-asm-last.js index 1a30066ddc1a0..54142ed519fe0 100644 --- a/tools/test-js-optimizer-asm-last.js +++ b/tools/test-js-optimizer-asm-last.js @@ -32,6 +32,7 @@ function finall(x) { a = -0xde0b6b000000000; a = +0x3ce7184d470dd60000; f(g() & -1); + x = 1.7976931348623157e+308; return +12e10; } function looop() { diff --git a/tools/test-js-optimizer-asm-lastOpts-output.js b/tools/test-js-optimizer-asm-lastOpts-output.js index f6f090a6ed558..cba0ea237b6f1 100644 --- a/tools/test-js-optimizer-asm-lastOpts-output.js +++ b/tools/test-js-optimizer-asm-lastOpts-output.js @@ -32,6 +32,7 @@ function finall(x) { a = -0xde0b6b000000000; a = +0x3ce7184d470dd60000; f(g() | 0); + x = 1.7976931348623157e+308; return +12e10; } function looop() { diff --git a/tools/test-js-optimizer-asm-lastOpts-output2.js b/tools/test-js-optimizer-asm-lastOpts-output2.js index 0c18b8c924a8d..780d793e1470d 100644 --- a/tools/test-js-optimizer-asm-lastOpts-output2.js +++ b/tools/test-js-optimizer-asm-lastOpts-output2.js @@ -32,6 +32,7 @@ function finall(x) { a = -0xde0b6b000000000; a = +1123456789012345651200; f(g() | 0); + x = 1797693134862315708145274e284; return +12e10; } function looop() { From db14de1f1216dd300b15de44ffcbd43488e07483 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 Dec 2014 17:26:07 -0800 Subject: [PATCH 49/75] move optimizer tests to tests/optimizer --- .../optimizer}/asm-eliminator-test-output.js | 0 .../optimizer}/asm-eliminator-test.js | 0 .../optimizer}/eliminator-test-output.js | 0 .../optimizer}/eliminator-test.js | 0 .../optimizer}/safe-eliminator-test-output.js | 0 .../optimizer}/safe-eliminator-test.js | 0 .../test-js-optimizer-asm-last-output.js | 0 .../test-js-optimizer-asm-last-output2.js | 0 .../optimizer}/test-js-optimizer-asm-last.js | 0 .../test-js-optimizer-asm-lastOpts-output.js | 0 .../test-js-optimizer-asm-lastOpts-output2.js | 0 .../test-js-optimizer-asm-minlast-output.js | 0 .../test-js-optimizer-asm-minlast.js | 0 .../test-js-optimizer-asm-outline1-output.js | 0 .../test-js-optimizer-asm-outline1.js | 0 .../test-js-optimizer-asm-outline2-output.js | 0 .../test-js-optimizer-asm-outline2.js | 0 .../test-js-optimizer-asm-outline3-output.js | 0 .../test-js-optimizer-asm-outline3.js | 0 .../test-js-optimizer-asm-pre-f32.js | 0 ...-js-optimizer-asm-pre-output-f32-nosimp.js | 0 .../test-js-optimizer-asm-pre-output-f32.js | 0 .../test-js-optimizer-asm-pre-output.js | 0 .../test-js-optimizer-asm-pre-output2.js | 0 .../optimizer}/test-js-optimizer-asm-pre.js | 0 ...est-js-optimizer-asm-regs-harder-output.js | 0 ...st-js-optimizer-asm-regs-harder-output2.js | 0 ...st-js-optimizer-asm-regs-harder-output3.js | 0 .../test-js-optimizer-asm-regs-harder.js | 0 .../test-js-optimizer-asm-regs-min-output.js | 0 .../test-js-optimizer-asm-regs-min.js | 0 .../test-js-optimizer-asm-regs-output.js | 0 .../optimizer}/test-js-optimizer-asm-regs.js | 0 .../test-js-optimizer-asm-relocate-output.js | 0 .../test-js-optimizer-asm-relocate.js | 0 ...test-js-optimizer-ensureLabelSet-output.js | 0 .../test-js-optimizer-ensureLabelSet.js | 0 .../test-js-optimizer-localCSE-output.js | 0 .../optimizer}/test-js-optimizer-localCSE.js | 0 .../optimizer}/test-js-optimizer-output.js | 0 .../test-js-optimizer-pointerMask-output.js | 0 .../test-js-optimizer-pointerMask.js | 0 .../test-js-optimizer-regs-output.js | 0 .../optimizer}/test-js-optimizer-regs.js | 0 ...st-js-optimizer-shiftsAggressive-output.js | 0 .../test-js-optimizer-shiftsAggressive.js | 0 .../optimizer}/test-js-optimizer-si-output.js | 0 .../optimizer}/test-js-optimizer-si.js | 0 .../optimizer}/test-js-optimizer-t2-output.js | 0 .../optimizer}/test-js-optimizer-t2.js | 0 .../test-js-optimizer-t2c-output.js | 0 .../optimizer}/test-js-optimizer-t2c.js | 0 .../optimizer}/test-js-optimizer-t3-output.js | 0 .../optimizer}/test-js-optimizer-t3.js | 0 .../optimizer}/test-js-optimizer.js | 0 tests/test_other.py | 52 +++++++++---------- 56 files changed, 26 insertions(+), 26 deletions(-) rename {tools/eliminator => tests/optimizer}/asm-eliminator-test-output.js (100%) rename {tools/eliminator => tests/optimizer}/asm-eliminator-test.js (100%) rename {tools/eliminator => tests/optimizer}/eliminator-test-output.js (100%) rename {tools/eliminator => tests/optimizer}/eliminator-test.js (100%) rename {tools/eliminator => tests/optimizer}/safe-eliminator-test-output.js (100%) rename {tools/eliminator => tests/optimizer}/safe-eliminator-test.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-last-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-last-output2.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-last.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-lastOpts-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-lastOpts-output2.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-minlast-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-minlast.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-outline1-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-outline1.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-outline2-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-outline2.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-outline3-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-outline3.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-pre-f32.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-pre-output-f32-nosimp.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-pre-output-f32.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-pre-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-pre-output2.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-pre.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-harder-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-harder-output2.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-harder-output3.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-harder.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-min-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-min.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-regs.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-relocate-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-asm-relocate.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-ensureLabelSet-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-ensureLabelSet.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-localCSE-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-localCSE.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-pointerMask-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-pointerMask.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-regs-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-regs.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-shiftsAggressive-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-shiftsAggressive.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-si-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-si.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-t2-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-t2.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-t2c-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-t2c.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-t3-output.js (100%) rename {tools => tests/optimizer}/test-js-optimizer-t3.js (100%) rename {tools => tests/optimizer}/test-js-optimizer.js (100%) diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tests/optimizer/asm-eliminator-test-output.js similarity index 100% rename from tools/eliminator/asm-eliminator-test-output.js rename to tests/optimizer/asm-eliminator-test-output.js diff --git a/tools/eliminator/asm-eliminator-test.js b/tests/optimizer/asm-eliminator-test.js similarity index 100% rename from tools/eliminator/asm-eliminator-test.js rename to tests/optimizer/asm-eliminator-test.js diff --git a/tools/eliminator/eliminator-test-output.js b/tests/optimizer/eliminator-test-output.js similarity index 100% rename from tools/eliminator/eliminator-test-output.js rename to tests/optimizer/eliminator-test-output.js diff --git a/tools/eliminator/eliminator-test.js b/tests/optimizer/eliminator-test.js similarity index 100% rename from tools/eliminator/eliminator-test.js rename to tests/optimizer/eliminator-test.js diff --git a/tools/eliminator/safe-eliminator-test-output.js b/tests/optimizer/safe-eliminator-test-output.js similarity index 100% rename from tools/eliminator/safe-eliminator-test-output.js rename to tests/optimizer/safe-eliminator-test-output.js diff --git a/tools/eliminator/safe-eliminator-test.js b/tests/optimizer/safe-eliminator-test.js similarity index 100% rename from tools/eliminator/safe-eliminator-test.js rename to tests/optimizer/safe-eliminator-test.js diff --git a/tools/test-js-optimizer-asm-last-output.js b/tests/optimizer/test-js-optimizer-asm-last-output.js similarity index 100% rename from tools/test-js-optimizer-asm-last-output.js rename to tests/optimizer/test-js-optimizer-asm-last-output.js diff --git a/tools/test-js-optimizer-asm-last-output2.js b/tests/optimizer/test-js-optimizer-asm-last-output2.js similarity index 100% rename from tools/test-js-optimizer-asm-last-output2.js rename to tests/optimizer/test-js-optimizer-asm-last-output2.js diff --git a/tools/test-js-optimizer-asm-last.js b/tests/optimizer/test-js-optimizer-asm-last.js similarity index 100% rename from tools/test-js-optimizer-asm-last.js rename to tests/optimizer/test-js-optimizer-asm-last.js diff --git a/tools/test-js-optimizer-asm-lastOpts-output.js b/tests/optimizer/test-js-optimizer-asm-lastOpts-output.js similarity index 100% rename from tools/test-js-optimizer-asm-lastOpts-output.js rename to tests/optimizer/test-js-optimizer-asm-lastOpts-output.js diff --git a/tools/test-js-optimizer-asm-lastOpts-output2.js b/tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js similarity index 100% rename from tools/test-js-optimizer-asm-lastOpts-output2.js rename to tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js diff --git a/tools/test-js-optimizer-asm-minlast-output.js b/tests/optimizer/test-js-optimizer-asm-minlast-output.js similarity index 100% rename from tools/test-js-optimizer-asm-minlast-output.js rename to tests/optimizer/test-js-optimizer-asm-minlast-output.js diff --git a/tools/test-js-optimizer-asm-minlast.js b/tests/optimizer/test-js-optimizer-asm-minlast.js similarity index 100% rename from tools/test-js-optimizer-asm-minlast.js rename to tests/optimizer/test-js-optimizer-asm-minlast.js diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tests/optimizer/test-js-optimizer-asm-outline1-output.js similarity index 100% rename from tools/test-js-optimizer-asm-outline1-output.js rename to tests/optimizer/test-js-optimizer-asm-outline1-output.js diff --git a/tools/test-js-optimizer-asm-outline1.js b/tests/optimizer/test-js-optimizer-asm-outline1.js similarity index 100% rename from tools/test-js-optimizer-asm-outline1.js rename to tests/optimizer/test-js-optimizer-asm-outline1.js diff --git a/tools/test-js-optimizer-asm-outline2-output.js b/tests/optimizer/test-js-optimizer-asm-outline2-output.js similarity index 100% rename from tools/test-js-optimizer-asm-outline2-output.js rename to tests/optimizer/test-js-optimizer-asm-outline2-output.js diff --git a/tools/test-js-optimizer-asm-outline2.js b/tests/optimizer/test-js-optimizer-asm-outline2.js similarity index 100% rename from tools/test-js-optimizer-asm-outline2.js rename to tests/optimizer/test-js-optimizer-asm-outline2.js diff --git a/tools/test-js-optimizer-asm-outline3-output.js b/tests/optimizer/test-js-optimizer-asm-outline3-output.js similarity index 100% rename from tools/test-js-optimizer-asm-outline3-output.js rename to tests/optimizer/test-js-optimizer-asm-outline3-output.js diff --git a/tools/test-js-optimizer-asm-outline3.js b/tests/optimizer/test-js-optimizer-asm-outline3.js similarity index 100% rename from tools/test-js-optimizer-asm-outline3.js rename to tests/optimizer/test-js-optimizer-asm-outline3.js diff --git a/tools/test-js-optimizer-asm-pre-f32.js b/tests/optimizer/test-js-optimizer-asm-pre-f32.js similarity index 100% rename from tools/test-js-optimizer-asm-pre-f32.js rename to tests/optimizer/test-js-optimizer-asm-pre-f32.js diff --git a/tools/test-js-optimizer-asm-pre-output-f32-nosimp.js b/tests/optimizer/test-js-optimizer-asm-pre-output-f32-nosimp.js similarity index 100% rename from tools/test-js-optimizer-asm-pre-output-f32-nosimp.js rename to tests/optimizer/test-js-optimizer-asm-pre-output-f32-nosimp.js diff --git a/tools/test-js-optimizer-asm-pre-output-f32.js b/tests/optimizer/test-js-optimizer-asm-pre-output-f32.js similarity index 100% rename from tools/test-js-optimizer-asm-pre-output-f32.js rename to tests/optimizer/test-js-optimizer-asm-pre-output-f32.js diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tests/optimizer/test-js-optimizer-asm-pre-output.js similarity index 100% rename from tools/test-js-optimizer-asm-pre-output.js rename to tests/optimizer/test-js-optimizer-asm-pre-output.js diff --git a/tools/test-js-optimizer-asm-pre-output2.js b/tests/optimizer/test-js-optimizer-asm-pre-output2.js similarity index 100% rename from tools/test-js-optimizer-asm-pre-output2.js rename to tests/optimizer/test-js-optimizer-asm-pre-output2.js diff --git a/tools/test-js-optimizer-asm-pre.js b/tests/optimizer/test-js-optimizer-asm-pre.js similarity index 100% rename from tools/test-js-optimizer-asm-pre.js rename to tests/optimizer/test-js-optimizer-asm-pre.js diff --git a/tools/test-js-optimizer-asm-regs-harder-output.js b/tests/optimizer/test-js-optimizer-asm-regs-harder-output.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-harder-output.js rename to tests/optimizer/test-js-optimizer-asm-regs-harder-output.js diff --git a/tools/test-js-optimizer-asm-regs-harder-output2.js b/tests/optimizer/test-js-optimizer-asm-regs-harder-output2.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-harder-output2.js rename to tests/optimizer/test-js-optimizer-asm-regs-harder-output2.js diff --git a/tools/test-js-optimizer-asm-regs-harder-output3.js b/tests/optimizer/test-js-optimizer-asm-regs-harder-output3.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-harder-output3.js rename to tests/optimizer/test-js-optimizer-asm-regs-harder-output3.js diff --git a/tools/test-js-optimizer-asm-regs-harder.js b/tests/optimizer/test-js-optimizer-asm-regs-harder.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-harder.js rename to tests/optimizer/test-js-optimizer-asm-regs-harder.js diff --git a/tools/test-js-optimizer-asm-regs-min-output.js b/tests/optimizer/test-js-optimizer-asm-regs-min-output.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-min-output.js rename to tests/optimizer/test-js-optimizer-asm-regs-min-output.js diff --git a/tools/test-js-optimizer-asm-regs-min.js b/tests/optimizer/test-js-optimizer-asm-regs-min.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-min.js rename to tests/optimizer/test-js-optimizer-asm-regs-min.js diff --git a/tools/test-js-optimizer-asm-regs-output.js b/tests/optimizer/test-js-optimizer-asm-regs-output.js similarity index 100% rename from tools/test-js-optimizer-asm-regs-output.js rename to tests/optimizer/test-js-optimizer-asm-regs-output.js diff --git a/tools/test-js-optimizer-asm-regs.js b/tests/optimizer/test-js-optimizer-asm-regs.js similarity index 100% rename from tools/test-js-optimizer-asm-regs.js rename to tests/optimizer/test-js-optimizer-asm-regs.js diff --git a/tools/test-js-optimizer-asm-relocate-output.js b/tests/optimizer/test-js-optimizer-asm-relocate-output.js similarity index 100% rename from tools/test-js-optimizer-asm-relocate-output.js rename to tests/optimizer/test-js-optimizer-asm-relocate-output.js diff --git a/tools/test-js-optimizer-asm-relocate.js b/tests/optimizer/test-js-optimizer-asm-relocate.js similarity index 100% rename from tools/test-js-optimizer-asm-relocate.js rename to tests/optimizer/test-js-optimizer-asm-relocate.js diff --git a/tools/test-js-optimizer-ensureLabelSet-output.js b/tests/optimizer/test-js-optimizer-ensureLabelSet-output.js similarity index 100% rename from tools/test-js-optimizer-ensureLabelSet-output.js rename to tests/optimizer/test-js-optimizer-ensureLabelSet-output.js diff --git a/tools/test-js-optimizer-ensureLabelSet.js b/tests/optimizer/test-js-optimizer-ensureLabelSet.js similarity index 100% rename from tools/test-js-optimizer-ensureLabelSet.js rename to tests/optimizer/test-js-optimizer-ensureLabelSet.js diff --git a/tools/test-js-optimizer-localCSE-output.js b/tests/optimizer/test-js-optimizer-localCSE-output.js similarity index 100% rename from tools/test-js-optimizer-localCSE-output.js rename to tests/optimizer/test-js-optimizer-localCSE-output.js diff --git a/tools/test-js-optimizer-localCSE.js b/tests/optimizer/test-js-optimizer-localCSE.js similarity index 100% rename from tools/test-js-optimizer-localCSE.js rename to tests/optimizer/test-js-optimizer-localCSE.js diff --git a/tools/test-js-optimizer-output.js b/tests/optimizer/test-js-optimizer-output.js similarity index 100% rename from tools/test-js-optimizer-output.js rename to tests/optimizer/test-js-optimizer-output.js diff --git a/tools/test-js-optimizer-pointerMask-output.js b/tests/optimizer/test-js-optimizer-pointerMask-output.js similarity index 100% rename from tools/test-js-optimizer-pointerMask-output.js rename to tests/optimizer/test-js-optimizer-pointerMask-output.js diff --git a/tools/test-js-optimizer-pointerMask.js b/tests/optimizer/test-js-optimizer-pointerMask.js similarity index 100% rename from tools/test-js-optimizer-pointerMask.js rename to tests/optimizer/test-js-optimizer-pointerMask.js diff --git a/tools/test-js-optimizer-regs-output.js b/tests/optimizer/test-js-optimizer-regs-output.js similarity index 100% rename from tools/test-js-optimizer-regs-output.js rename to tests/optimizer/test-js-optimizer-regs-output.js diff --git a/tools/test-js-optimizer-regs.js b/tests/optimizer/test-js-optimizer-regs.js similarity index 100% rename from tools/test-js-optimizer-regs.js rename to tests/optimizer/test-js-optimizer-regs.js diff --git a/tools/test-js-optimizer-shiftsAggressive-output.js b/tests/optimizer/test-js-optimizer-shiftsAggressive-output.js similarity index 100% rename from tools/test-js-optimizer-shiftsAggressive-output.js rename to tests/optimizer/test-js-optimizer-shiftsAggressive-output.js diff --git a/tools/test-js-optimizer-shiftsAggressive.js b/tests/optimizer/test-js-optimizer-shiftsAggressive.js similarity index 100% rename from tools/test-js-optimizer-shiftsAggressive.js rename to tests/optimizer/test-js-optimizer-shiftsAggressive.js diff --git a/tools/test-js-optimizer-si-output.js b/tests/optimizer/test-js-optimizer-si-output.js similarity index 100% rename from tools/test-js-optimizer-si-output.js rename to tests/optimizer/test-js-optimizer-si-output.js diff --git a/tools/test-js-optimizer-si.js b/tests/optimizer/test-js-optimizer-si.js similarity index 100% rename from tools/test-js-optimizer-si.js rename to tests/optimizer/test-js-optimizer-si.js diff --git a/tools/test-js-optimizer-t2-output.js b/tests/optimizer/test-js-optimizer-t2-output.js similarity index 100% rename from tools/test-js-optimizer-t2-output.js rename to tests/optimizer/test-js-optimizer-t2-output.js diff --git a/tools/test-js-optimizer-t2.js b/tests/optimizer/test-js-optimizer-t2.js similarity index 100% rename from tools/test-js-optimizer-t2.js rename to tests/optimizer/test-js-optimizer-t2.js diff --git a/tools/test-js-optimizer-t2c-output.js b/tests/optimizer/test-js-optimizer-t2c-output.js similarity index 100% rename from tools/test-js-optimizer-t2c-output.js rename to tests/optimizer/test-js-optimizer-t2c-output.js diff --git a/tools/test-js-optimizer-t2c.js b/tests/optimizer/test-js-optimizer-t2c.js similarity index 100% rename from tools/test-js-optimizer-t2c.js rename to tests/optimizer/test-js-optimizer-t2c.js diff --git a/tools/test-js-optimizer-t3-output.js b/tests/optimizer/test-js-optimizer-t3-output.js similarity index 100% rename from tools/test-js-optimizer-t3-output.js rename to tests/optimizer/test-js-optimizer-t3-output.js diff --git a/tools/test-js-optimizer-t3.js b/tests/optimizer/test-js-optimizer-t3.js similarity index 100% rename from tools/test-js-optimizer-t3.js rename to tests/optimizer/test-js-optimizer-t3.js diff --git a/tools/test-js-optimizer.js b/tests/optimizer/test-js-optimizer.js similarity index 100% rename from tools/test-js-optimizer.js rename to tests/optimizer/test-js-optimizer.js diff --git a/tests/test_other.py b/tests/test_other.py index d6a0aa3c0dc41..12b68aabcfaca 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1881,57 +1881,57 @@ def test_fix_closure(self): def test_js_optimizer(self): for input, expected, passes in [ - (path_from_root('tools', 'test-js-optimizer.js'), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-output.js')).read(), ['hoistMultiples', 'removeAssignsToUndefined', 'simplifyExpressions']), - (path_from_root('tools', 'test-js-optimizer-t2c.js'), open(path_from_root('tools', 'test-js-optimizer-t2c-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-t2c.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-t2c-output.js')).read(), ['simplifyExpressions', 'optimizeShiftsConservative']), - (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-t2.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-t2-output.js')).read(), ['simplifyExpressions', 'optimizeShiftsAggressive']), - (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-t3.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-t3-output.js')).read(), ['optimizeShiftsAggressive']), - (path_from_root('tools', 'test-js-optimizer-si.js'), open(path_from_root('tools', 'test-js-optimizer-si-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-si.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-si-output.js')).read(), ['simplifyIfs']), - (path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-regs.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-regs-output.js')).read(), ['registerize']), - (path_from_root('tools', 'eliminator', 'eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read(), + (path_from_root('tests', 'optimizer', 'eliminator-test.js'), open(path_from_root('tests', 'optimizer', 'eliminator-test-output.js')).read(), ['eliminate']), - (path_from_root('tools', 'eliminator', 'safe-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'safe-eliminator-test-output.js')).read(), + (path_from_root('tests', 'optimizer', 'safe-eliminator-test.js'), open(path_from_root('tests', 'optimizer', 'safe-eliminator-test-output.js')).read(), ['eliminateMemSafe']), - (path_from_root('tools', 'eliminator', 'asm-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'asm-eliminator-test-output.js')).read(), + (path_from_root('tests', 'optimizer', 'asm-eliminator-test.js'), open(path_from_root('tests', 'optimizer', 'asm-eliminator-test-output.js')).read(), ['asm', 'eliminate']), - (path_from_root('tools', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-output.js')).read(), ['asm', 'registerize']), - (path_from_root('tools', 'test-js-optimizer-asm-regs-harder.js'), [open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output2.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output3.js')).read()], + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-harder.js'), [open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-harder-output.js')).read(), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-harder-output2.js')).read(), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-harder-output3.js')).read()], ['asm', 'registerizeHarder']), - (path_from_root('tools', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-min-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-regs-min-output.js')).read(), ['asm', 'registerize', 'minifyLocals']), - (path_from_root('tools', 'test-js-optimizer-asm-pre.js'), [open(path_from_root('tools', 'test-js-optimizer-asm-pre-output.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output2.js')).read()], + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre.js'), [open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre-output.js')).read(), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre-output2.js')).read()], ['asm', 'simplifyExpressions']), - (path_from_root('tools', 'test-js-optimizer-asm-pre-f32.js'), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output-f32.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre-f32.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre-output-f32.js')).read(), ['asm', 'asmPreciseF32', 'simplifyExpressions', 'optimizeFrounds']), - (path_from_root('tools', 'test-js-optimizer-asm-pre-f32.js'), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output-f32-nosimp.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre-f32.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-pre-output-f32-nosimp.js')).read(), ['asm', 'asmPreciseF32', 'optimizeFrounds']), - (path_from_root('tools', 'test-js-optimizer-asm-last.js'), [open(path_from_root('tools', 'test-js-optimizer-asm-lastOpts-output.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-lastOpts-output2.js')).read()], + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-last.js'), [open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-lastOpts-output.js')).read(), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-lastOpts-output2.js')).read()], ['asm', 'asmLastOpts']), - (path_from_root('tools', 'test-js-optimizer-asm-last.js'), [open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-last-output2.js')).read()], + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-last.js'), [open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-last-output.js')).read(), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-last-output2.js')).read()], ['asm', 'asmLastOpts', 'last']), - (path_from_root('tools', 'test-js-optimizer-asm-relocate.js'), open(path_from_root('tools', 'test-js-optimizer-asm-relocate-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-relocate.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-relocate-output.js')).read(), ['asm', 'relocate']), - (path_from_root('tools', 'test-js-optimizer-asm-outline1.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline1-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-outline1.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-outline1-output.js')).read(), ['asm', 'outline']), - (path_from_root('tools', 'test-js-optimizer-asm-outline2.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline2-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-outline2.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-outline2-output.js')).read(), ['asm', 'outline']), - (path_from_root('tools', 'test-js-optimizer-asm-outline3.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline3-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-outline3.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-outline3-output.js')).read(), ['asm', 'outline']), - (path_from_root('tools', 'test-js-optimizer-asm-minlast.js'), open(path_from_root('tools', 'test-js-optimizer-asm-minlast-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-minlast.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-asm-minlast-output.js')).read(), ['asm', 'minifyWhitespace', 'asmLastOpts', 'last']), - (path_from_root('tools', 'test-js-optimizer-shiftsAggressive.js'), open(path_from_root('tools', 'test-js-optimizer-shiftsAggressive-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-shiftsAggressive.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-shiftsAggressive-output.js')).read(), ['asm', 'aggressiveVariableElimination']), - (path_from_root('tools', 'test-js-optimizer-pointerMask.js'), open(path_from_root('tools', 'test-js-optimizer-pointerMask-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-pointerMask.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-pointerMask-output.js')).read(), ['pointerMasking']), - (path_from_root('tools', 'test-js-optimizer-localCSE.js'), open(path_from_root('tools', 'test-js-optimizer-localCSE-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-localCSE.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-localCSE-output.js')).read(), ['asm', 'localCSE']), - (path_from_root('tools', 'test-js-optimizer-ensureLabelSet.js'), open(path_from_root('tools', 'test-js-optimizer-ensureLabelSet-output.js')).read(), + (path_from_root('tests', 'optimizer', 'test-js-optimizer-ensureLabelSet.js'), open(path_from_root('tests', 'optimizer', 'test-js-optimizer-ensureLabelSet-output.js')).read(), ['asm', 'ensureLabelSet']), ]: print input, passes From 14c623cf1640cdc493927ca4f57320c5404509ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 20 Dec 2014 12:32:44 -0500 Subject: [PATCH 50/75] Fix printNum on Visual Studio: sscanf does not scan unsigned hexadecimal 64-bit integers with format specifier "%lf" to a double, so instead explicitly scan hex strings with "%llx". Fixes parsing and writing string hex numbers such as "0x8000000000000000". --- tools/optimizer/simple_ast.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 44436cebd8772..6662aa0504b4b 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -829,8 +829,15 @@ struct JSPrinter { assert(d >= 0); unsigned long long uu = (unsigned long long)d; if (uu == d) { - snprintf(buffer, BUFFERSIZE-1, (e && !finalize) ? "0x%llx" : "%llu", uu); - sscanf(buffer, "%lf", &temp); + bool asHex = e && !finalize; + snprintf(buffer, BUFFERSIZE-1, asHex ? "0x%llx" : "%llu", uu); + if (asHex) { + unsigned long long tempULL; + sscanf(buffer, "%llx", &tempULL); + temp = (double)tempULL; + } else { + sscanf(buffer, "%lf", &temp); + } } else { // too large for a machine integer, just use floats snprintf(buffer, BUFFERSIZE-1, e ? "%e" : "%.0f", d); // even on integers, e with a dot is useful, e.g. 1.2e+200 From 7169a028959105afa11e5916179fa7666f3a938c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 20 Dec 2014 13:24:57 -0500 Subject: [PATCH 51/75] Add better handling of Windows \r\n on input file read to avoid \r characters in memory. --- tools/optimizer/optimizer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 463bbe74b68b6..16d3eb6e72c5c 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -3832,16 +3832,19 @@ int main(int argc, char **argv) { } // Read input file - FILE *f = fopen(argv[1], "rb"); + FILE *f = fopen(argv[1], "r"); assert(f); fseek(f, 0, SEEK_END); int size = ftell(f); char *input = new char[size+1]; rewind(f); int num = fread(input, 1, size, f); - assert(num == size); + // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when + // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one), + // so return value of fread can be less than size reported by ftell, and that is normal. + assert((num > 0 || size == 0) && num <= size); fclose(f); - input[size] = 0; + input[num] = 0; char *extraInfoStart = strstr(input, "// EXTRA_INFO:"); if (extraInfoStart) { From 0fc516f95c79d3f491a847479b1cd285d3d4660d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 20 Dec 2014 13:38:22 -0500 Subject: [PATCH 52/75] Print native optimizer invocations on EM_BUILD_VERBOSE=3 --- tools/js_optimizer.py | 2 ++ tools/optimizer/optimizer.cpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index c9b1dab49566c..bd10af5213fee 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -166,6 +166,8 @@ def run_on_chunk(command): while os.path.exists(saved): saved = 'input' + str(int(saved.replace('input', '').replace('.txt', ''))+1) + '.txt' print >> sys.stderr, 'running js optimizer command', ' '.join(map(lambda c: c if c != filename else saved, command)) shutil.copyfile(filename, os.path.join('/tmp/emscripten_temp', saved)) + verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0 + if verbose_level >= 3: print >> sys.stderr, str(command) proc = subprocess.Popen(command, stdout=subprocess.PIPE) output = proc.communicate()[0] assert proc.returncode == 0, 'Error in optimizer: ' + output diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 16d3eb6e72c5c..ef006795c1883 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -3896,7 +3896,6 @@ int main(int argc, char **argv) { jser.printAst(); std::cout << jser.buffer << "\n"; } - return 0; } From 9d58d0de968d07e703a31086dd62b3d95ad4557b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 20 Dec 2014 13:49:38 -0500 Subject: [PATCH 53/75] Fix line endings in Windows generation of output files from native optimizer: writing \r\n data to ascii text file would duplicate line endings to \r\r\n. --- tools/js_optimizer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index bd10af5213fee..4321e8a577404 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -173,7 +173,9 @@ def run_on_chunk(command): assert proc.returncode == 0, 'Error in optimizer: ' + output assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in optimizer: ' + output filename = temp_files.get(os.path.basename(filename) + '.jo.js').name - f = open(filename, 'w') + # Important to write out in binary mode, because the data we are writing contains Windows line endings '\r\n' because it was PIPED from console. + # Otherwise writing \r\n to ascii mode file will result in Windows amplifying \n to \r\n, generating bad \r\r\n line endings. + f = open(filename, 'wb') f.write(output) f.close() if DEBUG and not shared.WINDOWS: print >> sys.stderr, '.' # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console. From 28cfabaf482b1fca2b0c112ec320dcae26230266 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 20 Dec 2014 13:12:02 -0800 Subject: [PATCH 54/75] add testcase for #3099 --- tests/optimizer/test-js-optimizer-asm-last-output.js | 3 +++ tests/optimizer/test-js-optimizer-asm-last-output2.js | 3 +++ tests/optimizer/test-js-optimizer-asm-last.js | 3 +++ tests/optimizer/test-js-optimizer-asm-lastOpts-output.js | 3 +++ tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js | 3 +++ 5 files changed, 15 insertions(+) diff --git a/tests/optimizer/test-js-optimizer-asm-last-output.js b/tests/optimizer/test-js-optimizer-asm-last-output.js index bee401e5df96e..cab9bee2edaa4 100644 --- a/tests/optimizer/test-js-optimizer-asm-last-output.js +++ b/tests/optimizer/test-js-optimizer-asm-last-output.js @@ -33,6 +33,9 @@ function finall(x) { a = 1.1234567890123457e+21; f(g() | 0); x = 1.7976931348623157e+308; + a = 9007199254740992; + a = 9007199254740992; + a = 9007199254740994; return 12.0e10; } function looop() { diff --git a/tests/optimizer/test-js-optimizer-asm-last-output2.js b/tests/optimizer/test-js-optimizer-asm-last-output2.js index 1173ccdb48b92..1869ce255e997 100644 --- a/tests/optimizer/test-js-optimizer-asm-last-output2.js +++ b/tests/optimizer/test-js-optimizer-asm-last-output2.js @@ -33,6 +33,9 @@ function finall(x) { a = 1123456789012345651200.0; f(g() | 0); x = 1797693134862315708145274e284; + a = 9007199254740992; + a = 9007199254740992; + a = 9007199254740994; return 12.0e10; } function looop() { diff --git a/tests/optimizer/test-js-optimizer-asm-last.js b/tests/optimizer/test-js-optimizer-asm-last.js index 54142ed519fe0..97997356c18e3 100644 --- a/tests/optimizer/test-js-optimizer-asm-last.js +++ b/tests/optimizer/test-js-optimizer-asm-last.js @@ -33,6 +33,9 @@ function finall(x) { a = +0x3ce7184d470dd60000; f(g() & -1); x = 1.7976931348623157e+308; + a = 9007199254740992; // 2^53, the largest integer that can be represented in a double such that all smaller integers are also representable. + a = 9007199254740993; // 2^53 + 1 cannot be represented as double. + a = 9007199254740994; // This is again representable as double. return +12e10; } function looop() { diff --git a/tests/optimizer/test-js-optimizer-asm-lastOpts-output.js b/tests/optimizer/test-js-optimizer-asm-lastOpts-output.js index cba0ea237b6f1..b5b4d98064331 100644 --- a/tests/optimizer/test-js-optimizer-asm-lastOpts-output.js +++ b/tests/optimizer/test-js-optimizer-asm-lastOpts-output.js @@ -33,6 +33,9 @@ function finall(x) { a = +0x3ce7184d470dd60000; f(g() | 0); x = 1.7976931348623157e+308; + a = 9007199254740992; + a = 9007199254740992; + a = 9007199254740994; return +12e10; } function looop() { diff --git a/tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js b/tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js index 780d793e1470d..3200dbbd244f6 100644 --- a/tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js +++ b/tests/optimizer/test-js-optimizer-asm-lastOpts-output2.js @@ -33,6 +33,9 @@ function finall(x) { a = +1123456789012345651200; f(g() | 0); x = 1797693134862315708145274e284; + a = 9007199254740992; + a = 9007199254740992; + a = 9007199254740994; return +12e10; } function looop() { From fb057d31b19a79ce161398e524f95fd4b6d380ce Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 20 Dec 2014 17:28:10 -0800 Subject: [PATCH 55/75] add missing __expo2[f].c files; fixes #3101 --- system/lib/libc/musl/src/math/__expo2.c | 16 ++++++++++++++++ system/lib/libc/musl/src/math/__expo2f.c | 16 ++++++++++++++++ tools/system_libs.py | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 system/lib/libc/musl/src/math/__expo2.c create mode 100644 system/lib/libc/musl/src/math/__expo2f.c diff --git a/system/lib/libc/musl/src/math/__expo2.c b/system/lib/libc/musl/src/math/__expo2.c new file mode 100644 index 0000000000000..740ac680e8570 --- /dev/null +++ b/system/lib/libc/musl/src/math/__expo2.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ +static const int k = 2043; +static const double kln2 = 0x1.62066151add8bp+10; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +double __expo2(double x) +{ + double scale; + + /* note that k is odd and scale*scale overflows */ + INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/system/lib/libc/musl/src/math/__expo2f.c b/system/lib/libc/musl/src/math/__expo2f.c new file mode 100644 index 0000000000000..5163e4180033b --- /dev/null +++ b/system/lib/libc/musl/src/math/__expo2f.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +static const int k = 235; +static const float kln2 = 0x1.45c778p+7f; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +float __expo2f(float x) +{ + float scale; + + /* note that k is odd and scale*scale overflows */ + SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + return expf(x - kln2) * scale * scale; +} diff --git a/tools/system_libs.py b/tools/system_libs.py index 4bc8b40303849..c7bdcd598c95e 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -107,6 +107,8 @@ def create_libc(): 'shgetc.c', ]], ['math', [ + '__expo2.c', + '__expo2f.c', '__fpclassify.c', '__fpclassifyf.c', '__fpclassifyl.c', From 33dc4b7f83a3d9f48183ef6e15badd3813f0b798 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 20 Dec 2014 21:35:16 -0800 Subject: [PATCH 56/75] add closure to list of passes the native optimizer can run, so we see all the passes at once, and can minify whitespace when needed, like in the js optimizer --- tests/test_other.py | 3 ++- tools/js_optimizer.py | 2 +- tools/shared.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index 12b68aabcfaca..8366643dc7a50 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -168,7 +168,8 @@ def test_emcc(self): # emcc -s RELOOP=1 src.cpp ==> should pass -s to emscripten.py. --typed-arrays is a convenient alias for -s USE_TYPED_ARRAYS for params, test, text in [ (['-O2'], lambda generated: 'function intArrayToString' in generated, 'shell has unminified utilities'), - (['-O2', '--closure', '1'], lambda generated: 'function intArrayToString' not in generated, 'closure minifies the shell'), + (['-O2', '--closure', '1'], lambda generated: 'function intArrayToString' not in generated and ';function' in generated, 'closure minifies the shell, removes whitespace'), + (['-O2', '--closure', '1', '-g1'], lambda generated: 'function intArrayToString' not in generated and ';function' not in generated, 'closure minifies the shell, -g1 makes it keep whitespace'), (['-O2'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2'), (['-O2', '--minify', '0'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'minify is cancelled, but not registerize'), (['-O2', '--js-opts', '0'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'js opts are cancelled'), diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 4321e8a577404..125b9733f426e 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -9,7 +9,7 @@ def path_from_root(*pathelems): return os.path.join(__rootpath__, *pathelems) -NATIVE_PASSES = set(['asm', 'asmPreciseF32', 'receiveJSON', 'emitJSON', 'eliminate', 'eliminateMemSafe', 'simplifyExpressions', 'simplifyIfs', 'optimizeFrounds', 'registerize', 'registerizeHarder', 'minifyNames', 'minifyLocals', 'minifyWhitespace', 'cleanup', 'asmLastOpts', 'last', 'noop']) +NATIVE_PASSES = set(['asm', 'asmPreciseF32', 'receiveJSON', 'emitJSON', 'eliminate', 'eliminateMemSafe', 'simplifyExpressions', 'simplifyIfs', 'optimizeFrounds', 'registerize', 'registerizeHarder', 'minifyNames', 'minifyLocals', 'minifyWhitespace', 'cleanup', 'asmLastOpts', 'last', 'noop', 'closure']) JS_OPTIMIZER = path_from_root('tools', 'js-optimizer.js') diff --git a/tools/shared.py b/tools/shared.py index d6c590d2fab84..afeb931956985 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1660,6 +1660,7 @@ def closure_compiler(filename, pretty=True): if pretty: args += ['--formatting', 'PRETTY_PRINT'] if os.environ.get('EMCC_CLOSURE_ARGS'): args += shlex.split(os.environ.get('EMCC_CLOSURE_ARGS')) + logging.debug('closure compiler: ' + ' '.join(args)) process = Popen(args, stdout=PIPE, stderr=STDOUT) cc_output = process.communicate()[0] if process.returncode != 0 or not os.path.exists(filename + '.cc.js'): From 6fa69f8f4619da8ce4a00c3d3a2f8a94ee12f2a8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 21 Dec 2014 10:59:53 -0800 Subject: [PATCH 57/75] temporarily disable test_simd7; issue #3103 --- tests/test_core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_core.py b/tests/test_core.py index 9a4e2548261fb..b98b774abda91 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5298,6 +5298,7 @@ def test_simd6(self): def test_simd7(self): # test_simd7 is to test negative zero handling. + return self.skip('see issue #3103') if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('needs fastcomp') From 278ec84fbb517ba8081db979ed15bb21701ee66d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 21 Dec 2014 11:27:43 -0800 Subject: [PATCH 58/75] add SDL to list of libraries we don't need to issue link warnings about --- emcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc b/emcc index fd4e4c75ff6cd..898f822350137 100755 --- a/emcc +++ b/emcc @@ -830,7 +830,7 @@ try: break if found: break if found: break - if not found and lib not in ['GL', 'GLU', 'glut']: # whitelist our default libraries + if not found and lib not in ['GL', 'GLU', 'glut', 'SDL']: # whitelist our default libraries logging.warning('emcc: cannot find library "%s"', lib) # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so From 746b2113356a6d0d1e4ba4e7c3a871f9109761da Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 26 Dec 2014 17:27:56 -0800 Subject: [PATCH 59/75] Optimize xmmintrin.h comparisons and loads Add notEqual functions to Emscripten's vector.h, and make use of them to optimize relevant comparison intrinsics in xmmintrin.h. And, optimize the load intrinsics so that we don't depend as much on the optimizer to get these right. --- system/include/emscripten/vector.h | 2 ++ system/include/emscripten/xmmintrin.h | 50 +++++++++++---------------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/system/include/emscripten/vector.h b/system/include/emscripten/vector.h index 0b51af3581745..541ccb6a7e661 100644 --- a/system/include/emscripten/vector.h +++ b/system/include/emscripten/vector.h @@ -19,6 +19,7 @@ float32x4 emscripten_float32x4_sqrt(float32x4 __a) __attribute__((__nothrow__, _ int32x4 emscripten_float32x4_lessThan(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_float32x4_lessThanOrEqual(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_float32x4_equal(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); +int32x4 emscripten_float32x4_notEqual(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_float32x4_greaterThanOrEqual(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_float32x4_greaterThan(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); float32x4 emscripten_float32x4_and(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); @@ -33,6 +34,7 @@ int32x4 emscripten_int32x4_fromFloat32x4(float32x4 __a) __attribute__((__nothrow int32x4 emscripten_int32x4_lessThan(int32x4 __a, int32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_int32x4_lessThanOrEqual(int32x4 __a, int32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_int32x4_equal(int32x4 __a, int32x4 __b) __attribute__((__nothrow__, __const__)); +int32x4 emscripten_int32x4_notEqual(int32x4 __a, int32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_int32x4_greaterThanOrEqual(int32x4 __a, int32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_int32x4_greaterThan(int32x4 __a, int32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_int32x4_select(int32x4 __a, int32x4 __b, int32x4 __c) __attribute__((__nothrow__, __const__)); diff --git a/system/include/emscripten/xmmintrin.h b/system/include/emscripten/xmmintrin.h index 96a9ed2c87a00..8e74688ff5cc1 100644 --- a/system/include/emscripten/xmmintrin.h +++ b/system/include/emscripten/xmmintrin.h @@ -53,19 +53,24 @@ _mm_load_ps(const float *__p) static __inline__ __m128 __attribute__((__always_inline__)) _mm_loadl_pi(__m128 __a, const void /*__m64*/ *__p) { + // TODO: This actually corresponds to the SIMD.float32x4.loadXY function in + // SIMD.js. Use that instead. return (__m128){ ((const float*)__p)[0], ((const float*)__p)[1], __a[2], __a[3] }; } static __inline__ __m128 __attribute__((__always_inline__)) _mm_loadh_pi(__m128 __a, const void /*__m64*/ *__p) { + // TODO: Due to alignment masking, this would probably be faster as a loadXY + // followed by a shuffle. return (__m128){ __a[0], __a[1], ((const float*)__p)[0], ((const float*)__p)[1] }; } static __inline__ __m128 __attribute__((__always_inline__)) _mm_loadr_ps(const float *__p) { - return (__m128){ ((const float*)__p)[3], ((const float*)__p)[2], ((const float*)__p)[1], ((const float*)__p)[0] }; + __m128 __v = _mm_load_ps(__p); + return __builtin_shufflevector(__v, __v, 3, 2, 1, 0); } static __inline__ __m128 __attribute__((__always_inline__)) @@ -81,20 +86,24 @@ _mm_loadu_ps(const float *__p) static __inline__ __m128 __attribute__((__always_inline__)) _mm_load_ps1(const float *__p) { - return (__m128){ *__p, *__p, *__p, *__p }; + float __s = *__p; + return (__m128){ __s, __s, __s, __s }; } #define _mm_load1_ps _mm_load_ps1 static __inline__ __m128 __attribute__((__always_inline__)) _mm_load_ss(const float *__p) { - // TODO: This actually corresponds to the SIMD.float32x4.loadX function in SIMD.js. Use that instead. + // TODO: This actually corresponds to the SIMD.float32x4.loadX function in + // SIMD.js. Use that instead. return (__m128){ *__p, 0.0f, 0.0f, 0.0f }; } static __inline__ void __attribute__((__always_inline__)) _mm_storel_pi(void /*__m64*/ *__p, __m128 __a) { + // TODO: This actually corresponds to the SIMD.float32x4.storeXY function in + // SIMD.js. Use that instead. ((float*)__p)[0] = __a[0]; ((float*)__p)[1] = __a[1]; } @@ -102,6 +111,8 @@ _mm_storel_pi(void /*__m64*/ *__p, __m128 __a) static __inline__ void __attribute__((__always_inline__)) _mm_storeh_pi(void /*__m64*/ *__p, __m128 __a) { + // TODO: Due to alignment masking, on x64 this would be faster as a sizzle + // and a storeXY, so we should use that instead. ((float*)__p)[0] = __a[2]; ((float*)__p)[1] = __a[3]; } @@ -371,44 +382,26 @@ _mm_cmpgt_ss(__m128 __a, __m128 __b) return _mm_move_ss(__a, _mm_cmpgt_ps(__a, __b)); } -static __inline__ int __internal_isnan(float __f) -{ - return (*(unsigned int*)&__f << 1) > 0xFF000000u; -} - static __inline__ __m128 __attribute__((__always_inline__)) _mm_cmpord_ps(__m128 __a, __m128 __b) { - unsigned int r[4]; - r[0] = (!__internal_isnan(__a[0]) && !__internal_isnan(__b[0])) ? 0xFFFFFFFFU : 0; - r[1] = (!__internal_isnan(__a[1]) && !__internal_isnan(__b[1])) ? 0xFFFFFFFFU : 0; - r[2] = (!__internal_isnan(__a[2]) && !__internal_isnan(__b[2])) ? 0xFFFFFFFFU : 0; - r[3] = (!__internal_isnan(__a[3]) && !__internal_isnan(__b[3])) ? 0xFFFFFFFFU : 0; - return _mm_loadu_ps((float*)r); + return emscripten_float32x4_and(emscripten_float32x4_equal(__a, __a), + emscripten_float32x4_equal(__b, __b)); } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpord_ss(__m128 __a, __m128 __b) { - unsigned int r = (!__internal_isnan(__a[0]) && !__internal_isnan(__b[0])) ? 0xFFFFFFFFU : 0; - return _mm_move_ss(__a, _mm_set_ss(*(float*)&r)); + return _mm_move_ss(__a, _mm_cmpord_ps(__a, __b)); } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpunord_ps(__m128 __a, __m128 __b) { - union { - unsigned int r[4]; - __m128 m; - } u; - u.r[0] = (__internal_isnan(__a[0]) || __internal_isnan(__b[0])) ? 0xFFFFFFFFU : 0; - u.r[1] = (__internal_isnan(__a[1]) || __internal_isnan(__b[1])) ? 0xFFFFFFFFU : 0; - u.r[2] = (__internal_isnan(__a[2]) || __internal_isnan(__b[2])) ? 0xFFFFFFFFU : 0; - u.r[3] = (__internal_isnan(__a[3]) || __internal_isnan(__b[3])) ? 0xFFFFFFFFU : 0; - return u.m; + return emscripten_float32x4_or(emscripten_float32x4_notEqual(__a, __a), + emscripten_float32x4_notEqual(__b, __b)); } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpunord_ss(__m128 __a, __m128 __b) { - unsigned int r = (__internal_isnan(__a[0]) || __internal_isnan(__b[0])) ? 0xFFFFFFFFU : 0; - return _mm_move_ss(__a, _mm_set_ss(*(float*)&r)); + return _mm_move_ss(__a, _mm_cmpunord_ps(__a, __b)); } static __inline__ __m128 __attribute__((__always_inline__)) @@ -435,11 +428,10 @@ _mm_xor_ps(__m128 __a, __m128 __b) return emscripten_float32x4_xor(__a, __b); } -// TODO: Use SIMD.float32x4.notEqual static __inline__ __m128 __attribute__((__always_inline__)) _mm_cmpneq_ps(__m128 __a, __m128 __b) { - return emscripten_float32x4_not(_mm_cmpeq_ps(__a, __b)); + return emscripten_float32x4_notEqual(__a, __b); } static __inline__ __m128 __attribute__((__always_inline__)) From aa10e490d08a84965d14c9f7248b0bc605afd7f0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 29 Dec 2014 11:21:51 -0800 Subject: [PATCH 60/75] fix getrlimit in SAFE_HEAP; fixes #3109 --- src/library.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 6a90ec4cfa28a..34b2a1e49e2a6 100644 --- a/src/library.js +++ b/src/library.js @@ -6385,8 +6385,8 @@ LibraryManager.library = { // TODO: Implement for real. getrlimit: function(resource, rlp) { // int getrlimit(int resource, struct rlimit *rlp); - {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}} // RLIM_INFINITY - {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}} // RLIM_INFINITY + {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}}; // RLIM_INFINITY + {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}}; // RLIM_INFINITY return 0; }, setrlimit: function(resource, rlp) { From 303e9f394d332cb7b515ccaafd5d414f18018eb7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 31 Dec 2014 14:11:39 -0800 Subject: [PATCH 61/75] write out full 64-bit values in rlimit --- src/library.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library.js b/src/library.js index 34b2a1e49e2a6..eaa440f9eddfe 100644 --- a/src/library.js +++ b/src/library.js @@ -6386,7 +6386,9 @@ LibraryManager.library = { getrlimit: function(resource, rlp) { // int getrlimit(int resource, struct rlimit *rlp); {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}}; // RLIM_INFINITY + {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur + 4, '-1', 'i32') }}}; // RLIM_INFINITY {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}}; // RLIM_INFINITY + {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max + 4, '-1', 'i32') }}}; // RLIM_INFINITY return 0; }, setrlimit: function(resource, rlp) { From 8b7a8caccab19f0f934011942de12db846cbf25f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 31 Dec 2014 11:44:16 -0800 Subject: [PATCH 62/75] ensure the static bump is properly aligned in emterpreter --- tools/emterpretify.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/emterpretify.py b/tools/emterpretify.py index 636bad48912aa..f010ba0ea6f9d 100755 --- a/tools/emterpretify.py +++ b/tools/emterpretify.py @@ -772,6 +772,8 @@ def post_process_code(code): asm.staticbump += 1 stack_start = len(mem_init) asm.staticbump += EMT_STACK_MAX + while asm.staticbump % 8 != 0: + asm.staticbump += 1 open(out_mem_file, 'wb').write(''.join(map(chr, mem_init))) From e4eb04c911e7bc39e70ad7e0851674d5bc2a22cd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 30 Dec 2014 17:03:48 -0800 Subject: [PATCH 63/75] perform LLVM LTO in a separate invocation of opt, so that it does not mix with legalization and other stuff we do at link time --- emcc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/emcc b/emcc index 898f822350137..ef155d403b59d 100755 --- a/emcc +++ b/emcc @@ -1235,6 +1235,11 @@ try: if not shared.Building.can_inline(): link_opts.append('-disable-inlining') # do not internalize in std-link-opts - it ignores internalize-public-api-list - and add a manual internalize link_opts += ['-disable-internalize'] + shared.Building.get_safe_internalize() + ['-std-link-opts'] + # execute it now, so it is done entirely before we get to the stage of legalization etc. + shared.Building.llvm_opt(final, pre_fastcomp_opts + link_opts) + if DEBUG: save_intermediate('lto', 'bc') + pre_fastcomp_opts = [] + link_opts = [] else: # At minimum remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it) link_opts += shared.Building.get_safe_internalize() + ['-globaldce'] From 550729d64399231b20144064bf9c0ee45675d67e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 1 Jan 2015 11:14:32 -0800 Subject: [PATCH 64/75] fix lto in non-fastcomp --- emcc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/emcc b/emcc index ef155d403b59d..450f0a63019b2 100755 --- a/emcc +++ b/emcc @@ -865,6 +865,8 @@ try: # Set ASM_JS default here so that we can override it from the command line. shared.Settings.ASM_JS = 1 if opt_level > 0 else 2 + pre_fastcomp_opts = [] + # Apply -s settings in newargs here (after optimization levels, so they can override them) for change in settings_changes: key, value = change.split('=') @@ -902,7 +904,6 @@ try: logging.warning('jcache is deprecated and not supported in fastcomp (you should not need it anyhow), disabling') jcache = False - pre_fastcomp_opts = [] fastcomp_opts = [] if shared.Settings.NO_EXIT_RUNTIME: pre_fastcomp_opts += ['-emscripten-no-exit-runtime'] From 16d378c78fd9a76f7cf1de856379912e001a1d62 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 1 Jan 2015 19:48:54 -0800 Subject: [PATCH 65/75] do not use an env var to communicate c++ mode --- em++ | 3 +-- emcc | 9 +++++---- tools/system_libs.py | 6 ------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/em++ b/em++ index ba09e1a2d472d..1a90915aeeeec 100755 --- a/em++ +++ b/em++ @@ -7,6 +7,5 @@ See emcc.py. This script forwards to there, noting that we want C++ and not C by import os, subprocess, sys from tools import shared -os.environ['EMMAKEN_CXX'] = '1' -exit(subprocess.call([shared.PYTHON, shared.EMCC] + sys.argv[1:])) +exit(subprocess.call([shared.PYTHON, shared.EMCC] + sys.argv[1:] + ['--emscripten-cxx'])) diff --git a/emcc b/emcc index 450f0a63019b2..6813cf8707660 100755 --- a/emcc +++ b/emcc @@ -104,6 +104,9 @@ if DEBUG and LEAVE_INPUTS_RAW: logging.warning('leaving inputs raw') stdout = PIPE if not DEBUG else None # suppress output of child processes stderr = PIPE if not DEBUG else None # unless we are in DEBUG mode +EMCC_CXX = '--emscripten-cxx' in sys.argv +sys.argv = filter(lambda x: x != '--emscripten-cxx', sys.argv) + shared.check_sanity(force=DEBUG) # Handle some global flags @@ -126,8 +129,6 @@ while response_file: break if len(sys.argv) == 1 or '--help' in sys.argv: - this = os.path.basename('em++' if os.environ.get('EMMAKEN_CXX') else 'emcc') - # Documentation for emcc and its options must be updated in: # site/source/docs/tools_reference/emcc.rst # A prebuilt local version of the documentation is available at: @@ -212,7 +213,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: if debug_configure: open(tempout, 'a').write('Forcing clang since uses fopen to write\n') compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if not use_js else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that - if not ('CXXCompiler' in ' '.join(sys.argv) or os.environ.get('EMMAKEN_CXX')): + if not ('CXXCompiler' in ' '.join(sys.argv) or EMCC_CXX): compiler = shared.to_cc(compiler) def filter_emscripten_options(argv): @@ -276,7 +277,7 @@ else: CC = shared.to_cc(CXX) # If we got here from a redirection through emmakenxx.py, then force a C++ compiler here -if os.environ.get('EMMAKEN_CXX'): +if EMCC_CXX: CC = CXX CC_ADDITIONAL_ARGS = shared.COMPILER_OPTS diff --git a/tools/system_libs.py b/tools/system_libs.py index c7bdcd598c95e..db0d7f8792360 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -56,8 +56,6 @@ def read_symbols(path, exclude=None): def build_libc(lib_filename, files, lib_opts): o_s = [] - prev_cxx = os.environ.get('EMMAKEN_CXX') - if prev_cxx: os.environ['EMMAKEN_CXX'] = '' musl_internal_includes = ['-I', shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal'), '-I', shared.path_from_root('system', 'lib', 'libc', 'musl', 'arch', 'js')] commands = [] # Hide several musl warnings that produce a lot of spam to unit test build server logs. @@ -68,7 +66,6 @@ def build_libc(lib_filename, files, lib_opts): commands.append([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o] + musl_internal_includes + default_opts + c_opts + lib_opts) o_s.append(o) run_commands(commands) - if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx shared.Building.link(o_s, in_temp(lib_filename)) return in_temp(lib_filename) @@ -647,11 +644,8 @@ def apply_libcxxabi(need): # gl def create_gl(): - prev_cxx = os.environ.get('EMMAKEN_CXX') - if prev_cxx: os.environ['EMMAKEN_CXX'] = '' o = in_temp('gl.o') check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o]) - if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx return o # Setting this in the environment will avoid checking dependencies and make building big projects a little faster From 3af15fd320665f3c32e17ff27dac50257fe89b79 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 1 Jan 2015 19:49:07 -0800 Subject: [PATCH 66/75] add testing for ports in c++ mode --- tests/test_sanity.py | 77 +++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 8636a13a11e77..cff398388171f 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -574,43 +574,46 @@ def test_emcc_ports(self): from tools import system_libs PORTS_DIR = system_libs.Ports.get_dir() - for i in [0, 1]: - print i - if i == 0: - try_delete(PORTS_DIR) - else: - self.do([PYTHON, EMCC, '--clear-ports']) - assert not os.path.exists(PORTS_DIR) - if i == 0: Cache.erase() # test with cache erased and without - - # Building a file that doesn't need ports should not trigger anything - output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp')]) - assert RETRIEVING_MESSAGE not in output - assert BUILDING_MESSAGE not in output - assert not os.path.exists(PORTS_DIR) - - # Building a file that need a port does trigger stuff - output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) - assert RETRIEVING_MESSAGE in output, output - assert BUILDING_MESSAGE in output, output - assert os.path.exists(PORTS_DIR) - - def second_use(): - # Using it again avoids retrieve and build - output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) - assert RETRIEVING_MESSAGE not in output, output - assert BUILDING_MESSAGE not in output, output - - second_use() - - # if the version isn't sufficient, we retrieve and rebuild - open(os.path.join(PORTS_DIR, 'sdl2', 'SDL2-master', 'version.txt'), 'w').write('1') # current is >= 2, so this is too old - output = self.do([EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) - assert RETRIEVING_MESSAGE in output, output - assert BUILDING_MESSAGE in output, output - assert os.path.exists(PORTS_DIR) - - second_use() + for compiler in [EMCC, EMXX]: + print compiler + + for i in [0, 1]: + print i + if i == 0: + try_delete(PORTS_DIR) + else: + self.do([PYTHON, compiler, '--clear-ports']) + assert not os.path.exists(PORTS_DIR) + if i == 0: Cache.erase() # test with cache erased and without + + # Building a file that doesn't need ports should not trigger anything + output = self.do([compiler, path_from_root('tests', 'hello_world_sdl.cpp')]) + assert RETRIEVING_MESSAGE not in output + assert BUILDING_MESSAGE not in output + assert not os.path.exists(PORTS_DIR) + + # Building a file that need a port does trigger stuff + output = self.do([compiler, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) + assert RETRIEVING_MESSAGE in output, output + assert BUILDING_MESSAGE in output, output + assert os.path.exists(PORTS_DIR) + + def second_use(): + # Using it again avoids retrieve and build + output = self.do([compiler, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) + assert RETRIEVING_MESSAGE not in output, output + assert BUILDING_MESSAGE not in output, output + + second_use() + + # if the version isn't sufficient, we retrieve and rebuild + open(os.path.join(PORTS_DIR, 'sdl2', 'SDL2-master', 'version.txt'), 'w').write('1') # current is >= 2, so this is too old + output = self.do([compiler, path_from_root('tests', 'hello_world_sdl.cpp'), '-s', 'USE_SDL=2']) + assert RETRIEVING_MESSAGE in output, output + assert BUILDING_MESSAGE in output, output + assert os.path.exists(PORTS_DIR) + + second_use() def test_native_optimizer(self): restore() From 5b89c3388c3988189e863c78e0fed61ccc10cb65 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Jan 2015 13:28:38 -0800 Subject: [PATCH 67/75] add onRuntimeInitialized method; #3106 --- site/source/docs/getting_started/FAQ.rst | 5 ++++ src/postamble.js | 6 ++-- tests/runtime_misuse.cpp | 2 +- tests/runtime_misuse_2.cpp | 22 ++++++++++++++ tests/test_browser.py | 37 ++++++++++++++++++------ 5 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 tests/runtime_misuse_2.cpp diff --git a/site/source/docs/getting_started/FAQ.rst b/site/source/docs/getting_started/FAQ.rst index b5da7f27c024a..7a70ccbb3ddb6 100644 --- a/site/source/docs/getting_started/FAQ.rst +++ b/site/source/docs/getting_started/FAQ.rst @@ -207,6 +207,11 @@ or What happens in practice is that when code is ready to be run, we check for ``Module._main``. If present, we call it. If a ``main()`` function was compiled from C, it will be there (and it will be a JavaScript function). But, you can also just define a JavaScript function there, either will work. +Another option is to define an ``onRuntimeInitialized`` function, + + Module['onRuntimeInitialized'] = function() { ... }; + +That method will be called when the runtime is ready and it is ok for you to call compiled code. In practice, that is exactly the same time at which ``main()`` would be called, so ``onRuntimeInitialized`` doesn't let you do anything new, but it can be convenient in some cases - for example, if you use ``onRuntimeInitialized`` and don't define a ``main()`` function, then the runtime will not be shut down after ``main()`` exits, and you can keep calling compiled methods (you can also have a ``main()`` and build with ``-s NO_EXIT_RUNTIME=1`` to keep the runtime from being shut down). Thus, for libraries, ``onRuntimeInitialized`` can be convenient. .. _faq-dead-code-elimination: diff --git a/src/postamble.js b/src/postamble.js index bac17ab259d9a..59c4caa46650b 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -142,9 +142,9 @@ function run(args) { Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms'); } - if (Module['_main'] && shouldRunNow) { - Module['callMain'](args); - } + if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); + + if (Module['_main'] && shouldRunNow) Module['callMain'](args); postRun(); } diff --git a/tests/runtime_misuse.cpp b/tests/runtime_misuse.cpp index d74d05ea4db9e..7a264d600dbe6 100644 --- a/tests/runtime_misuse.cpp +++ b/tests/runtime_misuse.cpp @@ -9,7 +9,7 @@ char* EMSCRIPTEN_KEEPALIVE note(int n) { EM_ASM_({ Module.print([$0, $1]) }, n, noted); noted += n; EM_ASM_({ Module.print(['noted is now', $0]) }, noted); - return "silly-string"; + return (char*)"silly-string"; } void free(void*) { // free is valid to call even after the runtime closes, so useful as a hack here for this test diff --git a/tests/runtime_misuse_2.cpp b/tests/runtime_misuse_2.cpp new file mode 100644 index 0000000000000..4da63d6651db2 --- /dev/null +++ b/tests/runtime_misuse_2.cpp @@ -0,0 +1,22 @@ +#include +#include + +extern "C" { + +int noted = 0; + +char* EMSCRIPTEN_KEEPALIVE note(int n) { + EM_ASM_({ Module.print([$0, $1]) }, n, noted); + noted += n; + EM_ASM_({ Module.print(['noted is now', $0]) }, noted); + return (char*)"silly-string"; +} + +void free(void*) { // free is valid to call even after the runtime closes, so useful as a hack here for this test + EM_ASM_({ Module.print(['reporting', $0]) }, noted); + int result = noted; + REPORT_RESULT(); +} + +} + diff --git a/tests/test_browser.py b/tests/test_browser.py index ddd4849ac6dbb..73e4998adfe77 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1850,15 +1850,34 @@ def test_runtime_misuse(self): setTimeout(Module['_free'], 1000); // free is valid to call even after the runtime closes ''' - print 'mem init, so async, call too early' - open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + post_test + post_hook) - self.btest('runtime_misuse.cpp', expected='600', args=['--post-js', 'post.js', '--memory-init-file', '1']) - print 'sync startup, call too late' - open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + 'Module.postRun.push(function() { ' + post_test + ' });' + post_hook); - self.btest('runtime_misuse.cpp', expected='600', args=['--post-js', 'post.js', '--memory-init-file', '0']) - print 'sync, runtime still alive, so all good' - open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + 'expected_ok = true; Module.postRun.push(function() { ' + post_test + ' });' + post_hook); - self.btest('runtime_misuse.cpp', expected='606', args=['--post-js', 'post.js', '--memory-init-file', '0', '-s', 'NO_EXIT_RUNTIME=1']) + open('pre_main.js', 'w').write(r''' + Module._main = function(){ + myJSCallback(); + return 0; + }; + ''') + + open('pre_runtime.js', 'w').write(r''' + Module.onRuntimeInitialized = function(){ + myJSCallback(); + }; + ''') + + for filename, extra_args, second_code in [ + ('runtime_misuse.cpp', [], 600), + ('runtime_misuse_2.cpp', ['--pre-js', 'pre_main.js'], 600), + ('runtime_misuse_2.cpp', ['--pre-js', 'pre_runtime.js'], 601) # 601, because no main means we *do* run another call after exit() + ]: + print '\n', filename, extra_args + print 'mem init, so async, call too early' + open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + post_test + post_hook) + self.btest(filename, expected='600', args=['--post-js', 'post.js', '--memory-init-file', '1'] + extra_args) + print 'sync startup, call too late' + open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + 'Module.postRun.push(function() { ' + post_test + ' });' + post_hook); + self.btest(filename, expected=str(second_code), args=['--post-js', 'post.js', '--memory-init-file', '0'] + extra_args) + print 'sync, runtime still alive, so all good' + open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + 'expected_ok = true; Module.postRun.push(function() { ' + post_test + ' });' + post_hook); + self.btest(filename, expected='606', args=['--post-js', 'post.js', '--memory-init-file', '0', '-s', 'NO_EXIT_RUNTIME=1'] + extra_args) def test_worker_api(self): Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate() From 6baa633a577ca2d0f49eea1be13e8469bebc0684 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Jan 2015 14:08:57 -0800 Subject: [PATCH 68/75] use floats in newer csmith --- tests/fuzz/csmith_driver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/fuzz/csmith_driver.py b/tests/fuzz/csmith_driver.py index d004c2c723d1e..0332cde8b18d3 100755 --- a/tests/fuzz/csmith_driver.py +++ b/tests/fuzz/csmith_driver.py @@ -48,6 +48,7 @@ print '1) Generate source' extra_args = [] if random.random() < 0.5: extra_args += ['--no-math64'] + if random.random() < 0.5: extra_args += ['--float'] suffix = '.c' COMP = shared.CLANG_CC if random.random() < 0.5: @@ -95,7 +96,7 @@ def try_js(args): shared.try_delete(filename + '.js') print '(compile)' - shared.check_execute([shared.PYTHON, shared.EMCC, opts, fullname, '-o', filename + '.js'] + CSMITH_CFLAGS + args) + shared.check_execute([shared.PYTHON, shared.EMCC, opts, fullname, '-o', filename + '.js', '-s', 'PRECISE_F32=1'] + CSMITH_CFLAGS + args) assert os.path.exists(filename + '.js') print '(run)' js = shared.run_js(filename + '.js', engine=engine1, check_timeout=True, assert_returncode=None, cwd='/tmp/emscripten_temp') From 79f57ee274ba5e11f86f1dc8de9a3ea8f71daa56 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Jan 2015 15:33:27 -0800 Subject: [PATCH 69/75] update csmith helper scripts --- tests/fuzz/test.sh | 4 ++-- tests/fuzz/testpp.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/fuzz/test.sh b/tests/fuzz/test.sh index 90d6b1a47ab15..e8680d5860e17 100755 --- a/tests/fuzz/test.sh +++ b/tests/fuzz/test.sh @@ -10,8 +10,8 @@ gcc $@ -m32 -I/home/alon/Dev/csmith/runtime -o n1.out &> /dev/null #EMCC_FAST_COMPILER=0 ~/Dev/emscripten/emcc $@ -I/home/alon/Dev/csmith/runtime -o js.out.js &> /dev/null #EMCC_FAST_COMPILER=0~/Dev/emscripten/emcc $@ -s UNALIGNED_MEMORY=1 -I/home/alon/Dev/csmith/runtime -o ua.out.js &> /dev/null #EMCC_FAST_COMPILER=0~/Dev/emscripten/emcc $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -o sh.out.js &> /dev/null -~/Dev/emscripten/emcc $@ -I/home/alon/Dev/csmith/runtime -o fc.out.js &> /dev/null -~/Dev/emscripten/emcc $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -o fc-sh.out.js &> /dev/null +~/Dev/emscripten/emcc $@ -I/home/alon/Dev/csmith/runtime -s PRECISE_F32=1 -o fc.out.js &> /dev/null +~/Dev/emscripten/emcc $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -s PRECISE_F32=1 -o fc-sh.out.js &> /dev/null echo "run n1" ./n1.out &> n1 echo "run n2" diff --git a/tests/fuzz/testpp.sh b/tests/fuzz/testpp.sh index 49378645002c8..55e3bcf7d6e85 100755 --- a/tests/fuzz/testpp.sh +++ b/tests/fuzz/testpp.sh @@ -10,8 +10,8 @@ g++ $@ -m32 -I/home/alon/Dev/csmith/runtime -o n1.out &> /dev/null #EMCC_FAST_COMPILER=0 ~/Dev/emscripten/em++ $@ -I/home/alon/Dev/csmith/runtime -o js.out.js &> /dev/null #EMCC_FAST_COMPILER=0~/Dev/emscripten/em++ $@ -s UNALIGNED_MEMORY=1 -I/home/alon/Dev/csmith/runtime -o ua.out.js &> /dev/null #EMCC_FAST_COMPILER=0~/Dev/emscripten/em++ $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -o sh.out.js &> /dev/null -~/Dev/emscripten/em++ $@ -I/home/alon/Dev/csmith/runtime -o fc.out.js &> /dev/null -~/Dev/emscripten/em++ $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -o fc-sh.out.js &> /dev/null +~/Dev/emscripten/em++ $@ -I/home/alon/Dev/csmith/runtime -s PRECISE_F32=1 -o fc.out.js &> /dev/null +~/Dev/emscripten/em++ $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -s PRECISE_F32=1 -o fc-sh.out.js &> /dev/null echo "run n1" ./n1.out &> n1 echo "run n2" From f7f72a045a4f64ee27aa2078917e71b4e7588548 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Jan 2015 15:34:09 -0800 Subject: [PATCH 70/75] print js engine used in fuzzer --- tests/fuzz/csmith_driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fuzz/csmith_driver.py b/tests/fuzz/csmith_driver.py index 0332cde8b18d3..244a64155d559 100755 --- a/tests/fuzz/csmith_driver.py +++ b/tests/fuzz/csmith_driver.py @@ -98,7 +98,7 @@ def try_js(args): print '(compile)' shared.check_execute([shared.PYTHON, shared.EMCC, opts, fullname, '-o', filename + '.js', '-s', 'PRECISE_F32=1'] + CSMITH_CFLAGS + args) assert os.path.exists(filename + '.js') - print '(run)' + print '(run in %s)' % engine1 js = shared.run_js(filename + '.js', engine=engine1, check_timeout=True, assert_returncode=None, cwd='/tmp/emscripten_temp') js = js.split('\n')[0] + '\n' # remove any extra printed stuff (node workarounds) assert correct1 == js or correct2 == js, ''.join([a.rstrip()+'\n' for a in difflib.unified_diff(correct1.split('\n'), js.split('\n'), fromfile='expected', tofile='actual')]) From acb16a9c55d69f713f534de70ccc467edcc3c975 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Jan 2015 16:21:02 -0800 Subject: [PATCH 71/75] disable csmith floats because they can lead to undefined behavior --- tests/fuzz/csmith_driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fuzz/csmith_driver.py b/tests/fuzz/csmith_driver.py index 244a64155d559..f606d36c872e9 100755 --- a/tests/fuzz/csmith_driver.py +++ b/tests/fuzz/csmith_driver.py @@ -48,7 +48,7 @@ print '1) Generate source' extra_args = [] if random.random() < 0.5: extra_args += ['--no-math64'] - if random.random() < 0.5: extra_args += ['--float'] + #if random.random() < 0.5: extra_args += ['--float'] # XXX hits undefined behavior on float=>int conversions (too big to fit) suffix = '.c' COMP = shared.CLANG_CC if random.random() < 0.5: From 251b96a43d5bad7a4d3232ad185cd813d3e72c3f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 Jan 2015 20:31:44 -0800 Subject: [PATCH 72/75] update cashew --- tools/optimizer/istring.h | 4 ++-- tools/optimizer/parser.h | 23 ++++++++++++++++------- tools/optimizer/simple_ast.h | 5 ++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/tools/optimizer/istring.h b/tools/optimizer/istring.h index e795297385c08..c78d1f68ac7ac 100644 --- a/tools/optimizer/istring.h +++ b/tools/optimizer/istring.h @@ -78,11 +78,11 @@ struct IString { return strcmp(str ? str : "", other.str ? other.str : "") < 0; } - char operator[](int x) { + char operator[](int x) const { return str[x]; } - bool operator!() { // no string, or empty string + bool operator!() const { // no string, or empty string return !str || str[0] == 0; } diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index ff615218150e9..6d6a0c4306d23 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -5,6 +5,7 @@ #include #include +#include #include @@ -162,8 +163,9 @@ class Parser { OPERATOR = 1, IDENT = 2, STRING = 3, // without quotes - NUMBER = 4, - SEPARATOR = 5 + INT = 4, + DOUBLE = 5, + SEPARATOR = 6 }; struct Frag { @@ -178,6 +180,10 @@ class Parser { int size; FragType type; + bool isNumber() const { + return type == INT || type == DOUBLE; + } + explicit Frag(char* src) { assert(!isSpace(*src)); char *start = src; @@ -216,11 +222,12 @@ class Parser { else break; src++; } + type = INT; } else { num = strtod(start, &src); + type = std::find(start, src, '.') == src ? INT : DOUBLE; } assert(src > start); - type = NUMBER; } else if (hasChar(OPERATOR_INITS, *src)) { switch (*src) { case '!': str = src[1] == '=' ? NE : L_NOT; break; @@ -278,7 +285,8 @@ class Parser { } case IDENT: case STRING: - case NUMBER: { + case INT: + case DOUBLE: { src = skipSpace(src); if (frag.type == IDENT) return parseAfterIdent(frag, src, seps); else return parseExpression(parseFrag(frag), src, seps); @@ -301,7 +309,8 @@ class Parser { switch (frag.type) { case IDENT: return Builder::makeName(frag.str); case STRING: return Builder::makeString(frag.str); - case NUMBER: return Builder::makeNumber(frag.num); + case INT: return Builder::makeInt(uint32_t(frag.num)); + case DOUBLE: return Builder::makeDouble(frag.num); default: assert(0); } return nullptr; @@ -457,7 +466,7 @@ class Parser { src = skipSpace(src); NodeRef arg; Frag value(src); - if (value.type == NUMBER) { + if (value.isNumber()) { arg = parseFrag(value); src += value.size; } else { @@ -466,7 +475,7 @@ class Parser { src += value.size; src = skipSpace(src); Frag value2(src); - assert(value2.type == NUMBER); + assert(value2.isNumber()); arg = Builder::makePrefix(MINUS, parseFrag(value2)); src += value2.size; } diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h index 6662aa0504b4b..452b5680e9fbd 100644 --- a/tools/optimizer/simple_ast.h +++ b/tools/optimizer/simple_ast.h @@ -1295,10 +1295,13 @@ class ValueBuilder { } } - static Ref makeNumber(double num) { + static Ref makeDouble(double num) { return &makeRawArray()->push_back(makeRawString(NUM)) .push_back(&arena.alloc()->setNumber(num)); } + static Ref makeInt(uint32_t num) { + return makeDouble(double(num)); + } static Ref makeBinary(Ref left, IString op, Ref right) { if (op == SET) { From 8f5f45fb3fff94ad551d0128446c4e82c499173b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 3 Jan 2015 13:59:28 -0800 Subject: [PATCH 73/75] move csmith headers to side dir, for fuzz tests in core --- tests/fuzz/{ => include}/csmith.h | 0 tests/fuzz/{ => include}/platform_generic.h | 0 tests/fuzz/{ => include}/random_inc.h | 0 tests/fuzz/{ => include}/safe_math.h | 0 tests/test_core.py | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename tests/fuzz/{ => include}/csmith.h (100%) rename tests/fuzz/{ => include}/platform_generic.h (100%) rename tests/fuzz/{ => include}/random_inc.h (100%) rename tests/fuzz/{ => include}/safe_math.h (100%) diff --git a/tests/fuzz/csmith.h b/tests/fuzz/include/csmith.h similarity index 100% rename from tests/fuzz/csmith.h rename to tests/fuzz/include/csmith.h diff --git a/tests/fuzz/platform_generic.h b/tests/fuzz/include/platform_generic.h similarity index 100% rename from tests/fuzz/platform_generic.h rename to tests/fuzz/include/platform_generic.h diff --git a/tests/fuzz/random_inc.h b/tests/fuzz/include/random_inc.h similarity index 100% rename from tests/fuzz/random_inc.h rename to tests/fuzz/include/random_inc.h diff --git a/tests/fuzz/safe_math.h b/tests/fuzz/include/safe_math.h similarity index 100% rename from tests/fuzz/safe_math.h rename to tests/fuzz/include/safe_math.h diff --git a/tests/test_core.py b/tests/test_core.py index b98b774abda91..e53e0d61b093c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5812,7 +5812,7 @@ def test_cases(self): def test_fuzz(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2') - Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('tests', 'fuzz'), '-Wno-warn-absolute-paths'] + Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('tests', 'fuzz', 'include'), '-Wno-warn-absolute-paths'] def run_all(x): print x From c7bcc95b793bb066a51869f149149965ad384b86 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 3 Jan 2015 14:26:04 -0800 Subject: [PATCH 74/75] update cashew --- tools/optimizer/parser.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index 6d6a0c4306d23..9edbe92256c59 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -5,7 +5,6 @@ #include #include -#include #include @@ -157,6 +156,10 @@ class Parser { static bool hasChar(const char* list, char x) { while (*list) if (*list++ == x) return true; return false; } + static bool is32Bit(double x) { + return x == (int)x || x == (unsigned int)x; + } + // An atomic fragment of something. Stops at a natural boundary. enum FragType { KEYWORD = 0, @@ -222,11 +225,10 @@ class Parser { else break; src++; } - type = INT; } else { num = strtod(start, &src); - type = std::find(start, src, '.') == src ? INT : DOUBLE; } + type = is32Bit(num) ? INT : DOUBLE; assert(src > start); } else if (hasChar(OPERATOR_INITS, *src)) { switch (*src) { From 9ab0ccaa00d8c58ae316c29b03c03813e7d4f398 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 4 Jan 2015 10:52:26 -0800 Subject: [PATCH 75/75] 1.28.3 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index b7825b8d76746..a5096ba657ec9 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.28.2 +1.28.3