diff --git a/AUTHORS b/AUTHORS index 123ce0cc70ad6..69f84c6ca8588 100644 --- a/AUTHORS +++ b/AUTHORS @@ -170,4 +170,5 @@ a license to everyone to use it as detailed in LICENSE.) * Warren Seine (copyright owned by Aerys SAS) * Petr Babicka * Akira Takahashi +* Victor Costan diff --git a/ChangeLog.markdown b/ChangeLog.markdown index 70cb01551e204..968a0adf811f5 100644 --- a/ChangeLog.markdown +++ b/ChangeLog.markdown @@ -10,9 +10,98 @@ Not all changes are documented here. In particular, new features, user-oriented Current trunk code ------------------ - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see - - Emscripten: https://github.com/kripken/emscripten/compare/1.25.0...incoming - - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.25.0...incoming - - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.25.0...incoming + - Emscripten: https://github.com/kripken/emscripten/compare/1.27.1...incoming + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.27.1...incoming + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.27.1...incoming + +v1.27.1: 11/20/2014 +------------------- + - Migrated to upstream PNaCl LLVM+Clang 3.4 from the previous 3.3. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.27.0...1.27.1 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.27.0...1.27.1 + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.27.0...1.27.1 + +v1.27.0: 11/20/2014 +------------------- + - Added new work in progress option -s NATIVE_OPTIMIZER=1 that migrates optimizer code from JS to C++ for better performance. + - Fixed an embind issue when compiling with closure (#2974) + - Fixed an embind issue with unique_ptr (#2979) + - Fixed a bug with new GL context initialization in proxy to worker mode. + - Fixed an issue where GL context event handlers would leak after a GL context has been freed. + - Optimized embind operation in Chrome by avoiding using Function.prototype.bind(). + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.26.1...1.27.0 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.26.1...1.27.0 + - Emscripten-Clang: no changes. + +v1.26.1: 11/7/2014 +------------------ + - Fixed emscripten::val handle for special js values (#2930) + - Implemented SDL 1.2 SDL_SetClipRect / SDL_GetClipRect (#2931) + - Added support for building zlib from Emscripten Ports with linker flag -s USE_ZLIB=1. + - Improved experimental GLES3 support. + - Fixed issues with llseek (#2945) + - Enable using emscripten_get_now() in web workers (#2953) + - Added stricter input data validation in GL code. + - Added new HTML5 C API for managing fullscreen mode transitions to resolve cross-browser issue #2556 (#2975) + - Fixed an issue with using structs in va_args (#2923) + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.26.0...1.26.1 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.26.0...1.26.1 + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.26.0...1.26.1 + +v1.26.0: 10/29/2014 +------------------- + - Fixed an issue where emar would forward --em-config to llvm-ar (#2886) + - Added a new "emterpreter" feature that allows running Emscripten compiled code in interpreted form until asm.js compilation is ready (-s EMTERPRETIFY=1). + - For more information, see https://groups.google.com/d/msg/emscripten-discuss/vhaPL9kULxk/_eD2G06eucwJ + - Added new "Emscripten Ports" architecture that enables building SDL2 with -s USE_SDL=2 command line flag. + - Added support for SDL 1.2 SDL_CreateRGBSurfaceFrom() function. + - Improved experimental SIMD support. + - Use only minimum necessary digits to print floating point literals in generated JS code for smaller code output. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.25.2...1.26.0 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.25.2...1.26.0 + - Emscripten-Clang: no changes. + +v1.25.2: 10/16/2014 +------------------- + - Fixed a bug in tmpfile() function not allocating the mode argument correctly. + - Fixed a bug with handling empty files in IDBFS (#2845) + - Added an implementation of the utimes() function (#2845) + - Added experimental WebGL 2.0 support with the linker flag -s USE_WEBGL2=1. (#2873) + - Fixed a UnboundTypeError occurring in embind (#2875) + - Fixed an error "IndexSizeError: Index or size is negative or greater than the allowed amount" being thrown by Emscripten SDL 1.2 surface blit code. (#2879) + - Fixed a JS minifier issue that generated "x--y from x - -y" (#2869) + - Added a new emcc command line flag "--cache " to control the location of the Emscripten cache directory (#2816) + - Implemented SDL_ConvertSurface() and added support for SDL_SRCALPHA in SDL_SetAlpha (#2871) + - Fixed issues with the GL library handling of invalid input values. + - Optimized SDL copyIndexedColorData function (#2890) + - Implemented GLES3 emulation for glMapBufferRange() for upcoming WebGL 2 support, using the -s FULL_ES3=1 linker option. + - Fixed a bug where setting up and cancelling the main loop multiple times would stack up the main loop to be called too frequently (#2839) + - Introduced a new API emscripten_set_main_loop_timing() for managing the Emscripten main loop calling frequency (#2839) + - Added new optimization flags SDL.discardOnLock and SDL.opaqueFrontBuffer to Emscripten SDL 1.2 SDL_LockSurface() and SDL_UnlockSurface() (#2870) + - Fixed a bug with glfwGetProcAddress(). + - Added option to customize GLOBAL_BASE (the starting address of global variables in the Emscripten HEAP). + - Added the ability to register mouseover and mouseout events from the HTML5 API. + - Improved experimental SIMD support. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.25.1...1.25.2 + - Emscripten-LLVM: no changes. + - Emscripten-Clang: no changes. + +v1.25.1: 10/1/2014 +------------------ + - Updated heap resize support code when -s ALLOW_MEMORY_GROWTH=1 is defined. + - Updated libc++ to new version from upstream svn revision 218372, 2014-09-24. + - Fixed a bug where building on Windows might generate output JS files with incorrect syntax (emscripten-fastcomp #52) + - Improved experimental SIMD support. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.25.0...1.25.1 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.25.0...1.25.1 + - Emscripten-Clang: no changes. + v1.25.0: 9/30/2014 ------------------ diff --git a/emcc b/emcc index 4fb098e2364c4..a78fa890131c2 100755 --- a/emcc +++ b/emcc @@ -475,7 +475,7 @@ try: opt_level = validate_arg_level(requested_level, 3, 'Invalid optimization level: ' + newargs[i]) # We leave the -O option in place so that the clang front-end runs in that # optimization mode, but we disable the actual optimization passes, as we'll - # run them seperately. + # run them separately. newargs.append('-mllvm') newargs.append('-disable-llvm-optzns') elif newargs[i].startswith('--js-opts'): @@ -1393,7 +1393,7 @@ try: passes = ['asmPreciseF32'] + passes if emit_symbol_map and 'minifyNames' in passes: passes += ['symbolMap='+target+'.symbols'] - if minify_whitespace: + if minify_whitespace and 'last' in passes: passes += ['minifyWhitespace'] logging.debug('applying js optimization passes: %s', passes) final = shared.Building.js_optimizer(final, passes, jcache, debug_level >= 4, js_optimizer_extra_info, just_split=just_split, just_concat=just_concat) @@ -1407,35 +1407,27 @@ try: # must give it JSON and receive from it JSON chunks = [] curr = [] - native = False for p in passes: - if not shared.js_optimizer.use_native(p, source_map=debug_level >= 4): - if native: - chunks.append(['receiveJSON'] + curr + ['emitJSON']) - curr = [] - native = False - curr.append('receiveJSON') + if len(curr) == 0: curr.append(p) - else: # p is native - if not native: + else: + native = shared.js_optimizer.use_native(p, source_map=debug_level >= 4) + last_native = shared.js_optimizer.use_native(curr[-1], source_map=debug_level >= 4) + if native == last_native: + curr.append(p) + else: curr.append('emitJSON') chunks.append(curr) - curr = [] - native = True - curr.append(p) + curr = ['receiveJSON', p] if len(curr) > 0: - if native: - curr = ['receiveJSON'] + curr + ['emitJSON'] chunks.append(curr) - if native: - chunks.append(['receiveJSON']) if len(chunks) == 1: run_passes(chunks[0], title, just_split=False, just_concat=False) else: for i in range(len(chunks)): run_passes(chunks[i], 'js_opts_' + str(i), just_split='receiveJSON' in chunks[i], just_concat='emitJSON' in chunks[i]) else: - # DEBUG 2, run each pass seperately + # DEBUG 2, run each pass separately for p in passes: js_optimizer_queue = [p] flush_js_optimizer_queue(p) diff --git a/emscripten-version.txt b/emscripten-version.txt index b1832cf8e43f9..362c239d66da5 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.27.1 +1.27.2 diff --git a/emscripten.py b/emscripten.py index e5eb9cda036cd..12a1318bf1b89 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1096,18 +1096,20 @@ def make_emulated_param(i): simdfloattypes = ['float32x4'] simdinttypes = ['int32x4'] simdtypes = simdfloattypes + simdinttypes - # TODO: Make mul, min, max, notEqual, lessThanOrEqual, and greaterThanOrEqual - # available for int32x4 too. - simdfuncs = ['add', 'sub', + # TODO: mul + simdfuncs = ['add', 'sub', 'neg', 'equal', 'lessThan', 'greaterThan', + 'notEqual', 'lessThanOrEqual', 'greaterThanOrEqual', 'select', 'and', 'or', 'xor', 'not', 'splat', 'swizzle', 'shuffle', 'withX', 'withY', 'withZ', 'withW', 'load', 'store'] - simdfloatfuncs = simdfuncs + ['mul', 'div', 'min', 'max', 'sqrt', 'neg', - 'fromInt32x4', 'fromInt32x4Bits', - 'notEqual', 'lessThanOrEqual', 'greaterThanOrEqual']; - simdintfuncs = simdfuncs + ['fromFloat32x4', 'fromFloat32x4Bits']; + # TODO: fromInt32x4 + simdfloatfuncs = simdfuncs + ['mul', 'div', 'min', 'max', 'minNum', 'maxNum', 'sqrt', + 'abs', 'fromInt32x4Bits']; + # TODO: fromFloat32x4 + # TODO: shiftLeftByScalar, shiftRightArithmeticByScalar, shiftLeftArithmeticByScalar + simdintfuncs = simdfuncs + ['fromFloat32x4Bits']; fundamentals = ['Math', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] if metadata['simd']: fundamentals += ['SIMD'] diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index 79bb6cc487db8..fede72b330fc3 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -43,7 +43,7 @@ Calling compiled C functions from JavaScript :: - -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]' + -s EXPORTED_FUNCTIONS="['_main', '_myfunc']" Exported functions can be called as normal: :: @@ -87,7 +87,7 @@ Calling compiled C functions from JavaScript :: - -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]' + -s EXPORTED_FUNCTIONS="['_main', '_myfunc']" Exported functions can be called as normal: :: diff --git a/site/source/docs/optimizing/Optimizing-Code.rst b/site/source/docs/optimizing/Optimizing-Code.rst index 35e1f8ab24c1b..ddaf836ac17e9 100644 --- a/site/source/docs/optimizing/Optimizing-Code.rst +++ b/site/source/docs/optimizing/Optimizing-Code.rst @@ -66,7 +66,7 @@ By default Emscripten emits the static memory initialization code inside the **. The ``--memory-init-file 1`` :ref:`emcc option ` causes the compiler to emit this code in a separate binary file with suffix **.mem**. The **.mem** file is loaded (asynchronously) by the main **.js** file before ``main()`` is called and compiled code is able to run. -.. note: From Emscripten 1.21.1 this setting is enabled by default for ``-O2`` builds (and above). + .. note:: From Emscripten 1.21.1 this setting is enabled by default for fully optimized builds, that is, ``-O2`` and above. .. _optimizing-code-oz-os: @@ -125,13 +125,13 @@ C++ exceptions are turned off by default in ``-O1`` (and above). This prevents t To re-enable exceptions in optimized code, run *emcc* with ``-s DISABLE_EXCEPTION_CATCHING=0`` (see `src/settings.js `_). -.. _optimizing-code-inlining: - Memory Growth ------------- Building with ``-s ALLOW_MEMORY_GROWTH=1`` allows the total amount of memory used to change depending on the demands of the application. This is useful for apps that don't know ahead of time how much they will need, but it disables some optimizations. (Work is ongoing to improve this.) +.. _optimizing-code-inlining: + Inlining -------- diff --git a/site/source/index.rst b/site/source/index.rst index f8981258d99b1..227db17984733 100644 --- a/site/source/index.rst +++ b/site/source/index.rst @@ -17,7 +17,8 @@ News ==== -- **Humble Bundle** launches the `Humble Mozilla Bundle `_, a bunch of games ported to the web using Emscripten, including Super Hexagon, Aaaaaa for the awesome!, Zenbound 2, and FTL. Some technical background on one of the ports, using Unity, can be seen `here `_. +- Emscripten incoming branch `updated to LLVM 3.4 `_ +- **Humble Bundle** launches the `Humble Mozilla Bundle `_ (`more details `_), a bunch of games ported to the web using Emscripten, including Super Hexagon, Aaaaaa for the awesome!, Zenbound 2, and FTL. Some technical background on one of the ports, using Unity, can be seen `here `_. - **Unity** launches a `benchmark `_ for their WebGL port. This is an excellent way to measure overall performance of a CPU and GPU intensive codebase ported by Emscripten. Try the benchmark `here `_ diff --git a/src/library.js b/src/library.js index 8b37ea26a10b4..432b4880f002b 100644 --- a/src/library.js +++ b/src/library.js @@ -2439,7 +2439,14 @@ LibraryManager.library = { fflush: function(stream) { // int fflush(FILE *stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html - // we don't currently perform any user-space buffering of data + + /* + // Disabled, see https://github.com/kripken/emscripten/issues/2770 + stream = FS.getStreamFromPtr(stream); + if (stream.stream_ops.flush) { + stream.stream_ops.flush(stream); + } + */ }, fgetc__deps: ['$FS', 'fread'], fgetc__postset: '_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);', @@ -5329,7 +5336,7 @@ LibraryManager.library = { '%R': '%H:%M', // Replaced by the time in 24-hour notation '%T': '%H:%M:%S', // Replaced by the time '%x': '%m/%d/%y', // Replaced by the locale's appropriate date representation - '%X': '%H:%M:%S', // Replaced by the locale's appropriate date representation + '%X': '%H:%M:%S' // Replaced by the locale's appropriate date representation }; for (var rule in EXPANSION_RULES_1) { pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_1[rule]); @@ -8565,8 +8572,10 @@ LibraryManager.library = { } } else if (typeof dateNow !== 'undefined') { _emscripten_get_now.actual = dateNow; - } else if ((ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && self['performance'] && self['performance']['now']) { + } else if (typeof self === 'object' && self['performance'] && typeof self['performance']['now'] === 'function') { _emscripten_get_now.actual = function _emscripten_get_now_actual() { return self['performance']['now'](); }; + } else if (typeof performance === 'object' && typeof performance['now'] === 'function') { + _emscripten_get_now.actual = function _emscripten_get_now_actual() { return performance['now'](); }; } else { _emscripten_get_now.actual = Date.now; } diff --git a/src/library_fs.js b/src/library_fs.js index 76f82bf9eab72..68eb42592e3f1 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -214,11 +214,11 @@ mergeInto(LibraryManager.library, { set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; } }, isFolder: { - get: function() { return FS.isDir(this.mode); }, + get: function() { return FS.isDir(this.mode); } }, isDevice: { - get: function() { return FS.isChrdev(this.mode); }, - }, + get: function() { return FS.isChrdev(this.mode); } + } }); } diff --git a/src/library_gl.js b/src/library_gl.js index 662018d25745d..99e7c85cd33c7 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -324,6 +324,9 @@ var LibraryGL = { #endif } return; // Do not write anything to the out pointer, since no binary formats are supported. +#if USE_WEBGL2 + case 0x87FE: // GL_NUM_PROGRAM_BINARY_FORMATS +#endif case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS ret = 0; break; @@ -425,60 +428,44 @@ var LibraryGL = { getTexPixelData: function(type, format, width, height, pixels, internalFormat) { var sizePerPixel; - switch (type) { - case 0x1401 /* GL_UNSIGNED_BYTE */: - switch (format) { - case 0x1906 /* GL_ALPHA */: - case 0x1909 /* GL_LUMINANCE */: - sizePerPixel = 1; - break; - case 0x1907 /* GL_RGB */: - sizePerPixel = 3; - break; - case 0x1908 /* GL_RGBA */: - sizePerPixel = 4; - break; - case 0x190A /* GL_LUMINANCE_ALPHA */: - sizePerPixel = 2; - break; - default: - GL.recordError(0x0500); // GL_INVALID_ENUM + var numChannels; + switch(format) { + case 0x1906 /* GL_ALPHA */: + case 0x1909 /* GL_LUMINANCE */: + case 0x1902 /* GL_DEPTH_COMPONENT */: + numChannels = 1; + break; + case 0x190A /* GL_LUMINANCE_ALPHA */: + case 0x8227 /* GL_RG */: + numChannels = 2; + break; + case 0x1907 /* GL_RGB */: + numChannels = 3; + break; + case 0x1908 /* GL_RGBA */: + numChannels = 4; + break; + default: + GL.recordError(0x0500); // GL_INVALID_ENUM #if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format); + Module.printErr('GL_INVALID_ENUM due to unknown format in getTexPixelData, type: ' + type + ', format: ' + format); #endif - return { - pixels: null, - internalFormat: 0x0 - }; - } + return { + pixels: null, + internalFormat: 0x0 + }; + } + switch (type) { + case 0x1401 /* GL_UNSIGNED_BYTE */: + sizePerPixel = numChannels*1; break; case 0x1403 /* GL_UNSIGNED_SHORT */: - if (format == 0x1902 /* GL_DEPTH_COMPONENT */) { - sizePerPixel = 2; - } else { - GL.recordError(0x0500); // GL_INVALID_ENUM -#if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format); -#endif - return { - pixels: null, - internalFormat: 0x0 - }; - } + case 0x8D61 /* GL_HALF_FLOAT_OES */: + sizePerPixel = numChannels*2; break; case 0x1405 /* GL_UNSIGNED_INT */: - if (format == 0x1902 /* GL_DEPTH_COMPONENT */) { - sizePerPixel = 4; - } else { - GL.recordError(0x0500); // GL_INVALID_ENUM -#if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format); -#endif - return { - pixels: null, - internalFormat: 0x0 - }; - } + case 0x1406 /* GL_FLOAT */: + sizePerPixel = numChannels*4; break; case 0x84FA /* UNSIGNED_INT_24_8_WEBGL */: sizePerPixel = 4; @@ -488,58 +475,10 @@ var LibraryGL = { case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */: sizePerPixel = 2; break; - case 0x1406 /* GL_FLOAT */: -#if GL_ASSERTIONS - if (!GL.currentContext.floatExt) Module.printErr('Must have OES_texture_float to use float textures'); -#endif - switch (format) { - case 0x1907 /* GL_RGB */: - sizePerPixel = 3*4; - break; - case 0x1908 /* GL_RGBA */: - sizePerPixel = 4*4; - break; - default: - GL.recordError(0x0500); // GL_INVALID_ENUM -#if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format); -#endif - return { - pixels: null, - internalFormat: 0x0 - }; - } - internalFormat = GLctx.RGBA; - break; - case 0x8D61 /* GL_HALF_FLOAT_OES */: - switch (format) { - case 0x1903 /* GL_RED */: - sizePerPixel = 2; - break; - case 0x8277 /* GL_RG */: - sizePerPixel = 2*2; - break; - case 0x1907 /* GL_RGB */: - sizePerPixel = 3*2; - break; - case 0x1908 /* GL_RGBA */: - sizePerPixel = 4*2; - break; - default: - GL.recordError(0x0500); // GL_INVALID_ENUM -#if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format); -#endif - return { - pixels: null, - internalFormat: 0x0 - }; - } - break; default: GL.recordError(0x0500); // GL_INVALID_ENUM #if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format); + Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image/glReadPixels, type: ' + type + ', format: ' + format); #endif return { pixels: null, @@ -810,6 +749,10 @@ var LibraryGL = { // possible GL_DEBUG entry point: ctx = wrapDebugGL(ctx); if (!ctx) return 0; + return GL.registerContext(ctx, webGLContextAttributes); + }, + + registerContext: function(ctx, webGLContextAttributes) { var handle = GL.getNewId(GL.contexts); var context = { handle: handle, @@ -1117,38 +1060,15 @@ var LibraryGL = { glReadPixels__sig: 'viiiiiii', glReadPixels: function(x, y, width, height, format, type, pixels) { - var sizePerPixel; - switch (format) { - case 0x1907 /* GL_RGB */: - sizePerPixel = 3; - break; - case 0x1908 /* GL_RGBA */: - sizePerPixel = 4; - break; - default: - GL.recordError(0x0500/*GL_INVALID_ENUM*/); -#if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glReadPixels: Unsupported format ' + format + '!'); -#endif - return; - } - var totalSize = width*height*sizePerPixel; - if (type == 0x1401 /* GL_UNSIGNED_BYTE */ || type == 0x1400 /* GL_BYTE */) { - GLctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize)); - } else if (type == 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */ || type == 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */ - || type == 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */ || type == 0x1403 /* GL_UNSIGNED_SHORT */ || type == 0x1402 /* GL_SHORT */) { - GLctx.readPixels(x, y, width, height, format, type, HEAPU16.subarray(pixels >> 1, pixels + totalSize >> 1)); - } else if (type == 0x1404 /* GL_INT */ || type == 0x1405 /* GL_UNSIGNED_INT */) { - GLctx.readPixels(x, y, width, height, format, type, HEAPU32.subarray(pixels >> 2, pixels + totalSize >> 2)); - } else if (type == 0x1406 /* GL_FLOAT */) { - GLctx.readPixels(x, y, width, height, format, type, HEAPF32.subarray(pixels >> 2, pixels + totalSize >> 2)); - } else { + var data = GL.getTexPixelData(type, format, width, height, pixels, format); + if (!data.pixels) { GL.recordError(0x0500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glReadPixels: Unrecognized type ' + type + '!'); + Module.printErr('GL_INVALID_ENUM in glReadPixels: Unrecognized combination of type=' + type + ' and format=' + format + '!'); #endif return; } + GLctx.readPixels(x, y, width, height, format, type, data.pixels); }, glBindTexture__sig: 'vii', diff --git a/src/library_glfw.js b/src/library_glfw.js index a2f13c3cb4312..7998022485c9b 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -799,7 +799,7 @@ var LibraryGLFW = { glfwGetMonitors: function(count) { setValue(count, 1, 'i32'); if (!GLFW.monitors) { - GLFW.monitors = allocate(Int32Array([1]), 'i32', ALLOC_NORMAL); + GLFW.monitors = allocate([1, 0, 0, 0], 'i32', ALLOC_NORMAL); } return GLFW.monitors; }, diff --git a/src/library_memfs.js b/src/library_memfs.js index 8d4df98f8c45f..ca189918d9fcc 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -55,7 +55,7 @@ mergeInto(LibraryManager.library, { setattr: MEMFS.node_ops.setattr }, stream: FS.chrdev_stream_ops - }, + } }; } var node = FS.createNode(parent, name, mode, dev); diff --git a/src/library_sdl.js b/src/library_sdl.js index f2b99e560c2c0..befa4e4b32c9d 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1069,12 +1069,12 @@ var LibrarySDL = { }, setPannerPosition: function(info, x, y, z) { - if (!info) return 0; + if (!info) return; if (info.audio) { - if (info.audio.webAudioPannerNode) - info.audio.webAudioPannerNode['setPosition'](x, y, z); + if (info.audio.webAudioPannerNode) { + info.audio.webAudioPannerNode['setPosition'](x, y, z); + } } - return ret; }, // Plays out an SDL audio resource that was loaded with the Mix_Load APIs, when using Web Audio.. diff --git a/src/library_tty.js b/src/library_tty.js index bf4a2472c01d7..78157b8b6070c 100644 --- a/src/library_tty.js +++ b/src/library_tty.js @@ -41,9 +41,10 @@ mergeInto(LibraryManager.library, { }, close: function(stream) { // flush any pending line data - if (stream.tty.output.length) { - stream.tty.ops.put_char(stream.tty, {{{ charCode('\n') }}}); - } + stream.tty.ops.flush(stream.tty); + }, + flush: function(stream) { + stream.tty.ops.flush(stream.tty); }, read: function(stream, buffer, offset, length, pos /* ignored */) { if (!stream.tty || !stream.tty.ops.get_char) { @@ -123,6 +124,12 @@ mergeInto(LibraryManager.library, { } return tty.input.shift(); }, + flush: function(tty) { + if (tty.output && tty.output.length > 0) { + Module['print'](tty.output.join('')); + tty.output = []; + } + }, put_char: function(tty, val) { if (val === null || val === {{{ charCode('\n') }}}) { Module['print'](tty.output.join('')); @@ -140,7 +147,13 @@ mergeInto(LibraryManager.library, { } else { tty.output.push(TTY.utf8.processCChar(val)); } - } + }, + flush: function(tty) { + if (tty.output && tty.output.length > 0) { + Module['printErr'](tty.output.join('')); + tty.output = []; + } + } } } }); \ No newline at end of file diff --git a/src/parseTools.js b/src/parseTools.js index cb912ece1d21a..fd7a813ec7586 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1522,7 +1522,7 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) { return 'for (var $$src = ' + oldSrc + ', $$dest = ' + oldDest + ', $$stop = $$src + ' + num + '; $$src < $$stop; $$src++, $$dest++) {\n' + unroll(type, 1) + ' }'; } else { // USE_TYPED_ARRAYS == 2 - // If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset + // If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memcpy if (!isNumber(num)) num = stripCorrections(num); if (!isNumber(align)) align = stripCorrections(align); if (!isNumber(num) || (parseInt(num)/align >= UNROLL_LOOP_MAX)) { diff --git a/src/preamble.js b/src/preamble.js index 693f049c9de9e..30f5b9d30b4a5 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -340,13 +340,15 @@ function getCFunc(ident) { var cwrap, ccall; (function(){ - var stack = 0; var JSfuncs = { - 'stackSave' : function() { - stack = Runtime.stackSave(); + // Helpers for cwrap -- it can't refer to Runtime directly because it might + // be renamed by closure, instead it calls JSfuncs['stackSave'].body to find + // out what the minified function name is. + 'stackSave': function() { + Runtime.stackSave() }, - 'stackRestore' : function() { - Runtime.stackRestore(stack); + 'stackRestore': function() { + Runtime.stackRestore() }, // type conversion from js to c 'arrayToC' : function(arr) { @@ -371,6 +373,7 @@ var cwrap, ccall; ccall = function ccallFunc(ident, returnType, argTypes, args) { var func = getCFunc(ident); var cArgs = []; + var stack = 0; #if ASSERTIONS assert(returnType !== 'array', 'Return type should not be "array".'); #endif @@ -387,7 +390,7 @@ var cwrap, ccall; } var ret = func.apply(null, cArgs); if (returnType === 'string') ret = Pointer_stringify(ret); - if (stack !== 0) JSfuncs['stackRestore'](); + if (stack !== 0) Runtime.stackRestore(stack); return ret; } @@ -425,7 +428,7 @@ var cwrap, ccall; if (!numericArgs) { // Generate the code needed to convert the arguments from javascript // values to pointers - funcstr += JSsource['stackSave'].body + ';'; + funcstr += 'var stack = ' + JSsource['stackSave'].body + ';'; for (var i = 0; i < nargs; i++) { var arg = argNames[i], type = argTypes[i]; if (type === 'number') continue; @@ -447,7 +450,7 @@ var cwrap, ccall; } if (!numericArgs) { // If we had a stack, restore it - funcstr += JSsource['stackRestore'].body + ';'; + funcstr += JSsource['stackRestore'].body.replace('()', '(stack)') + ';'; } funcstr += 'return ret})'; return eval(funcstr); @@ -907,7 +910,7 @@ function demangle(func) { return ret + flushList(); } } - var final = func; + var parsed = func; try { // Special-case the entry point, since its name differs from other name mangling. if (func == 'Object._main' || func == '_main') { @@ -921,14 +924,14 @@ function demangle(func) { case 'n': return 'operator new()'; case 'd': return 'operator delete()'; } - final = parse(); + parsed = parse(); } catch(e) { - final += '?'; + parsed += '?'; } - if (final.indexOf('?') >= 0 && !hasLibcxxabi) { + if (parsed.indexOf('?') >= 0 && !hasLibcxxabi) { Runtime.warnOnce('warning: a problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling'); } - return final; + return parsed; } function demangleAll(text) { diff --git a/src/settings.js b/src/settings.js index 8cf44149e5d3b..9795a76a47f33 100644 --- a/src/settings.js +++ b/src/settings.js @@ -315,7 +315,7 @@ var EXCEPTION_CATCHING_WHITELIST = []; // Enables catching exception in the lis var ASYNCIFY = 0; // Whether to enable asyncify transformation // This allows to inject some async functions to the C code that appear to be sync // e.g. emscripten_sleep -var ASYNCIFY_FUNCTIONS = ['emscripten_sleep', // Functions that call any funcion in the list, directly or indirectly +var ASYNCIFY_FUNCTIONS = ['emscripten_sleep', // Functions that call any function in the list, directly or indirectly 'emscripten_wget', // will be transformed 'emscripten_yield']; var ASYNCIFY_WHITELIST = ['qsort', // Functions in this list are never considered async, even if they appear in ASYNCIFY_FUNCTIONS diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 09eea2fbba7a9..1ec344927b106 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -1379,9 +1379,11 @@ namespace emscripten { typedef std::vector VecType; void (VecType::*push_back)(const T&) = &VecType::push_back; + void (VecType::*resize)(const size_t) = &VecType::resize; return class_>(name) .template constructor<>() .function("push_back", push_back) + .function("resize", resize) .function("size", &VecType::size) .function("get", &internal::VectorAccess::get) .function("set", &internal::VectorAccess::set) diff --git a/system/include/emscripten/vector.h b/system/include/emscripten/vector.h index 6fbed22475dbc..0b51af3581745 100644 --- a/system/include/emscripten/vector.h +++ b/system/include/emscripten/vector.h @@ -14,6 +14,7 @@ unsigned int emscripten_float32x4_signmask(float32x4 __x) __attribute__((__nothr float32x4 emscripten_float32x4_min(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); float32x4 emscripten_float32x4_max(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); +float32x4 emscripten_float32x4_abs(float32x4 __a) __attribute__((__nothrow__, __const__)); float32x4 emscripten_float32x4_sqrt(float32x4 __a) __attribute__((__nothrow__, __const__)); int32x4 emscripten_float32x4_lessThan(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); int32x4 emscripten_float32x4_lessThanOrEqual(float32x4 __a, float32x4 __b) __attribute__((__nothrow__, __const__)); diff --git a/system/include/emscripten/xmmintrin.h b/system/include/emscripten/xmmintrin.h index 0ee8c265efbc9..55ae928c8adba 100644 --- a/system/include/emscripten/xmmintrin.h +++ b/system/include/emscripten/xmmintrin.h @@ -3,6 +3,11 @@ #include +// Emscripten SIMD support doesn't support MMX/float32x2/__m64. +// However, we support loading and storing 2-vectors, so +// treat "__m64 *" as "void *" for that purpose. +typedef void __m64; + typedef float32x4 __m128; typedef int32x4 __v4si; typedef float32x4 __v4sf; @@ -14,21 +19,29 @@ _mm_set_ps(float __z, float __y, float __x, float __w) } static __inline__ __m128 __attribute__((__always_inline__)) -_mm_set1_ps(float __w) +_mm_setr_ps(float __z, float __y, float __x, float __w) { - return (__m128){ __w, __w, __w, __w }; + return (__m128){ __z, __y, __x, __w }; +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_set_ss(float __w) +{ + return (__m128){ __w, 0, 0, 0 }; } static __inline__ __m128 __attribute__((__always_inline__)) _mm_set_ps1(float __w) { - return _mm_set1_ps(__w); + return (__m128){ __w, __w, __w, __w }; } +#define _mm_set1_ps _mm_set_ps1 + static __inline__ __m128 __attribute__((__always_inline__)) _mm_setzero_ps(void) { - return (__m128){ 0.0, 0.0, 0.0, 0.0 }; + return (__m128){ 0.0f, 0.0f, 0.0f, 0.0f }; } static __inline__ __m128 __attribute__((__always_inline__)) @@ -37,6 +50,24 @@ _mm_load_ps(const float *__p) return *(__m128 *)__p; } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_loadl_pi(__m128 __a, const void /*__m64*/ *__p) +{ + 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) +{ + 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] }; +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_loadu_ps(const float *__p) { @@ -47,11 +78,71 @@ _mm_loadu_ps(const float *__p) return ((struct __unaligned *)__p)->__v; } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_load_ps1(const float *__p) +{ + return (__m128){ *__p, *__p, *__p, *__p }; +} +#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. + return (__m128){ *__p, 0.0f, 0.0f, 0.0f }; +} + +static __inline__ void __attribute__((__always_inline__)) +_mm_storel_pi(void /*__m64*/ *__p, __m128 __a) +{ + ((float*)__p)[0] = __a[0]; + ((float*)__p)[1] = __a[1]; +} + +static __inline__ void __attribute__((__always_inline__)) +_mm_storeh_pi(void /*__m64*/ *__p, __m128 __a) +{ + ((float*)__p)[0] = __a[2]; + ((float*)__p)[1] = __a[3]; +} + static __inline__ void __attribute__((__always_inline__)) _mm_store_ps(float *__p, __m128 __a) { *(__m128 *)__p = __a; } +// No NTA cache hint available. +#define _mm_stream_ps _mm_store_ps + +#define _MM_SHUFFLE(w, z, y, x) (((w) << 6) | ((z) << 4) | ((y) << 2) | (x)) + +// This is defined as a macro because __builtin_shufflevector requires its +// mask argument to be a compile-time constant. +#define _mm_shuffle_ps(a, b, mask) \ + ((__m128)__builtin_shufflevector((a), (b), \ + (((mask) >> 0) & 0x3) + 0, \ + (((mask) >> 2) & 0x3) + 0, \ + (((mask) >> 4) & 0x3) + 4, \ + (((mask) >> 6) & 0x3) + 4)) + +static __inline__ void __attribute__((__always_inline__)) +_mm_storer_ps(float *__p, __m128 __a) +{ + _mm_store_ps(__p, _mm_shuffle_ps(__a, __a, _MM_SHUFFLE(0, 1, 2, 3))); +} + +static __inline__ void __attribute__((__always_inline__)) +_mm_store_ps1(float *__p, __m128 __a) +{ + _mm_store_ps(__p, _mm_shuffle_ps(__a, __a, _MM_SHUFFLE(0, 0, 0, 0))); +} +#define _mm_store1_ps _mm_store_ps1 + +static __inline__ void __attribute__((__always_inline__)) +_mm_store_ss(float *__p, __m128 __a) +{ + *__p = __a[0]; +} static __inline__ void __attribute__((__always_inline__)) _mm_storeu_ps(float *__p, __m128 __a) @@ -69,79 +160,127 @@ _mm_movemask_ps(__m128 __a) return emscripten_float32x4_signmask(__a); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_move_ss(__m128 __a, __m128 __b) +{ + return __builtin_shufflevector(__a, __b, 4, 1, 2, 3); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_add_ps(__m128 __a, __m128 __b) { return __a + __b; } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_add_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_add_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_sub_ps(__m128 __a, __m128 __b) { return __a - __b; } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_sub_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_sub_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_mul_ps(__m128 __a, __m128 __b) { return __a * __b; } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_mul_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_mul_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_div_ps(__m128 __a, __m128 __b) { return __a / __b; } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_div_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_div_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_min_ps(__m128 __a, __m128 __b) { - // Use a comparsion and select instead of emscripten_float32x4_min in order to + // Use a comparison and select instead of emscripten_float32x4_min in order to // correctly emulate x86's NaN and -0.0 semantics. return emscripten_float32x4_select(emscripten_float32x4_lessThan(__a, __b), __a, __b); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_min_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_min_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_max_ps(__m128 __a, __m128 __b) { - // Use a comparsion and select instead of emscripten_float32x4_max in order to + // Use a comparison and select instead of emscripten_float32x4_max in order to // correctly emulate x86's NaN and -0.0 semantics. return emscripten_float32x4_select(emscripten_float32x4_greaterThan(__a, __b), __a, __b); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_max_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_max_ps(__a, __b)); +} + +// TODO: we should re-evaluate rcpps, rsqrtps, and friends once we figure out what we're doing with SIMD.float32x4.reciprocal, SIMD.float32x4.reciprocalSqrt, and friends in SIMD.js. +#define _mm_rcp_ps(__a) (_mm_set1_ps(1.0f) / (__a)) + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_rcp_ss(__m128 __a) +{ + return _mm_move_ss(__a, _mm_rcp_ps(__a)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_sqrt_ps(__m128 __a) { return emscripten_float32x4_sqrt(__a); } -// This is defined as a macro because __builtin_shufflevector requires its -// mask argument to be a compile-time constant. -#define _mm_shuffle_ps(a, b, mask) \ - ((__m128)__builtin_shufflevector((a), (b), \ - (((mask) >> 0) & 0x3) + 0, \ - (((mask) >> 2) & 0x3) + 0, \ - (((mask) >> 4) & 0x3) + 4, \ - (((mask) >> 6) & 0x3) + 4)) +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_sqrt_ss(__m128 __a) +{ + return _mm_move_ss(__a, _mm_sqrt_ps(__a)); +} -#define _MM_SHUFFLE(w, z, y, x) (((w) << 6) | ((z) << 4) | ((y) << 2) | (x)) +#define _mm_rsqrt_ps(__a) _mm_rcp_ps(_mm_sqrt_ps((__a))) static __inline__ __m128 __attribute__((__always_inline__)) -_mm_unpackhi_ps(__m128 __a, __m128 __b) +_mm_rsqrt_ss(__m128 __a) { - return __builtin_shufflevector(__a, __b, 2, 6, 3, 7); + return _mm_move_ss(__a, _mm_rsqrt_ps(__a)); } static __inline__ __m128 __attribute__((__always_inline__)) -_mm_unpacklo_ps(__m128 __a, __m128 __b) +_mm_unpackhi_ps(__m128 __a, __m128 __b) { - return __builtin_shufflevector(__a, __b, 0, 4, 1, 5); + return __builtin_shufflevector(__a, __b, 2, 6, 3, 7); } static __inline__ __m128 __attribute__((__always_inline__)) -_mm_move_ss(__m128 __a, __m128 __b) +_mm_unpacklo_ps(__m128 __a, __m128 __b) { - return __builtin_shufflevector(__a, __b, 4, 1, 2, 3); + return __builtin_shufflevector(__a, __b, 0, 4, 1, 5); } static __inline__ __m128 __attribute__((__always_inline__)) @@ -178,24 +317,48 @@ _mm_cmplt_ps(__m128 __a, __m128 __b) return emscripten_float32x4_lessThan(__a, __b); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmplt_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmplt_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_cmple_ps(__m128 __a, __m128 __b) { return emscripten_float32x4_lessThanOrEqual(__a, __b); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmple_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmple_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_cmpeq_ps(__m128 __a, __m128 __b) { return emscripten_float32x4_equal(__a, __b); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpeq_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpeq_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_cmpge_ps(__m128 __a, __m128 __b) { return emscripten_float32x4_greaterThanOrEqual(__a, __b); } +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpge_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpge_ps(__a, __b)); +} + static __inline__ __m128 __attribute__((__always_inline__)) _mm_cmpgt_ps(__m128 __a, __m128 __b) { @@ -203,18 +366,50 @@ _mm_cmpgt_ps(__m128 __a, __m128 __b) } static __inline__ __m128 __attribute__((__always_inline__)) -_mm_cmpnlt_ps(__m128 __a, __m128 __b) +_mm_cmpgt_ss(__m128 __a, __m128 __b) { - return emscripten_float32x4_not(emscripten_float32x4_lessThan(__a, __b)); + return _mm_move_ss(__a, _mm_cmpgt_ps(__a, __b)); } -static __inline__ __m128 __attribute__((__always_inline__)) -_mm_cmpnle_ps(__m128 __a, __m128 __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) { - return emscripten_float32x4_not(emscripten_float32x4_lessThanOrEqual(__a, __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); } -// TODO: _mm_cmpord_ps, _mm_cmpunord_ps +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)); +} + +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; +} + +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)); +} static __inline__ __m128 __attribute__((__always_inline__)) _mm_and_ps(__m128 __a, __m128 __b) @@ -240,4 +435,181 @@ _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)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpneq_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpneq_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpnge_ps(__m128 __a, __m128 __b) +{ + return emscripten_float32x4_not(_mm_cmpge_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpnge_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpnge_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpngt_ps(__m128 __a, __m128 __b) +{ + return emscripten_float32x4_not(_mm_cmpgt_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpngt_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpngt_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpnle_ps(__m128 __a, __m128 __b) +{ + return emscripten_float32x4_not(_mm_cmple_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpnle_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpnle_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpnlt_ps(__m128 __a, __m128 __b) +{ + return emscripten_float32x4_not(_mm_cmplt_ps(__a, __b)); +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cmpnlt_ss(__m128 __a, __m128 __b) +{ + return _mm_move_ss(__a, _mm_cmpnlt_ps(__a, __b)); +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_comieq_ss(__m128 __a, __m128 __b) +{ + return __a[0] == __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_comige_ss(__m128 __a, __m128 __b) +{ + return __a[0] >= __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_comigt_ss(__m128 __a, __m128 __b) +{ + return __a[0] > __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_comile_ss(__m128 __a, __m128 __b) +{ + return __a[0] <= __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_comilt_ss(__m128 __a, __m128 __b) +{ + return __a[0] < __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_comineq_ss(__m128 __a, __m128 __b) +{ + return __a[0] != __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_ucomieq_ss(__m128 __a, __m128 __b) +{ + return __a[0] == __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_ucomige_ss(__m128 __a, __m128 __b) +{ + return __a[0] >= __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_ucomigt_ss(__m128 __a, __m128 __b) +{ + return __a[0] > __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_ucomile_ss(__m128 __a, __m128 __b) +{ + return __a[0] <= __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_ucomilt_ss(__m128 __a, __m128 __b) +{ + return __a[0] < __b[0]; +} + +static __inline__ int __attribute__((__always_inline__)) +_mm_ucomineq_ss(__m128 __a, __m128 __b) +{ + return __a[0] != __b[0]; +} + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cvtsi32_ss(__m128 __a, int __b) +{ + __a[0] = (float)__b; + return __a; +} +#define _mm_cvt_si2ss _mm_cvtsi32_ss + +static __inline__ int __attribute__((__always_inline__)) _mm_cvtss_si32(__m128 a) +{ + return (int)a[0]; // TODO: Rounding mode +} +#define _mm_cvt_ss2si _mm_cvtss_si32 + +static __inline__ int __attribute__((__always_inline__)) _mm_cvttss_si32(__m128 a) +{ + return (int)a[0]; // TODO: Rounding mode, truncate. +} +#define _mm_cvtt_ss2si _mm_cvttss_si32 + +static __inline__ __m128 __attribute__((__always_inline__)) +_mm_cvtsi64_ss(__m128 __a, long long __b) +{ + __a[0] = (float)__b; + return __a; +} + +static __inline__ long long __attribute__((__always_inline__)) +_mm_cvtss_si64(__m128 __a) +{ + return (long long)__a[0]; // TODO: Rounding mode +} + +static __inline__ long long __attribute__((__always_inline__)) +_mm_cvttss_si64(__m128 __a) +{ + return (long long)__a[0]; // TODO: Rounding mode, truncate. +} + +static __inline__ float __attribute__((__always_inline__)) +_mm_cvtss_f32(__m128 __a) +{ + return (float)__a[0]; +} #endif diff --git a/tests/benchmark_sse1.cpp b/tests/benchmark_sse1.cpp new file mode 100644 index 0000000000000..6a1efaab16243 --- /dev/null +++ b/tests/benchmark_sse1.cpp @@ -0,0 +1,335 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __EMSCRIPTEN__ +#include +#define _mm_storeu_ps _mm_store_ps // Hack for missing function. Works for now since Emscripten does not care about alignment. +#define aligned_alloc(align, size) malloc(size) // Hack for missing function. Works for now since Emscripten does not care about alignment. +#endif + +#if defined(__unix__) && !defined(__EMSCRIPTEN__) // Native build without Emscripten. +#include +#include +#include +#include +#define tick_t unsigned long long +#endif + +#ifdef __APPLE__ +#include +#define aligned_alloc(align, size) malloc(size) +#endif + + +// Scalar horizonal max across four lanes. +float hmax(__m128 m) +{ + float f[4]; + _mm_storeu_ps(f, m); + return fmax(fmax(f[0], f[1]), fmax(f[2], f[3])); +} + +#ifdef __EMSCRIPTEN__ +#define tick emscripten_get_now +#define tick_t double +tick_t ticks_per_sec() { return 1000.0; } +#elif defined(__APPLE__) +#define tick_t unsigned long long +#define tick mach_absolute_time +tick_t ticks_per_sec() +{ + mach_timebase_info_data_t timeBaseInfo; + mach_timebase_info(&timeBaseInfo); + return 1000000000ULL * (uint64_t)timeBaseInfo.denom / (uint64_t)timeBaseInfo.numer; +} +#elif defined(_POSIX_MONOTONIC_CLOCK) +inline tick_t tick() +{ + timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec; +} +tick_t ticks_per_sec() +{ + return 1000 * 1000 * 1000; +} +#elif defined(_POSIX_C_SOURCE) +inline tick_t tick() +{ + timeval t; + gettimeofday(&t, NULL); + return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec; +} +tick_t ticks_per_sec() +{ + return 1000 * 1000; +} +#else +#error No tick_t +#endif + +const int N = 2*1024*1024; + +tick_t scalarTotalTicks = 0; +tick_t simdTotalTicks = 0; +tick_t scalarTicks = 0; +const char *chartName = ""; +#define SETCHART(x) chartName = (x); + +#define START() \ + do { \ + tick_t start = tick(); + +bool comma=false; +#define END(result, name) \ + tick_t end = tick(); \ + tick_t ticks = end - start; \ + scalarTotalTicks += scalarTicks; \ + simdTotalTicks += ticks; \ + double nsecs = (double)ticks * 1000.0 * 1000.0 * 1000.0 / ticks_per_sec() / N; \ + printf("%s{ \"chart\": \"%s\", \"category\": \"%s\", \"scalar\": %f, \"simd\": %f }\n", comma?",":"", chartName, name, scalarTime, nsecs); \ + comma = true; \ + /*printf(name ": %f msecs (%.3fx of scalar)%s\n", msecs, msecs/scalarTime);*/ \ + printf("%s", (result) != 0 ? "Error!" : ""); \ + } while(0) + +#define ENDSCALAR(result, name) \ + tick_t end = tick(); \ + scalarTicks = end - start; \ + scalarTime = (double)scalarTicks * 1000.0 * 1000.0 * 1000.0 / ticks_per_sec() / N; \ + printf("%s", (result) != 0 ? "Error!" : ""); \ + } while(0) + +void Print(__m128 m) +{ + float val[4]; + _mm_storeu_ps(val, m); + fprintf(stderr, "[%g, %g, %g, %g]\n", val[3], val[2], val[1], val[0]); +} + +bool always_true() { return time(NULL) != 0; } // This function always returns true, but the compiler should not know this. + +float __attribute__((noinline)) *get_src() { return always_true() ? (float*)aligned_alloc(16, (N+16)*sizeof(float)) : 0; } +float __attribute__((noinline)) *get_src2() { return always_true() ? (float*)aligned_alloc(16, (N+16)*sizeof(float)) : 0; } +float __attribute__((noinline)) *get_dst() { return always_true() ? (float*)aligned_alloc(16, (N+16)*sizeof(float)) : 0; } + +float checksum_dst(float *dst) +{ + if (always_true()) return 0.f; + else + { + float s = 0.f; for(int i = 0; i < N; ++i) s += dst[i]; + return s; + } +} + +uint32_t fcastu(float f) { return *(uint32_t*)&f; } +float ucastf(uint32_t t) { return *(float*)&t; } + +// load-store test +#define LS_TEST(msg, load_instr, load_offset, store_instr, store_offset) \ + START(); \ + for(int i = 0; i < N; i += 4) \ + store_instr((float*)dst+store_offset+i, load_instr(src+load_offset+i)); \ + END(checksum_dst(dst), msg); + +#define LS64_TEST(msg, load_instr, load_offset, store_instr, store_offset) \ + START(); \ + for(int i = 0; i < N; i += 4) \ + store_instr((__m64*)(dst+store_offset+i), load_instr(src+load_offset+i)); \ + END(checksum_dst(dst), msg); + +// set-store test +#define SS_TEST(msg, set_instr) \ + START(); \ + for(int i = 0; i < N; i += 4) \ + _mm_store_ps((float*)dst+i, set_instr); \ + END(checksum_dst(dst), msg); + +#define UNARYOP_TEST(msg, instr, op0) \ + START(); \ + __m128 o = op0; \ + for(int i = 0; i < N; i += 4) \ + o = instr(o); \ + _mm_store_ps(dst, o); \ + END(checksum_dst(dst), msg); + +#define BINARYOP_TEST(msg, instr, op0, op1) \ + START(); \ + __m128 o0 = op0; \ + __m128 o1 = op1; \ + for(int i = 0; i < N; i += 4) \ + o0 = instr(o0, o1); \ + _mm_store_ps(dst, o0); \ + END(checksum_dst(dst), msg); + +#define Max(a,b) ((a) >= (b) ? (a) : (b)) +#define Min(a,b) ((a) <= (b) ? (a) : (b)) + +static __inline__ int Isnan(float __f) +{ + return (*(unsigned int*)&__f << 1) > 0xFF000000u; +} + +int main() +{ +#ifndef __EMSCRIPTEN__ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); +#endif + + printf ("{ \"workload\": %u, \"results\": [\n", N); + assert(N%4 == 0); // Don't care about the tail for now. + float *src = get_src();//(float*)aligned_alloc(16, N*sizeof(float)); + for(int i = 0; i < N; ++i) + src[i] = (float)rand() / RAND_MAX; + float *src2 = get_src2();//(float*)aligned_alloc(16, N*sizeof(float)); + for(int i = 0; i < N; ++i) + src2[i] = (float)rand() / RAND_MAX; + float *dst = get_dst();//(float*)aligned_alloc(16, N*sizeof(float)); + + float scalarTime; + SETCHART("load"); + START(); + for(int i = 0; i < N; ++i) + dst[i] = src[i]; + ENDSCALAR(checksum_dst(dst), "scalar"); + + LS_TEST("_mm_load_ps", _mm_load_ps, 0, _mm_store_ps, 0); + LS_TEST("_mm_load_ps1", _mm_load_ps1, 1, _mm_store_ps, 0); + LS_TEST("_mm_load_ss", _mm_load_ss, 1, _mm_store_ps, 0); + LS_TEST("_mm_load1_ps", _mm_load1_ps, 1, _mm_store_ps, 0); + // _mm_loadh_pi + // _mm_loadl_pi + LS_TEST("_mm_loadr_ps", _mm_loadr_ps, 0, _mm_store_ps, 0); + LS_TEST("_mm_loadu_ps", _mm_loadu_ps, 1, _mm_store_ps, 0); + + SETCHART("set"); + SS_TEST("_mm_set_ps", _mm_set_ps(src[i+2], src[i+1], src[i+5], src[i+0])); + SS_TEST("_mm_set_ps1", _mm_set_ps1(src[i])); + SS_TEST("_mm_set_ss", _mm_set_ss(src[i])); + SS_TEST("_mm_set1_ps", _mm_set1_ps(src[i])); + SS_TEST("_mm_setr_ps", _mm_set_ps(src[i+2], src[i+1], src[i+5], src[i+0])); + SS_TEST("_mm_setzero_ps", _mm_setzero_ps()); + + SETCHART("move"); + SS_TEST("_mm_move_ss", _mm_move_ss(_mm_load_ps(src+i), _mm_load_ps(src2+i))); + SS_TEST("_mm_movehl_ps", _mm_movehl_ps(_mm_load_ps(src+i), _mm_load_ps(src2+i))); + SS_TEST("_mm_movelh_ps", _mm_movelh_ps(_mm_load_ps(src+i), _mm_load_ps(src2+i))); + + SETCHART("store"); + LS_TEST("_mm_store_ps", _mm_load_ps, 0, _mm_store_ps, 0); + LS_TEST("_mm_store_ps1", _mm_load_ps, 0, _mm_store_ps1, 0); + LS_TEST("_mm_store_ss", _mm_load_ps, 0, _mm_store_ss, 1); + LS64_TEST("_mm_storeh_pi", _mm_load_ps, 0, _mm_storeh_pi, 1); + LS64_TEST("_mm_storel_pi", _mm_load_ps, 0, _mm_storel_pi, 1); + LS_TEST("_mm_storer_ps", _mm_load_ps, 0, _mm_storer_ps, 0); + LS_TEST("_mm_storeu_ps", _mm_load_ps, 0, _mm_storeu_ps, 1); + LS_TEST("_mm_stream_ps", _mm_load_ps, 0, _mm_stream_ps, 0); + + SETCHART("arithmetic"); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] += src2[0]; dst[1] += src2[1]; dst[2] += src2[2]; dst[3] += src2[3]; } ENDSCALAR(checksum_dst(dst), "scalar add"); + BINARYOP_TEST("_mm_add_ps", _mm_add_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_add_ss", _mm_add_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] /= src2[0]; dst[1] /= src2[1]; dst[2] /= src2[2]; dst[3] /= src2[3]; } ENDSCALAR(checksum_dst(dst), "scalar div"); + BINARYOP_TEST("_mm_div_ps", _mm_div_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_div_ss", _mm_div_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] *= src2[0]; dst[1] *= src2[1]; dst[2] *= src2[2]; dst[3] *= src2[3]; } ENDSCALAR(checksum_dst(dst), "scalar mul"); + BINARYOP_TEST("_mm_mul_ps", _mm_mul_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_mul_ss", _mm_mul_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] -= src2[0]; dst[1] -= src2[1]; dst[2] -= src2[2]; dst[3] -= src2[3]; } ENDSCALAR(checksum_dst(dst), "scalar sub"); + BINARYOP_TEST("_mm_sub_ps", _mm_sub_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_sub_ss", _mm_sub_ss, _mm_load_ps(src), _mm_load_ps(src2)); + + SETCHART("roots"); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = 1.f / dst[0]; dst[1] = 1.f / dst[1]; dst[2] = 1.f / dst[2]; dst[3] = 1.f / dst[3]; } ENDSCALAR(checksum_dst(dst), "scalar rcp"); + UNARYOP_TEST("_mm_rcp_ps", _mm_rcp_ps, _mm_load_ps(src)); + UNARYOP_TEST("_mm_rcp_ss", _mm_rcp_ss, _mm_load_ps(src)); + + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = 1.f / sqrtf(dst[0]); dst[1] = 1.f / sqrtf(dst[1]); dst[2] = 1.f / sqrtf(dst[2]); dst[3] = 1.f / sqrtf(dst[3]); } ENDSCALAR(checksum_dst(dst), "scalar rsqrt"); + UNARYOP_TEST("_mm_rsqrt_ps", _mm_rsqrt_ps, _mm_load_ps(src)); + UNARYOP_TEST("_mm_rsqrt_ss", _mm_rsqrt_ss, _mm_load_ps(src)); + + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = sqrtf(dst[0]); dst[1] = sqrtf(dst[1]); dst[2] = sqrtf(dst[2]); dst[3] = sqrtf(dst[3]); } ENDSCALAR(checksum_dst(dst), "scalar sqrt"); + UNARYOP_TEST("_mm_sqrt_ps", _mm_sqrt_ps, _mm_load_ps(src)); + UNARYOP_TEST("_mm_sqrt_ss", _mm_sqrt_ss, _mm_load_ps(src)); + + SETCHART("logical"); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = ucastf(fcastu(dst[0]) & fcastu(src2[0])); dst[1] = ucastf(fcastu(dst[1]) & fcastu(src2[1])); dst[2] = ucastf(fcastu(dst[2]) & fcastu(src2[2])); dst[3] = ucastf(fcastu(dst[3]) & fcastu(src2[3])); } ENDSCALAR(checksum_dst(dst), "scalar and"); + BINARYOP_TEST("_mm_and_ps", _mm_and_ps, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = ucastf((~fcastu(dst[0])) & fcastu(src2[0])); dst[1] = ucastf((~fcastu(dst[1])) & fcastu(src2[1])); dst[2] = ucastf((~fcastu(dst[2])) & fcastu(src2[2])); dst[3] = ucastf((~fcastu(dst[3])) & fcastu(src2[3])); } ENDSCALAR(checksum_dst(dst), "scalar andnot"); + BINARYOP_TEST("_mm_andnot_ps", _mm_andnot_ps, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = ucastf(fcastu(dst[0]) | fcastu(src2[0])); dst[1] = ucastf(fcastu(dst[1]) | fcastu(src2[1])); dst[2] = ucastf(fcastu(dst[2]) | fcastu(src2[2])); dst[3] = ucastf(fcastu(dst[3]) | fcastu(src2[3])); } ENDSCALAR(checksum_dst(dst), "scalar or"); + BINARYOP_TEST("_mm_or_ps", _mm_or_ps, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = ucastf(fcastu(dst[0]) ^ fcastu(src2[0])); dst[1] = ucastf(fcastu(dst[1]) ^ fcastu(src2[1])); dst[2] = ucastf(fcastu(dst[2]) ^ fcastu(src2[2])); dst[3] = ucastf(fcastu(dst[3]) ^ fcastu(src2[3])); } ENDSCALAR(checksum_dst(dst), "scalar xor"); + BINARYOP_TEST("_mm_xor_ps", _mm_xor_ps, _mm_load_ps(src), _mm_load_ps(src2)); + + SETCHART("cmp"); +#ifndef __EMSCRIPTEN__ // TODO: Disabled due to https://github.com/kripken/emscripten/issues/2841 + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (dst[0] == src2[0]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (dst[1] == src2[1]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (dst[2] == src2[2]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (dst[3] == src2[3]) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmp=="); + BINARYOP_TEST("_mm_cmpeq_ps", _mm_cmpeq_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmpeq_ss", _mm_cmpeq_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (dst[0] >= src2[0]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (dst[1] >= src2[1]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (dst[2] >= src2[2]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (dst[3] >= src2[3]) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmp>="); + BINARYOP_TEST("_mm_cmpge_ps", _mm_cmpge_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmpge_ss", _mm_cmpge_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (dst[0] > src2[0]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (dst[1] > src2[1]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (dst[2] > src2[2]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (dst[3] > src2[3]) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmp>"); + BINARYOP_TEST("_mm_cmpgt_ps", _mm_cmpgt_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmpgt_ss", _mm_cmpgt_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (dst[0] <= src2[0]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (dst[1] <= src2[1]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (dst[2] <= src2[2]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (dst[3] <= src2[3]) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmp<="); + BINARYOP_TEST("_mm_cmple_ps", _mm_cmple_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmple_ss", _mm_cmple_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (dst[0] < src2[0]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (dst[1] < src2[1]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (dst[2] < src2[2]) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (dst[3] < src2[3]) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmp<"); + BINARYOP_TEST("_mm_cmplt_ps", _mm_cmplt_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmplt_ss", _mm_cmplt_ss, _mm_load_ps(src), _mm_load_ps(src2)); +#endif + + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (!Isnan(dst[0]) && !Isnan(src2[0])) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (!Isnan(dst[1]) && !Isnan(src2[1])) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (!Isnan(dst[2]) && !Isnan(src2[2])) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (!Isnan(dst[3]) && !Isnan(src2[3])) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmpord"); + BINARYOP_TEST("_mm_cmpord_ps", _mm_cmpord_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmpord_ss", _mm_cmpord_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = (Isnan(dst[0]) || Isnan(src2[0])) ? ucastf(0xFFFFFFFFU) : 0.f; dst[1] = (Isnan(dst[1]) || Isnan(src2[1])) ? ucastf(0xFFFFFFFFU) : 0.f; dst[2] = (Isnan(dst[2]) || Isnan(src2[2])) ? ucastf(0xFFFFFFFFU) : 0.f; dst[3] = (Isnan(dst[3]) || Isnan(src2[3])) ? ucastf(0xFFFFFFFFU) : 0.f; } ENDSCALAR(checksum_dst(dst), "scalar cmpunord"); + BINARYOP_TEST("_mm_cmpunord_ps", _mm_cmpunord_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_cmpunord_ss", _mm_cmpunord_ss, _mm_load_ps(src), _mm_load_ps(src2)); + + SETCHART("max"); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = Max(dst[0], src2[0]); dst[1] = Max(dst[1], src2[1]); dst[2] = Max(dst[2], src2[2]); dst[3] = Max(dst[3], src2[3]); } ENDSCALAR(checksum_dst(dst), "scalar max"); + BINARYOP_TEST("_mm_max_ps", _mm_max_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_max_ss", _mm_max_ss, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = Min(dst[0], src2[0]); dst[1] = Min(dst[1], src2[1]); dst[2] = Min(dst[2], src2[2]); dst[3] = Min(dst[3], src2[3]); } ENDSCALAR(checksum_dst(dst), "scalar min"); + BINARYOP_TEST("_mm_min_ps", _mm_min_ps, _mm_load_ps(src), _mm_load_ps(src2)); + BINARYOP_TEST("_mm_min_ss", _mm_min_ss, _mm_load_ps(src), _mm_load_ps(src2)); + + SETCHART("shuffle"); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[3] = dst[1]; dst[2] = dst[0]; dst[1] = src2[3]; dst[0] = src2[2]; } ENDSCALAR(checksum_dst(dst), "scalar shuffle"); +// BINARYOP_TEST("_mm_shuffle_ps", _mm_shuffle_ps, _mm_load_ps(src), _mm_load_ps(src2)); + START(); + __m128 o0 = _mm_load_ps(src); + __m128 o1 = _mm_load_ps(src2); + for(int i = 0; i < N; i += 4) + o0 = _mm_shuffle_ps(o0, o1, _MM_SHUFFLE(1, 0, 3, 2)); + _mm_store_ps(dst, o0); + END(checksum_dst(dst), "_mm_shuffle_ps"); + + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[0] = dst[2]; dst[1] = src2[2]; dst[2] = dst[3]; dst[3] = src2[3]; } ENDSCALAR(checksum_dst(dst), "scalar unpackhi_ps"); + BINARYOP_TEST("_mm_unpackhi_ps", _mm_unpackhi_ps, _mm_load_ps(src), _mm_load_ps(src2)); + START(); dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; for(int i = 0; i < N; ++i) { dst[2] = dst[1]; dst[1] = dst[0]; dst[0] = src2[0]; dst[3] = src2[1]; } ENDSCALAR(checksum_dst(dst), "scalar unpacklo_ps"); + BINARYOP_TEST("_mm_unpacklo_ps", _mm_unpacklo_ps, _mm_load_ps(src), _mm_load_ps(src2)); + printf("]}\n"); +/* + printf("Finished!\n"); + printf("Total time spent in scalar intrinsics: %f msecs.\n", (double)scalarTotalTicks * 1000.0 / ticks_per_sec()); + printf("Total time spent in SSE1 intrinsics: %f msecs.\n", (double)simdTotalTicks * 1000.0 / ticks_per_sec()); + if (scalarTotalTicks > simdTotalTicks) + printf("SSE1 was %.3fx faster than scalar!\n", (double)scalarTotalTicks / simdTotalTicks); + else + printf("SSE1 was %.3fx slower than scalar!\n", (double)simdTotalTicks / scalarTotalTicks); +*/ +#ifdef __EMSCRIPTEN__ + fprintf(stderr,"User Agent: %s\n", emscripten_run_script_string("navigator.userAgent")); + printf("/*Test finished! Now please close Firefox to continue with benchmark_sse1.py.*/\n"); +#endif + exit(0); +} diff --git a/tests/benchmark_sse1.py b/tests/benchmark_sse1.py new file mode 100755 index 0000000000000..fca0ddfeb6111 --- /dev/null +++ b/tests/benchmark_sse1.py @@ -0,0 +1,292 @@ +import subprocess, tempfile, os, sys, shutil, json +from subprocess import Popen, PIPE, STDOUT + +__rootpath__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +def path_from_root(*pathelems): + return os.path.join(__rootpath__, *pathelems) +sys.path += [path_from_root('')] +import tools.shared +from tools.shared import * + +temp_dir = tempfile.mkdtemp() + +# System info +system_info = Popen([path_from_root('emrun'), '--system_info'], stdout=PIPE, stderr=PIPE).communicate() + +# Native info +native_info = Popen(['clang', '-v'], stdout=PIPE, stderr=PIPE).communicate() + +# Emscripten info +emscripten_info = Popen([EMCC, '-v'], stdout=PIPE, stderr=PIPE).communicate() + +# Run native build +out_file = os.path.join(temp_dir, 'benchmark_sse1_native') +cmd = [CLANG_CPP] + get_clang_native_args() + [path_from_root('tests', 'benchmark_sse1.cpp'), '-O3', '-o', out_file] +print 'Building native version of the benchmark:' +print ' '.join(cmd) +build = Popen(cmd) +out = build.communicate() +if build.returncode != 0: + sys.exit(1) + +native_results = Popen([out_file], stdout=PIPE, stderr=PIPE).communicate() +print native_results[0] + +# Run emscripten build +out_file = os.path.join(temp_dir, 'benchmark_sse1_html.html') +cmd = [EMCC, path_from_root('tests', 'benchmark_sse1.cpp'), '-O3', '--emrun', '-s', 'TOTAL_MEMORY=536870912', '-o', out_file] +print 'Building Emscripten version of the benchmark:' +print ' '.join(cmd) +build = Popen(cmd) +out = build.communicate() +if build.returncode != 0: + sys.exit(1) + +# The output file will have a 'almost asm' annotation, since SIMD is not yet in Nightly, so it won't even attempt to validate. +# Replace with 'use asm' to get a hint of validation errors, if those exist. +out_js_file = out_file.replace('.html', '.js') +js = open(out_js_file, 'r').read() +if 'almost asm' in js: + print 'Replacing "almost asm" with "use asm" in generated output to attempt asm.js and detect errors with asm.js validation.' + open(out_js_file, 'w').write(js.replace('almost asm', 'use asm')) + +# Enforce asm.js validation for the output file so that we can capture any validation errors. +asmjs_validation_status = Popen([PYTHON, path_from_root('tools', 'validate_asmjs.py'), out_file], stdout=PIPE, stderr=PIPE).communicate() +asmjs_validation_status = (asmjs_validation_status[0].strip() + '\n' + asmjs_validation_status[1].strip()).strip() +if 'is not valid asm.js' in asmjs_validation_status: + print >> sys.stderr, asmjs_validation_status + asmjs_validation_status = '' + asmjs_validation_status + '' + +browser = 'firefox_nightly' +if len(sys.argv) > 1 and sys.argv[1].startswith('--browser='): + browser = sys.argv[1][len('--browser='):].strip() + +# We require running in FF Nightly, since no other browsers support SIMD yet. +print 'Now launching Firefox to run the browser benchmark. For this to work properly, ensure the following:' +print ' - Firefox Nightly is installed.' +print ' - No version of Firefox was running beforehand (autostart conflicts with Firefox profile mechanism).' +print ' - The slow script dialog in Firefox is disabled.' +print ' - Make sure that all Firefox debugging, profiling etc. add-ons that might impact performance are disabled (Firebug, Geckoprofiler, ...).' +print '' +print 'Once the test has finished, close the browser application to continue.' +html_results = Popen([path_from_root('emrun'), '--browser=' + browser, out_file], stdout=PIPE, stderr=PIPE).communicate() + +if not html_results or not html_results[0].strip(): + print 'Running Firefox Nightly failed! Please rerun with the command line parameter --browser=/path/to/firefox/nightly/firefox' + sys.exit(1) + +def strip_comments(text): + return re.sub('//.*?\n|/\*.*?\*/', '', text, re.S) +benchmark_results = strip_comments(html_results[0]) + +##html_results = native_results +print benchmark_results + +browser_info = html_results[1] +browser_info = '
'.join([line for line in browser_info.strip().split('\n') if line.startswith('User Agent')]) + +shutil.rmtree(temp_dir) + +native_results = json.loads(native_results[0]) +html_results = json.loads(benchmark_results) + +native_workload = native_results['workload'] +html_workload = html_results['workload'] + +html = '''

SSE1 JavaScript Benchmark

+ + +System Info:
+''' + system_info[0].replace('\n', '
') + ''' +Native Clang Compiler:
+''' + native_info[1].replace('\n', '
') + ''' +Emscripten Compiler:
+''' + emscripten_info[0].replace('\n', '
') + ''' +Browser Information:
+''' + browser_info + '''
+Benchmark Build Log:
+''' + asmjs_validation_status.replace('\n', '
') + +charts_native = {} +charts_html = {} +for result in native_results['results']: + ch = result['chart'] + if not ch in charts_native: charts_native[ch] = [] + charts_native[ch] += [result] +for result in html_results['results']: + ch = result['chart'] + if not ch in charts_html: charts_html[ch] = [] + charts_html[ch] += [result] + +def find_result_in_category(results, category): + for result in results: + if result['category'] == category: + return result + return None + +def format_comparison(a, b): + if a <= b: return " {:10.2f}".format(b/a) + 'x FASTER' + else: return " {:10.2f}".format(a/b) + 'x SLOWER' + +chartNumber = 0 + +total_time_native_scalar = 0 +total_time_native_simd = 0 +total_time_html_scalar = 0 +total_time_html_simd = 0 + +for chart_name in charts_native.keys(): + # Extract data for each chart. + categories = [] + nativeScalarResults = [] + nativeSimdResults = [] + htmlScalarResults = [] + htmlSimdResults = [] + native_results = charts_native[chart_name] + html_results = charts_html[chart_name] + textual_results_native = '

' + textual_results_html = '

' + textual_results_html2 = '

' + textual_results_html3 = '

' + for result in native_results: + categories += ["'" + result['category'] + "'"] + nsc = result['scalar'] + nsi = result['simd'] + nativeScalarResults += [str(nsc)] + nativeSimdResults += [str(nsi)] + html_result = find_result_in_category(html_results, result['category']) + textual_results_native += 'Native ' + result['category'] + ': ' + "{:10.4f}".format(nsc) + 'ns -> ' + "{:10.4f}".format(nsi) + 'ns. ' + textual_results_native += 'Native SSE1 is ' + format_comparison(nsi, nsc) + ' than native scalar.        
' + + if html_result is not None: + hsc = html_result['scalar'] + htmlScalarResults += [str(hsc)] + hsi = html_result['simd'] + htmlSimdResults += [str(hsi)] + textual_results_html += 'JS ' + result['category'] + ': ' + "{:10.4f}".format(hsc) + 'ns -> ' + "{:10.4f}".format(hsi) + 'ns. ' + textual_results_html += 'JS SSE1 is ' + format_comparison(hsi, hsc) + ' than JS scalar.        
' + textual_results_html2 += 'JS ' + result['category'] + ': JS scalar is ' + format_comparison(hsc, nsc) + ' than native scalar.        
' + textual_results_html3 += 'JS ' + result['category'] + ': JS SSE1 is ' + format_comparison(hsi, nsi) + ' than native SSE1.        
' + total_time_native_scalar += nsc + total_time_native_simd += nsi + total_time_html_scalar += hsc + total_time_html_simd += hsi + else: + htmlScalarResults += [str(-1)] + htmlSimdResults += [str(-1)] + + chartNumber += 1 + html += '

' + html += '''''' + '
' + textual_results_native + '' + textual_results_html + '
' + textual_results_html2 + '' + textual_results_html3 + '
' + +# Final overall score + +html += '
' +html += '''''' + +html += '' + +open('results_sse1.html', 'w').write(html) +print 'Wrote ' + str(len(html)) + ' bytes to file results_sse1.html.' \ No newline at end of file diff --git a/tests/core/test_ccall.in b/tests/core/test_ccall.in index 0aefdc9d36795..c0ad0b07afc3d 100644 --- a/tests/core/test_ccall.in +++ b/tests/core/test_ccall.in @@ -1,5 +1,6 @@ #include #include +#include extern "C" { int get_int() { return 5; } @@ -17,6 +18,25 @@ int *pointer(int *in) { static int ret = 21; return &ret; } + +// This test checks that ccall restores the stack correctly to whatever it was +// when ccall was entered. We save the stack pointer on the heap in stackChecker +// and verify that ccall restores it correctly. +struct test_struct { + int arg1, arg2, arg3; +}; +static int* stackChecker = 0; +int get_stack() { int i; return (int)&i; } +int uses_stack(test_struct* t1) { + if (stackChecker == 0) stackChecker = (int*)malloc(sizeof(int)); + *stackChecker = get_stack(); + EM_ASM(Module.ccall('get_int', 'number')); + printf("stack is %s.\n", *stackChecker == get_stack() ? "ok" : "messed up"); +} +void call_ccall_again() { + test_struct t1 = { 1, 2, 3 }; + uses_stack(&t1); +} } int main(int argc, char **argv) { return 0; } diff --git a/tests/core/test_ccall.out b/tests/core/test_ccall.out index b4cddc5e4695f..85b5162b065df 100644 --- a/tests/core/test_ccall.out +++ b/tests/core/test_ccall.out @@ -22,3 +22,4 @@ bret 53 * stack is ok. +stack is ok. diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 32b5f9a069551..1b29c5ad79755 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -582,6 +582,7 @@ module({ }); test("can get global", function(){ + /*jshint evil:true*/ assert.equal((new Function("return this;"))(), cm.embind_test_getglobal()); }); @@ -916,6 +917,29 @@ module({ str.delete(); vec.delete(); }); + + test("resize appends the default value", function() { + var vec = cm.emval_test_return_vector(); + + vec.resize(5); + assert.equal(5, vec.size()); + assert.equal(10, vec.get(0)); + assert.equal(20, vec.get(1)); + assert.equal(30, vec.get(2)); + assert.equal(0, vec.get(3)); + assert.equal(0, vec.get(4)); + vec.delete(); + }); + + test("resize preserves content when shrinking", function() { + var vec = cm.emval_test_return_vector(); + + vec.resize(2); + assert.equal(2, vec.size()); + assert.equal(10, vec.get(0)); + assert.equal(20, vec.get(1)); + vec.delete(); + }); }); BaseFixture.extend("map", function() { diff --git a/tests/fuzz/22.c b/tests/fuzz/22.c new file mode 100644 index 0000000000000..f2de2acd5a144 --- /dev/null +++ b/tests/fuzz/22.c @@ -0,0 +1,1414 @@ +/* + * This is a RANDOMLY GENERATED PROGRAM. + * + * Generator: csmith 2.2.0 + * Git version: bf42ffd + * Options: --no-volatiles --no-packed-struct + * Seed: 3292581068 + */ + +#include "csmith.h" + + +static long __undefined; + +/* --- Struct/Union Declarations --- */ +struct S0 { + signed f0 : 20; + int16_t f1; + int64_t f2; +}; + +struct S1 { + const unsigned f0 : 3; + unsigned f1 : 17; + unsigned f2 : 22; + const signed f3 : 10; + unsigned f4 : 7; + unsigned f5 : 9; + const unsigned f6 : 16; + unsigned f7 : 27; + unsigned f8 : 16; + signed f9 : 24; +}; + +struct S2 { + uint64_t f0; + uint16_t f1; + const int8_t f2; + int16_t f3; +}; + +union U3 { + int32_t f0; +}; + +union U4 { + const uint32_t f0; + const int32_t f1; + uint16_t f2; + uint64_t f3; +}; + +/* --- GLOBAL VARIABLES --- */ +static int64_t g_4 = 0L; +static uint32_t g_14[3][3][1] = {{{0x995F7626L},{0x1DB6084EL},{0x1DB6084EL}},{{0x995F7626L},{0x1DB6084EL},{0x1DB6084EL}},{{0x995F7626L},{0x1DB6084EL},{0x1DB6084EL}}}; +static int32_t g_17[4] = {0L,0L,0L,0L}; +static int32_t g_18 = 0L; +static int16_t g_70 = 0x8841L; +static uint32_t g_79 = 0xD7B9758AL; +static uint16_t g_97 = 65530UL; +static uint32_t g_100 = 0x688ECCDFL; +static int32_t g_104 = (-7L); +static uint8_t g_106[4] = {6UL,6UL,6UL,6UL}; +static int16_t g_118 = 5L; +static int32_t *g_139 = (void*)0; +static struct S0 g_143 = {-107,0L,0xADF186003B377FB2LL}; +static uint8_t g_189 = 0x71L; +static uint16_t *g_192[8] = {&g_97,&g_97,&g_97,&g_97,&g_97,&g_97,&g_97,&g_97}; +static uint16_t **g_191 = &g_192[2]; +static union U4 g_213 = {0UL}; +static uint64_t g_226[6] = {0xBF4A9A9FA4E0B664LL,0xBF4A9A9FA4E0B664LL,0xBF4A9A9FA4E0B664LL,0xBF4A9A9FA4E0B664LL,0xBF4A9A9FA4E0B664LL,0xBF4A9A9FA4E0B664LL}; +static struct S1 g_231 = {0,261,214,-22,10,4,91,11103,7,388}; +static struct S1 *g_230 = &g_231; +static uint32_t *g_240 = &g_79; +static struct S2 g_249 = {1UL,6UL,-1L,0x6DA3L}; +static union U3 g_252[2] = {{0xE470BC13L},{0xE470BC13L}}; +static uint8_t g_287 = 0UL; +static const struct S1 g_313 = {0,91,447,16,5,12,16,6563,49,-3331}; +static uint32_t *g_328 = (void*)0; +static uint32_t g_334 = 4294967291UL; +static uint32_t g_339 = 9UL; +static uint32_t g_342 = 0x37EBF149L; +static uint8_t g_348 = 0xDCL; +static struct S0 *g_355 = &g_143; +static int8_t g_359 = 9L; +static int8_t *g_358 = &g_359; +static int8_t **g_357 = &g_358; +static uint32_t g_362 = 1UL; +static struct S2 g_385 = {3UL,0xF508L,-5L,-1L}; +static struct S0 **g_395 = &g_355; +static uint16_t g_440 = 0x05F0L; +static int32_t g_476 = 0xCB2DE0D5L; +static uint16_t g_510[3][7][1] = {{{0x9995L},{65535UL},{0x8E1CL},{65535UL},{0x9995L},{0x9995L},{65535UL}},{{0x8E1CL},{65535UL},{0x9995L},{0x9995L},{65535UL},{0x8E1CL},{0x8E1CL}},{{0x9EFBL},{0x9EFBL},{0x8E1CL},{0x9995L},{0x8E1CL},{0x9EFBL},{0x9EFBL}}}; +static int8_t g_538 = 0xB5L; +static uint32_t g_569 = 0x853264C2L; +static const union U4 g_584 = {0x81BAA2C6L}; +static const union U4 g_586 = {1UL}; +static const union U4 g_588 = {1UL}; +static const union U4 *g_587 = &g_588; +static struct S0 **g_601 = (void*)0; +static uint32_t g_629[9] = {4294967288UL,4294967288UL,4294967288UL,4294967288UL,4294967288UL,4294967288UL,4294967288UL,4294967288UL,4294967288UL}; +static uint64_t g_677 = 0xA56A85F7A4C266FELL; +static uint8_t g_689 = 0x4CL; +static int64_t *g_714 = &g_143.f2; +static int64_t ** const g_713 = &g_714; +static uint32_t g_723 = 0xFDDCCDB7L; +static uint64_t g_733 = 0xDDDD0A3B7E3FDE6DLL; +static struct S0 g_736 = {1003,0L,0xC0205A6612F15792LL}; +static uint8_t g_846[3] = {255UL,255UL,255UL}; +static int64_t **g_851 = &g_714; +static int64_t ***g_850[2] = {&g_851,&g_851}; +static int64_t ****g_849[7][10][3] = {{{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]},{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]},{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]},{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]}},{{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]},{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]},{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]},{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]}},{{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]},{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]},{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]},{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]}},{{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]},{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]},{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]},{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]}},{{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]},{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]},{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]},{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[1],&g_850[1],&g_850[1]},{&g_850[0],&g_850[0],&g_850[1]}},{{(void*)0,&g_850[0],&g_850[1]},{&g_850[0],&g_850[0],&g_850[0]},{(void*)0,&g_850[1],(void*)0},{&g_850[0],&g_850[0],&g_850[1]},{&g_850[1],&g_850[0],(void*)0},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[1],(void*)0,(void*)0},{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],&g_850[0],(void*)0},{&g_850[0],(void*)0,&g_850[0]}},{{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],&g_850[0],&g_850[0]},{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],(void*)0,(void*)0},{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],&g_850[0],(void*)0},{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],(void*)0,&g_850[0]},{&g_850[0],(void*)0,&g_850[0]}}}; +static int32_t **g_860 = (void*)0; +static const uint32_t g_861 = 4294967295UL; +static struct S2 g_900 = {0x8A4EAC62C1A3DC8BLL,1UL,-7L,-10L}; +static struct S2 *g_899 = &g_900; +static int8_t ***g_937 = &g_357; + + +/* --- FORWARD DECLARATIONS --- */ +static struct S2 func_1(void); +static int8_t func_11(uint32_t p_12); +static int32_t func_24(int64_t p_25, struct S0 p_26); +static uint8_t func_30(uint8_t p_31, uint32_t * p_32, uint8_t p_33, int16_t p_34, uint32_t p_35); +static uint32_t * func_36(const uint16_t p_37, uint32_t * p_38, int64_t p_39, uint32_t * p_40); +static uint16_t func_41(uint32_t * p_42, struct S2 p_43, uint8_t p_44); +static uint32_t * func_45(union U4 p_46, int32_t p_47, uint32_t * p_48, uint32_t * p_49); +static union U4 func_50(union U4 p_51, const uint32_t * p_52, uint32_t * const p_53); +static union U4 func_54(uint64_t p_55, uint32_t * p_56, uint32_t * p_57, struct S1 p_58, uint32_t * p_59); +static uint64_t func_60(uint32_t p_61, uint32_t p_62, uint32_t * p_63, const uint32_t * p_64); + + +/* --- FUNCTIONS --- */ +/* ------------------------------------------ */ +/* + * reads : g_4 g_14 g_70 g_97 g_100 g_104 g_106 g_118 g_143 g_189 g_191 g_213 g_226 g_230 g_213.f1 g_240 g_231.f9 g_79 g_249 g_252 g_231.f3 g_231.f1 g_252.f0 g_231 g_287 g_192 g_313.f2 g_334 g_348 g_357 g_362 g_313.f9 g_313.f5 g_385 g_313.f7 g_358 g_359 g_395 g_440 g_476 g_313.f3 g_510 g_355 g_538 g_569 g_587 g_588 g_629 g_677 g_689 g_713 g_584.f2 g_733 g_736 g_584.f0 g_714 g_586.f1 g_17 g_846 g_849 g_861 g_851 g_18 g_588.f1 g_213.f2 g_900.f1 g_339 g_313.f0 g_899 + * writes: g_14 g_17 g_18 g_70 g_79 g_97 g_104 g_106 g_118 g_139 g_143 g_189 g_226 g_230 g_252.f0 g_287 g_249.f0 g_328 g_334 g_339 g_249.f1 g_348 g_355 g_357 g_362 g_359 g_440 g_249.f3 g_385.f1 g_510 g_358 g_100 g_191 g_569 g_587 g_395 g_601 g_538 g_629 g_677 g_689 g_476 g_733 g_385.f3 g_231.f9 g_736.f1 g_846 g_860 g_736.f0 g_899 g_900.f1 g_4 g_937 + */ +static struct S2 func_1(void) +{ /* block id: 0 */ + uint32_t *l_13[10][8] = {{&g_14[1][0][0],&g_14[1][0][0],&g_14[0][0][0],&g_14[0][1][0],&g_14[2][0][0],(void*)0,&g_14[1][1][0],&g_14[0][2][0]},{(void*)0,&g_14[1][1][0],&g_14[2][0][0],&g_14[1][0][0],&g_14[2][0][0],&g_14[1][1][0],(void*)0,&g_14[0][2][0]},{&g_14[1][1][0],(void*)0,&g_14[2][0][0],&g_14[0][1][0],&g_14[0][0][0],&g_14[1][0][0],&g_14[1][0][0],&g_14[0][0][0]},{&g_14[2][0][0],(void*)0,(void*)0,&g_14[2][0][0],&g_14[0][0][0],(void*)0,&g_14[0][2][0],&g_14[1][0][0]},{&g_14[1][1][0],&g_14[2][0][0],&g_14[2][0][0],&g_14[0][0][0],&g_14[2][0][0],&g_14[0][0][0],&g_14[2][0][0],&g_14[2][0][0]},{(void*)0,&g_14[2][0][0],&g_14[1][0][0],&g_14[2][0][0],&g_14[2][0][0],(void*)0,&g_14[0][1][0],&g_14[0][1][0]},{&g_14[1][0][0],(void*)0,(void*)0,(void*)0,(void*)0,&g_14[1][0][0],&g_14[0][1][0],&g_14[2][0][0]},{&g_14[0][2][0],(void*)0,&g_14[1][0][0],(void*)0,&g_14[2][0][0],&g_14[1][1][0],&g_14[2][0][0],(void*)0},{&g_14[2][0][0],&g_14[1][1][0],&g_14[2][0][0],(void*)0,&g_14[1][0][0],(void*)0,&g_14[0][2][0],&g_14[2][0][0]},{&g_14[0][1][0],&g_14[1][0][0],(void*)0,(void*)0,(void*)0,(void*)0,&g_14[1][0][0],&g_14[0][1][0]}}; + int32_t l_27 = 0xB249E3C8L; + int32_t l_67 = 1L; + int16_t *l_68 = (void*)0; + int16_t *l_69 = &g_70; + uint32_t *l_281 = (void*)0; + uint32_t *l_282 = (void*)0; + uint32_t *l_722 = &g_723; + uint16_t *l_739[7][4] = {{&g_510[2][6][0],&g_510[2][3][0],&g_510[2][6][0],&g_385.f1},{&g_510[2][6][0],&g_385.f1,&g_385.f1,&g_510[2][6][0]},{(void*)0,&g_385.f1,(void*)0,&g_385.f1},{&g_385.f1,&g_510[2][3][0],(void*)0,(void*)0},{(void*)0,(void*)0,&g_385.f1,(void*)0},{&g_510[2][6][0],&g_510[2][3][0],&g_510[2][6][0],&g_385.f1},{&g_510[2][6][0],&g_385.f1,&g_385.f1,&g_510[2][6][0]}}; + int32_t l_740 = (-10L); + uint16_t l_742[2][3][6] = {{{0x1C7BL,1UL,65535UL,4UL,0x5752L,0x5752L},{1UL,1UL,1UL,1UL,1UL,0x4532L},{1UL,1UL,0x4532L,4UL,1UL,0x4532L}},{{0x1C7BL,0x5752L,1UL,0xBE84L,1UL,0x5752L},{4UL,1UL,65535UL,0xBE84L,1UL,1UL},{0x1C7BL,1UL,65535UL,4UL,0x5752L,0x5752L}}}; + int32_t l_743 = 0xA46F1ACDL; + union U4 l_748 = {0x2A606DD9L}; + struct S0 l_754 = {70,1L,0x53104FB7AEDA01D3LL}; + int64_t l_755 = 0x443FD9F6A3090B09LL; + struct S1 **l_763 = &g_230; + int16_t l_785 = (-6L); + int64_t **l_800 = &g_714; + int64_t ***l_799 = &l_800; + int32_t l_833 = (-5L); + int16_t l_834 = 0x1352L; + int8_t l_862 = 0xFFL; + struct S2 l_905[6][4][4] = {{{{18446744073709551615UL,0x95F5L,0L,-9L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{18446744073709551615UL,0x95F5L,0L,-9L},{4UL,0xE32DL,0x45L,1L}},{{1UL,1UL,-1L,-5L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{1UL,65535UL,1L,0xF9ADL}},{{18446744073709551615UL,0x95F5L,0L,-9L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L}},{{4UL,0xE32DL,0x45L,1L},{4UL,0xE32DL,0x45L,1L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{7UL,1UL,0xEEL,0xAD1FL}}},{{{18446744073709551615UL,0x95F5L,0L,-9L},{1UL,1UL,-1L,-5L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L}},{{7UL,6UL,0xCDL,7L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{7UL,1UL,0xEEL,0xAD1FL},{0x3C43812E7A0B84F8LL,0UL,6L,3L}},{{7UL,1UL,0xEEL,0xAD1FL},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{7UL,6UL,0xCDL,7L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L}},{{0x3C43812E7A0B84F8LL,0UL,6L,3L},{1UL,1UL,-1L,-5L},{18446744073709551615UL,0x95F5L,0L,-9L},{7UL,1UL,0xEEL,0xAD1FL}}},{{{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{4UL,0xE32DL,0x45L,1L},{4UL,0xE32DL,0x45L,1L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L}},{{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L},{18446744073709551615UL,0x95F5L,0L,-9L},{1UL,65535UL,1L,0xF9ADL}},{{0x3C43812E7A0B84F8LL,0UL,6L,3L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{7UL,6UL,0xCDL,7L},{18446744073709551615UL,65530UL,0x71L,1L}},{{7UL,1UL,0xEEL,0xAD1FL},{0x3820DA7291C36553LL,0xD74AL,0x03L,0x5415L},{7UL,1UL,0xEEL,0xAD1FL},{18446744073709551615UL,65530UL,0x71L,1L}}},{{{7UL,6UL,0xCDL,7L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{1UL,65535UL,1L,0xF9ADL}},{{18446744073709551615UL,0x95F5L,0L,-9L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L}},{{4UL,0xE32DL,0x45L,1L},{4UL,0xE32DL,0x45L,1L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{7UL,1UL,0xEEL,0xAD1FL}},{{18446744073709551615UL,0x95F5L,0L,-9L},{1UL,1UL,-1L,-5L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L}}},{{{7UL,6UL,0xCDL,7L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{7UL,1UL,0xEEL,0xAD1FL},{0x3C43812E7A0B84F8LL,0UL,6L,3L}},{{7UL,1UL,0xEEL,0xAD1FL},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{7UL,6UL,0xCDL,7L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L}},{{0x3C43812E7A0B84F8LL,0UL,6L,3L},{1UL,1UL,-1L,-5L},{18446744073709551615UL,0x95F5L,0L,-9L},{7UL,1UL,0xEEL,0xAD1FL}},{{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{4UL,0xE32DL,0x45L,1L},{4UL,0xE32DL,0x45L,1L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L}}},{{{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x5F51C307223DF4B7LL,0x9903L,0xFBL,-1L},{18446744073709551615UL,0x95F5L,0L,-9L},{1UL,65535UL,1L,0xF9ADL}},{{0x3C43812E7A0B84F8LL,0UL,6L,3L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{7UL,6UL,0xCDL,7L},{18446744073709551615UL,65530UL,0x71L,1L}},{{7UL,1UL,0xEEL,0xAD1FL},{0x3820DA7291C36553LL,0xD74AL,0x03L,0x5415L},{7UL,1UL,0xEEL,0xAD1FL},{18446744073709551615UL,65530UL,0x71L,1L}},{{7UL,6UL,0xCDL,7L},{0x4C7CCD567DF114D3LL,0x55D0L,0xC8L,0L},{0x3C43812E7A0B84F8LL,0UL,6L,3L},{1UL,65535UL,1L,0xF9ADL}}}}; + union U3 *l_910 = &g_252[1]; + uint32_t l_925[10] = {18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL,18446744073709551606UL}; + uint64_t l_939 = 18446744073709551607UL; + int i, j, k; + if ((safe_sub_func_int64_t_s_s((g_4 && 0L), ((+(safe_mul_func_int8_t_s_s((!(g_4 >= ((((safe_add_func_uint8_t_u_u(((((safe_mul_func_int8_t_s_s(func_11((g_14[2][0][0]--)), (safe_rshift_func_int16_t_s_u((safe_rshift_func_uint16_t_u_s((l_27 = (func_24((l_27 , (safe_lshift_func_uint8_t_u_s(func_30(g_4, func_36(func_41(func_45(func_50(func_54(func_60((l_27 && l_27), ((((*l_69) |= (l_67 = ((safe_div_func_int32_t_s_s(l_67, l_27)) , g_4))) <= l_27) <= 1UL), l_13[8][1], l_13[1][5]), &g_100, l_281, g_231, l_282), &g_100, &g_100), g_313.f9, &g_100, l_13[2][5]), g_385, g_313.f7), l_722, l_27, &g_723), g_231.f9, l_27, g_584.f2), g_4))), g_736) == g_385.f3)), 10)), l_740)))) > g_584.f0) , l_740) <= g_385.f0), 9UL)) || 0x4EL) | l_740) || l_740))), l_740))) >= 0x25DEL)))) + { /* block id: 377 */ + int32_t *l_741[6] = {&l_740,&l_740,&l_740,&l_740,&l_740,&l_740}; + uint32_t l_744 = 4294967292UL; + uint8_t *l_749 = &g_287; + int32_t **l_756 = (void*)0; + int32_t **l_757 = &l_741[5]; + int i; + g_18 = 1L; + l_27 = l_742[0][1][3]; + --l_744; + (*l_757) = func_36((((*g_714) = (((**g_191) && 0L) > (safe_unary_minus_func_uint64_t_u(0x619AF56C3EC8FF28LL)))) ^ 0xB3A25009DC52BB1CLL), func_45(l_748, l_748.f0, func_36((((*l_749) = 8UL) < (g_106[3] & ((safe_sub_func_int16_t_s_s((l_754 , 9L), l_755)) >= (-4L)))), l_741[2], l_748.f2, &g_100), l_13[0][0]), l_742[0][1][3], l_741[0]); + } + else + { /* block id: 384 */ + int32_t l_786 = (-8L); + struct S0 ***l_787 = &g_601; + uint32_t l_788 = 9UL; + int64_t ****l_801[7][7] = {{(void*)0,&l_799,&l_799,&l_799,&l_799,&l_799,&l_799},{&l_799,&l_799,(void*)0,&l_799,&l_799,&l_799,&l_799},{(void*)0,&l_799,&l_799,&l_799,&l_799,&l_799,&l_799},{&l_799,&l_799,(void*)0,(void*)0,&l_799,&l_799,(void*)0},{(void*)0,&l_799,(void*)0,(void*)0,&l_799,(void*)0,&l_799},{&l_799,(void*)0,&l_799,&l_799,&l_799,&l_799,&l_799},{(void*)0,(void*)0,(void*)0,&l_799,&l_799,&l_799,(void*)0}}; + uint8_t *l_802 = &g_287; + uint64_t *l_803[6]; + int32_t *l_804 = (void*)0; + int8_t l_896[3][4]; + int8_t l_897 = 0xE3L; + int i, j; + for (i = 0; i < 6; i++) + l_803[i] = &g_733; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 4; j++) + l_896[i][j] = 0x4CL; + } + for (g_100 = 12; (g_100 >= 60); ++g_100) + { /* block id: 387 */ + struct S1 **l_765 = &g_230; + struct S1 ***l_764 = &l_765; + int32_t *l_766 = (void*)0; + int32_t *l_767 = (void*)0; + int32_t *l_768 = &l_743; + int16_t *l_781[9][2][3] = {{{&l_754.f1,&l_754.f1,&g_736.f1},{&l_754.f1,&l_754.f1,&l_754.f1}},{{&l_754.f1,&l_754.f1,&g_736.f1},{&l_754.f1,&l_754.f1,&l_754.f1}},{{&l_754.f1,&l_754.f1,&g_736.f1},{&l_754.f1,&l_754.f1,&l_754.f1}},{{&l_754.f1,&l_754.f1,&g_736.f1},{&l_754.f1,&l_754.f1,&l_754.f1}},{{&l_754.f1,&l_754.f1,&g_736.f1},{&l_754.f1,&l_754.f1,&l_754.f1}},{{&l_754.f1,&l_754.f1,&g_736.f1},{&l_754.f1,&l_754.f1,&l_754.f1}},{{(void*)0,(void*)0,&l_754.f1},{(void*)0,(void*)0,&l_754.f1}},{{(void*)0,(void*)0,&l_754.f1},{(void*)0,(void*)0,&l_754.f1}},{{(void*)0,(void*)0,&l_754.f1},{(void*)0,(void*)0,&l_754.f1}}}; + uint8_t *l_784[1]; + int i, j, k; + for (i = 0; i < 1; i++) + l_784[i] = &g_106[0]; + (*l_768) = (l_67 = ((safe_unary_minus_func_uint16_t_u(0x2E4AL)) != (safe_rshift_func_int8_t_s_s(((g_586.f1 , l_763) != ((*l_764) = (void*)0)), (*g_358))))); + (*l_768) = (l_748.f1 < (safe_lshift_func_int8_t_s_u((*g_358), (safe_lshift_func_int16_t_s_s((g_385.f3 = ((*g_240) ^ (safe_mul_func_int16_t_s_s((((safe_sub_func_uint32_t_u_u((safe_sub_func_int8_t_s_s((safe_mod_func_int32_t_s_s((l_781[5][0][1] == (void*)0), (*g_240))), (l_785 |= (safe_lshift_func_uint8_t_u_s((g_348 = 0x38L), 1))))), (g_17[2] <= (((-6L) ^ l_786) >= (-8L))))) <= g_231.f0) & (**g_191)), 0x809FL)))), g_226[4]))))); + } + g_231.f9 = (((**g_357) = 1L) > (0xFF492E51L > ((&g_601 == l_787) , l_788))); + g_231.f9 = (safe_rshift_func_uint16_t_u_s((((void*)0 == &g_231) || (0xFA9A0BDBL >= (((*g_714) = (*g_714)) == (g_733 = (safe_lshift_func_int8_t_s_s(((safe_add_func_uint8_t_u_u(((*l_802) = (safe_mod_func_int16_t_s_s(((**g_191) || (safe_div_func_int16_t_s_s((((l_799 = l_799) == &g_713) != ((void*)0 != &g_714)), g_17[3]))), l_788))), l_27)) == l_788), 1)))))), 11)); + if ((safe_mul_func_uint16_t_u_u(((*g_714) == l_748.f1), (safe_sub_func_int32_t_s_s((l_27 = (g_143.f1 == (safe_div_func_int16_t_s_s(0L, (0x5803C37EL ^ (&l_800 == (((safe_add_func_int8_t_s_s(l_742[0][1][3], (safe_mul_func_int16_t_s_s(((*l_69) = (l_748.f0 < (l_27 , 0xF663L))), 0x4C7BL)))) , l_754.f0) , &l_800))))))), (*g_240)))))) + { /* block id: 405 */ + uint64_t l_835 = 18446744073709551609UL; + struct S0 l_836[2][9][8] = {{{{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{47,0L,1L},{358,0xA520L,1L},{47,0L,1L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{1018,0x36C1L,-10L},{-573,-2L,1L},{826,0xFE8CL,1L}},{{-257,0xFE19L,-1L},{47,0L,1L},{315,0xAC0FL,1L},{-168,0xD38EL,-1L},{-18,0x900AL,4L},{880,0x4CC7L,0L},{-704,0x03C6L,3L},{47,0L,1L}},{{-573,-2L,1L},{196,0x9051L,8L},{315,0xAC0FL,1L},{826,0xFE8CL,1L},{315,0xAC0FL,1L},{196,0x9051L,8L},{-573,-2L,1L},{880,0x4CC7L,0L}},{{-18,0x900AL,4L},{263,0x6C58L,0x771AEFE267022595LL},{358,0xA520L,1L},{826,0xFE8CL,1L},{-573,-2L,1L},{1018,0x36C1L,-10L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{47,0L,1L}},{{-257,0xFE19L,-1L},{826,0xFE8CL,1L},{-704,0x03C6L,3L},{-168,0xD38EL,-1L},{-573,-2L,1L},{-168,0xD38EL,-1L},{-704,0x03C6L,3L},{826,0xFE8CL,1L}},{{-18,0x900AL,4L},{196,0x9051L,8L},{-257,0xFE19L,-1L},{47,0L,1L},{315,0xAC0FL,1L},{-168,0xD38EL,-1L},{-18,0x900AL,4L},{880,0x4CC7L,0L}},{{-573,-2L,1L},{826,0xFE8CL,1L},{358,0xA520L,1L},{263,0x6C58L,0x771AEFE267022595LL},{-18,0x900AL,4L},{1018,0x36C1L,-10L},{-18,0x900AL,4L},{263,0x6C58L,0x771AEFE267022595LL}},{{-257,0xFE19L,-1L},{263,0x6C58L,0x771AEFE267022595LL},{-257,0xFE19L,-1L},{-168,0xD38EL,-1L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{196,0x9051L,8L},{-704,0x03C6L,3L},{263,0x6C58L,0x771AEFE267022595LL}},{{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{196,0x9051L,8L},{-704,0x03C6L,3L},{263,0x6C58L,0x771AEFE267022595LL},{315,0xAC0FL,1L},{880,0x4CC7L,0L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{880,0x4CC7L,0L}}},{{{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{47,0L,1L},{358,0xA520L,1L},{47,0L,1L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{1018,0x36C1L,-10L},{-573,-2L,1L},{826,0xFE8CL,1L}},{{-257,0xFE19L,-1L},{47,0L,1L},{315,0xAC0FL,1L},{-168,0xD38EL,-1L},{-18,0x900AL,4L},{880,0x4CC7L,0L},{-704,0x03C6L,3L},{47,0L,1L}},{{-573,-2L,1L},{196,0x9051L,8L},{315,0xAC0FL,1L},{826,0xFE8CL,1L},{315,0xAC0FL,1L},{196,0x9051L,8L},{-573,-2L,1L},{880,0x4CC7L,0L}},{{-18,0x900AL,4L},{263,0x6C58L,0x771AEFE267022595LL},{358,0xA520L,1L},{826,0xFE8CL,1L},{-573,-2L,1L},{1018,0x36C1L,-10L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{47,0L,1L}},{{-257,0xFE19L,-1L},{826,0xFE8CL,1L},{-704,0x03C6L,3L},{-168,0xD38EL,-1L},{-573,-2L,1L},{-168,0xD38EL,-1L},{-704,0x03C6L,3L},{826,0xFE8CL,1L}},{{-18,0x900AL,4L},{196,0x9051L,8L},{-257,0xFE19L,-1L},{47,0L,1L},{315,0xAC0FL,1L},{-168,0xD38EL,-1L},{-18,0x900AL,4L},{880,0x4CC7L,0L}},{{-573,-2L,1L},{826,0xFE8CL,1L},{358,0xA520L,1L},{263,0x6C58L,0x771AEFE267022595LL},{-18,0x900AL,4L},{1018,0x36C1L,-10L},{-18,0x900AL,4L},{263,0x6C58L,0x771AEFE267022595LL}},{{-257,0xFE19L,-1L},{263,0x6C58L,0x771AEFE267022595LL},{-257,0xFE19L,-1L},{-168,0xD38EL,-1L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{196,0x9051L,8L},{-704,0x03C6L,3L},{263,0x6C58L,0x771AEFE267022595LL}},{{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{196,0x9051L,8L},{-704,0x03C6L,3L},{263,0x6C58L,0x771AEFE267022595LL},{315,0xAC0FL,1L},{880,0x4CC7L,0L},{-647,0xD1BAL,0xC68CE0D9FB59B8C8LL},{880,0x4CC7L,0L}}}}; + uint8_t *l_852 = (void*)0; + uint8_t *l_853 = &g_689; + int32_t *l_856[10] = {(void*)0,&l_67,(void*)0,&l_67,(void*)0,&l_67,(void*)0,&l_67,(void*)0,&l_67}; + int i, j, k; + if ((safe_add_func_int64_t_s_s((safe_sub_func_uint8_t_u_u(((safe_sub_func_uint64_t_u_u(((safe_div_func_uint8_t_u_u(((*l_802)++), (*g_358))) <= ((safe_mod_func_int32_t_s_s((safe_sub_func_uint64_t_u_u(l_785, ((g_736.f1 |= (((safe_lshift_func_int16_t_s_s((~((*l_69) = g_118)), g_249.f3)) >= (((~(safe_rshift_func_int16_t_s_s(g_510[1][1][0], g_231.f6))) <= (*g_240)) <= (&g_18 != (g_252[1].f0 , &l_740)))) != 0x2F73L)) >= (**g_191)))), 4294967295UL)) <= l_833)), l_834)) <= l_833), l_27)), l_835))) + { /* block id: 409 */ + struct S0 *l_837 = (void*)0; + struct S0 *l_838 = &l_754; + (*l_838) = l_836[0][4][1]; + } + else + { /* block id: 411 */ + uint16_t *l_841 = &g_213.f2; + int32_t l_845[2]; + int i; + for (i = 0; i < 2; i++) + l_845[i] = 0xEC2C8207L; + for (g_677 = 0; (g_677 <= 18); g_677++) + { /* block id: 414 */ + int32_t l_843[1][1][3]; + int i, j, k; + for (i = 0; i < 1; i++) + { + for (j = 0; j < 1; j++) + { + for (k = 0; k < 3; k++) + l_843[i][j][k] = (-4L); + } + } + if ((l_841 == (*g_191))) + { /* block id: 415 */ + struct S2 l_842 = {18446744073709551615UL,1UL,-1L,-10L}; + g_17[3] = (-6L); + return l_842; + } + else + { /* block id: 418 */ + int32_t *l_844[1][5][2]; + int i, j, k; + for (i = 0; i < 1; i++) + { + for (j = 0; j < 5; j++) + { + for (k = 0; k < 2; k++) + l_844[i][j][k] = &l_786; + } + } + if (l_843[0][0][1]) + break; + g_846[2]++; + } + } + } + g_231.f9 = (((*l_802) = (g_849[5][0][2] == l_801[6][4])) >= ((*l_853)++)); + } + else + { /* block id: 427 */ + int32_t **l_859[4][10] = {{&g_139,&l_804,(void*)0,&l_804,&g_139,&g_139,&l_804,(void*)0,&l_804,&g_139},{&g_139,&l_804,(void*)0,&l_804,&g_139,&g_139,&l_804,(void*)0,&g_139,&l_804},{&l_804,&g_139,&g_139,&g_139,&l_804,&l_804,&g_139,&g_139,&g_139,&l_804},{&l_804,&g_139,&g_139,&g_139,&l_804,&l_804,&g_139,&g_139,&g_139,&l_804}}; + uint32_t *l_871 = &g_14[2][0][0]; + int64_t l_875 = 0x22A8FCA16C589F14LL; + int32_t ***l_898 = &g_860; + int i, j; + if ((((((**g_191) | g_17[3]) < (254UL || ((*g_358) = (((((0xFA674883L && (((safe_mul_func_int16_t_s_s(((&g_139 == (g_860 = l_859[3][8])) ^ ((void*)0 != &g_118)), g_861)) < g_629[3]) && (**g_851))) != 1UL) < (-1L)) , l_862) || l_742[1][2][0])))) , (*g_230)) , g_18)) + { /* block id: 430 */ + for (l_834 = 0; (l_834 <= 5); l_834 += 1) + { /* block id: 433 */ + g_139 = &l_67; + return g_249; + } + } + else + { /* block id: 437 */ + int16_t l_867[7][7][5] = {{{(-1L),9L,0xB9F3L,1L,0L},{0xB37BL,0x1298L,0xF840L,0x7937L,0xEC83L},{5L,0L,0xD549L,0x7937L,0xB37BL},{0xEC83L,0L,1L,1L,0L},{0L,0x40C8L,0xEC83L,0xB37BL,(-1L)},{0x3FCCL,0xD8B2L,0x5CEDL,0x137AL,0x4D4DL},{0x4001L,0L,0xB9F3L,0x4001L,0x137AL}},{{0x3FCCL,1L,(-1L),0x8EFFL,0x7F1AL},{0L,0x3FCCL,1L,9L,0x4D4DL},{0xEC83L,9L,0x7F1AL,(-1L),(-9L)},{5L,(-10L),0x7F1AL,0x917AL,0xB9F3L},{0xB37BL,0x137AL,1L,0x137AL,0xB37BL},{(-1L),0x7937L,(-1L),0xF840L,9L},{0x8EFFL,0xEC83L,0xB9F3L,0L,1L}},{{0xB37BL,0x3FCCL,0x5CEDL,0x7937L,9L},{0xE20CL,0L,0xEC83L,(-10L),0xB37BL},{9L,0xB9F3L,1L,0L,0xB9F3L},{0L,0xD8B2L,0xD549L,0xB37BL,(-9L)},{0x1298L,0xD8B2L,0xF840L,0x7F1AL,0x4D4DL},{0x917AL,0xB9F3L,0xB9F3L,0x917AL,0x7F1AL},{0x3FCCL,0L,4L,0x8EFFL,0x137AL}},{{0xB9F3L,0x3FCCL,0x80DDL,0xEC83L,0x4D4DL},{9L,0xEC83L,0x7F1AL,0x8EFFL,(-1L)},{5L,0x7937L,0xF6B3L,0x917AL,0L},{0xF840L,0x137AL,0x80DDL,0x7F1AL,0xB37BL},{0x8EFFL,(-10L),(-1L),0xB37BL,0xEC83L},{0x8EFFL,9L,0x8689L,0L,0L},{0xF840L,0x3FCCL,0xF840L,(-10L),9L}},{{5L,1L,0xEC83L,0x7937L,0xF840L},{9L,0L,(-1L),0L,0L},{0xB9F3L,0xD8B2L,0xEC83L,0xF840L,(-9L)},{0x3FCCL,0x40C8L,0xF840L,0x137AL,0x80DDL},{0x917AL,0L,0x8689L,0x917AL,0x137AL},{0x1298L,0L,(-1L),(-1L),0x1298L},{0x4001L,3L,(-1L),0x7F1AL,(-1L)}},{{0x7F1AL,0x7F1AL,0x3FCCL,(-10L),0x80DDL},{0x5CEDL,0x40C8L,0x1988L,0xD549L,0x4001L},{1L,0x1988L,(-1L),0x1298L,(-1L)},{(-10L),0x40C8L,0x4D4DL,1L,0x7F1AL},{(-1L),0x7F1AL,0x9324L,0x8689L,0xB9F3L},{1L,3L,(-1L),0x40C8L,0xF6B3L},{0xF840L,0xB9F3L,0x137AL,0x40C8L,1L}},{{0xF6B3L,0x4001L,0x8689L,0x8689L,0x4001L},{0x4001L,4L,0xF6B3L,1L,1L},{(-1L),(-1L),0L,0x1298L,0xE20CL},{0xD549L,0x4001L,0x9324L,0xD549L,0x1298L},{(-1L),0x8689L,1L,(-10L),0x1988L},{0x4001L,(-1L),5L,0x7F1AL,0xE20CL},{0xF6B3L,0x7F1AL,0x1988L,(-1L),0x80DDL}}}; + uint32_t *l_868 = &l_788; + uint32_t **l_872 = &l_13[8][1]; + union U3 *l_874 = &g_252[1]; + union U3 **l_873 = &l_874; + int i, j, k; + l_804 = ((safe_mul_func_uint32_t_u_u((--(*g_240)), (l_867[6][2][3] != 5L))) , func_36(((g_736.f0 = (l_67 = (l_868 != (void*)0))) <= (l_786 ^= (1L & (+(g_252[1] , (l_27 = 0x3EB7C111L)))))), ((*l_872) = func_36((safe_rshift_func_int16_t_s_u(l_867[6][2][3], 10)), l_868, (**g_713), l_871)), (*g_714), &g_100)); + (*l_873) = &g_252[0]; + g_17[1] ^= ((g_385 , (l_875 >= 0x37E0L)) , (safe_mul_func_int8_t_s_s(((safe_add_func_uint8_t_u_u(((*l_804) < (!((*l_69) ^= (safe_mul_func_int16_t_s_s((safe_lshift_func_uint16_t_u_s((safe_mul_func_uint16_t_u_u((safe_mul_func_uint8_t_u_u(((*l_802) = (0xB2D3B5621D3D8219LL & (safe_rshift_func_uint16_t_u_s(((g_249.f0 == (safe_sub_func_int64_t_s_s(l_27, ((((0UL != (((safe_div_func_uint64_t_u_u(((safe_div_func_int8_t_s_s(((**g_713) > g_588.f1), (**g_357))) || 7L), (*l_804))) , l_867[5][1][2]) & 0x19L)) != (*l_804)) == l_896[2][3]) < 0x1ED4L)))) <= g_79), g_588.f1)))), 0x77L)), l_897)), 0)), g_213.f2))))), l_867[6][2][3])) != 0L), g_231.f8))); + } + (*l_898) = &g_139; + } + } + g_899 = &g_385; + for (g_900.f1 = 0; (g_900.f1 <= 0); g_900.f1 += 1) + { /* block id: 456 */ + struct S0 l_901 = {-802,0xA0CEL,0x39CD8AD3F99BFAECLL}; + struct S1 *l_902 = &g_231; + const struct S1 *l_904 = &g_313; + const struct S1 **l_903 = &l_904; + const int32_t *l_907 = &l_740; + int32_t l_933 = 0xD839B7A6L; + int8_t ***l_936 = &g_357; + union U4 *l_938 = &g_213; + l_754 = l_901; + g_17[2] = (l_901.f0 = (l_902 != ((*l_903) = &g_313))); + for (g_733 = 0; (g_733 <= 3); g_733 += 1) + { /* block id: 463 */ + return l_905[2][3][1]; + } + for (g_104 = 0; (g_104 <= 3); g_104 += 1) + { /* block id: 468 */ + int32_t **l_906[2][1]; + int i, j; + for (i = 0; i < 2; i++) + { + for (j = 0; j < 1; j++) + l_906[i][j] = &g_139; + } + l_907 = (void*)0; + for (g_339 = 0; (g_339 <= 0); g_339 += 1) + { /* block id: 472 */ + union U3 *l_909[2][1]; + union U3 **l_908[10][5][4] = {{{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]},{&l_909[1][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]}},{{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[1][0],&l_909[1][0],&l_909[1][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[0][0],&l_909[1][0]},{&l_909[0][0],&l_909[1][0],&l_909[1][0],&l_909[0][0]}}}; + int i, j, k; + for (i = 0; i < 2; i++) + { + for (j = 0; j < 1; j++) + l_909[i][j] = (void*)0; + } + g_17[(g_339 + 1)] = g_17[(g_339 + 1)]; + l_910 = &g_252[(g_900.f1 + 1)]; + g_736.f0 = (safe_rshift_func_int8_t_s_s((safe_div_func_int8_t_s_s((safe_add_func_int64_t_s_s(g_17[g_104], (safe_div_func_int32_t_s_s((-6L), (safe_mod_func_uint8_t_u_u(((((g_510[(g_900.f1 + 1)][g_104][g_900.f1] != (l_901 , (g_231.f4 >= g_584.f2))) == (safe_mod_func_int8_t_s_s((safe_rshift_func_int8_t_s_u(l_925[1], 4)), (safe_add_func_uint16_t_u_u((safe_unary_minus_func_int32_t_s((0xE47DL | (((safe_add_func_uint32_t_u_u((safe_mul_func_uint16_t_u_u(l_748.f2, 0x3BEFL)), (*g_240))) || 2L) | 0x35L)))), g_313.f0))))) == (**g_191)) > 0xA9D54447L), (**g_357))))))), 1UL)), 7)); + for (g_4 = 0; (g_4 >= 0); g_4 -= 1) + { /* block id: 478 */ + return (*g_899); + } + } + g_18 = l_933; + l_939 ^= (((g_937 = l_936) != &g_357) == (l_938 != &g_213)); + for (l_748.f2 = 0; (l_748.f2 <= 0); l_748.f2 += 1) + { /* block id: 487 */ + uint32_t l_940 = 5UL; + struct S2 l_943 = {18446744073709551615UL,5UL,0xD0L,1L}; + l_940--; + return l_943; + } + } + } + return l_905[2][3][1]; +} + + +/* ------------------------------------------ */ +/* + * reads : + * writes: g_17 g_18 g_14 + */ +static int8_t func_11(uint32_t p_12) +{ /* block id: 2 */ + uint16_t l_19 = 0UL; + for (p_12 = 0; p_12 < 3; p_12 += 1) + { + for (g_17[3] = 0; g_17[3] < 3; g_17[3] += 1) + { + for (g_18 = 0; g_18 < 1; g_18 += 1) + { + g_14[p_12][g_17[3]][g_18] = 7UL; + } + } + } + return l_19; +} + + +/* ------------------------------------------ */ +/* + * reads : + * writes: + */ +static int32_t func_24(int64_t p_25, struct S0 p_26) +{ /* block id: 373 */ + int32_t *l_737[2][1]; + uint32_t l_738 = 0x6A2B6200L; + int i, j; + for (i = 0; i < 2; i++) + { + for (j = 0; j < 1; j++) + l_737[i][j] = &g_104; + } + p_26.f0 = (-1L); + return l_738; +} + + +/* ------------------------------------------ */ +/* + * reads : g_733 g_70 + * writes: g_733 + */ +static uint8_t func_30(uint8_t p_31, uint32_t * p_32, uint8_t p_33, int16_t p_34, uint32_t p_35) +{ /* block id: 370 */ + int32_t *l_727 = &g_104; + int32_t *l_728 = (void*)0; + int32_t *l_729 = &g_104; + int32_t *l_730 = &g_252[1].f0; + int32_t *l_731 = &g_104; + int32_t *l_732[10][4] = {{&g_104,&g_104,&g_104,&g_104},{&g_252[1].f0,&g_252[1].f0,&g_104,&g_104},{&g_252[1].f0,&g_104,&g_104,&g_104},{&g_104,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0},{&g_104,&g_104,&g_104,&g_104},{&g_252[1].f0,&g_252[1].f0,&g_104,&g_104},{&g_252[1].f0,&g_252[1].f0,&g_104,&g_104},{&g_104,&g_252[1].f0,&g_104,&g_104},{&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_104},{&g_104,&g_104,&g_252[1].f0,&g_252[1].f0}}; + int i, j; + ++g_733; + return g_70; +} + + +/* ------------------------------------------ */ +/* + * reads : g_476 + * writes: g_476 g_104 + */ +static uint32_t * func_36(const uint16_t p_37, uint32_t * p_38, int64_t p_39, uint32_t * p_40) +{ /* block id: 363 */ + for (g_476 = 0; (g_476 != 12); g_476 = safe_add_func_uint32_t_u_u(g_476, 2)) + { /* block id: 366 */ + int32_t *l_726 = &g_104; + (*l_726) = 0L; + } + return p_38; +} + + +/* ------------------------------------------ */ +/* + * reads : g_357 g_358 g_359 g_231.f7 g_395 g_287 g_440 g_191 g_192 g_97 g_226 g_249.f1 g_348 g_476 g_104 g_249.f3 g_385.f1 g_143 g_70 g_240 g_79 g_313.f3 g_510 g_355 g_313.f7 g_213 g_538 g_230 g_231 g_106 g_252.f0 g_569 g_587 g_588 g_4 g_629 g_189 g_677 g_689 g_713 + * writes: g_359 g_440 g_104 g_97 g_226 g_348 g_287 g_249.f3 g_252.f0 g_385.f1 g_510 g_358 g_143 g_355 g_100 g_191 g_569 g_587 g_395 g_601 g_538 g_139 g_629 g_79 g_249.f0 g_118 g_677 g_689 g_189 + */ +static uint16_t func_41(uint32_t * p_42, struct S2 p_43, uint8_t p_44) +{ /* block id: 192 */ + struct S0 **l_394 = &g_355; + int32_t l_400[9] = {0xE664F176L,8L,8L,0xE664F176L,8L,8L,0xE664F176L,8L,8L}; + uint64_t l_401 = 0xF75E01E494C05B71LL; + struct S0 l_402 = {379,0x0EC4L,0x76A19489864157ECLL}; + int8_t l_417 = 0xE4L; + uint32_t l_475 = 0x1F58EE16L; + uint32_t l_503 = 0x0D9DC638L; + const int16_t *l_545 = (void*)0; + struct S1 **l_681[2][9][1] = {{{(void*)0},{(void*)0},{&g_230},{&g_230},{&g_230},{&g_230},{&g_230},{(void*)0},{(void*)0}},{{&g_230},{&g_230},{&g_230},{&g_230},{&g_230},{(void*)0},{(void*)0},{&g_230},{&g_230}}}; + union U3 l_710 = {0x55F6C32AL}; + int64_t *l_712 = &l_402.f2; + int64_t **l_711[10][6] = {{&l_712,&l_712,(void*)0,&l_712,&l_712,&l_712},{&l_712,&l_712,&l_712,&l_712,&l_712,&l_712},{&l_712,&l_712,&l_712,&l_712,&l_712,&l_712},{&l_712,&l_712,&l_712,(void*)0,(void*)0,&l_712},{&l_712,&l_712,(void*)0,&l_712,(void*)0,&l_712},{&l_712,&l_712,&l_712,&l_712,(void*)0,(void*)0},{&l_712,&l_712,&l_712,&l_712,(void*)0,&l_712},{&l_712,&l_712,&l_712,&l_712,&l_712,(void*)0},{&l_712,&l_712,(void*)0,(void*)0,&l_712,&l_712},{&l_712,&l_712,(void*)0,&l_712,(void*)0,&l_712}}; + uint32_t l_715 = 6UL; + int i, j, k; + if ((((safe_mod_func_uint64_t_u_u((safe_add_func_uint8_t_u_u(255UL, ((~(((-1L) <= ((safe_add_func_uint8_t_u_u((safe_lshift_func_int8_t_s_u((**g_357), g_231.f7)), ((l_394 != g_395) & (((((((void*)0 == &g_358) , (safe_sub_func_int8_t_s_s(((safe_lshift_func_uint8_t_u_u(l_400[4], l_401)) & 6UL), p_43.f2))) < 0UL) & p_44) < p_44) > g_287)))) > l_401)) == p_43.f1)) , 0x5CL))), p_43.f0)) < 0x844BE889EB94F8DALL) , p_43.f3)) + { /* block id: 193 */ + struct S0 *l_403 = &g_143; + int32_t l_408 = (-1L); + int32_t l_415 = 1L; + int32_t l_418 = 0x947E9364L; + int32_t l_419[4] = {1L,1L,1L,1L}; + int64_t *l_428 = &g_143.f2; + int64_t **l_427[7] = {&l_428,&l_428,&l_428,&l_428,&l_428,&l_428,&l_428}; + uint32_t l_495[3]; + uint32_t l_504 = 1UL; + union U4 *l_553 = &g_213; + int8_t *l_560 = (void*)0; + uint32_t l_625 = 0x04DB0F64L; + int32_t *l_626 = (void*)0; + int32_t *l_627 = &g_104; + int32_t *l_628[3][4][5] = {{{&l_415,&l_415,&l_415,&l_415,&l_415},{&g_104,(void*)0,&g_104,(void*)0,&g_104},{&l_415,&l_415,&l_415,&l_415,&l_415},{&g_104,(void*)0,&g_104,(void*)0,&g_104}},{{&l_415,&l_415,&l_415,&l_415,&l_415},{&g_104,(void*)0,&g_104,(void*)0,&g_104},{&l_415,&l_415,&l_415,&l_415,&l_415},{&g_104,(void*)0,&g_104,(void*)0,&g_104}},{{&l_415,&l_415,&l_415,&l_415,&l_415},{&g_104,(void*)0,&g_104,(void*)0,&g_104},{&l_415,&l_415,&l_415,&l_415,&l_415},{&g_104,(void*)0,&g_104,(void*)0,&g_104}}}; + int i, j, k; + for (i = 0; i < 3; i++) + l_495[i] = 0xC1FCB659L; + if (((l_402 , l_403) == l_403)) + { /* block id: 194 */ + uint64_t l_409 = 0x4052EEA0C97CF48BLL; + struct S0 **l_412 = &g_355; + int32_t l_413 = 0x7F0D242CL; + int32_t l_414 = 7L; + int32_t l_416 = 0xDD450A13L; + int32_t l_420 = 0xB8098866L; + uint32_t l_421 = 9UL; + int64_t ***l_429 = &l_427[2]; + for (g_359 = 8; (g_359 >= 0); g_359 -= 1) + { /* block id: 197 */ + int32_t *l_404 = (void*)0; + int32_t *l_405 = &l_400[7]; + int32_t *l_406 = &l_400[4]; + int32_t *l_407[3][3][6] = {{{&l_400[1],&l_400[6],&l_400[4],&g_252[1].f0,&l_400[4],&l_400[6]},{(void*)0,&l_400[1],&l_400[4],(void*)0,&g_252[1].f0,&g_252[1].f0},{&l_400[g_359],(void*)0,&l_400[6],&l_400[6],(void*)0,&l_400[g_359]}},{{&l_400[6],(void*)0,&l_400[g_359],&g_104,&g_252[1].f0,&l_400[4]},{&l_400[4],&l_400[1],(void*)0,&l_400[1],&l_400[4],(void*)0},{&l_400[4],&l_400[6],&l_400[1],&g_104,&l_400[4],&l_400[4]}},{{&l_400[6],&g_252[1].f0,&g_252[1].f0,&l_400[6],(void*)0,&l_400[4]},{&l_400[g_359],&l_400[4],&l_400[1],(void*)0,&g_104,(void*)0},{(void*)0,&g_252[1].f0,(void*)0,&g_252[1].f0,&g_104,&l_400[4]}}}; + int i, j, k; + l_409++; + l_412 = l_394; + l_421++; + for (l_408 = 3; (l_408 <= 8); l_408 += 1) + { /* block id: 203 */ + uint16_t l_424[1]; + int i; + for (i = 0; i < 1; i++) + l_424[i] = 0xB06AL; + l_424[0]++; + } + } + (*l_429) = l_427[2]; + } + else + { /* block id: 208 */ + uint16_t l_453[1][9][10] = {{{1UL,0xD58DL,2UL,0x86CEL,0x0662L,1UL,0x3961L,1UL,0x88DAL,0x5A9AL},{0xEE43L,0x5863L,0x4E59L,1UL,1UL,65529UL,0x6881L,0x6881L,65529UL,1UL},{65529UL,1UL,1UL,65529UL,0xD58DL,0x471BL,0x4299L,0x86CEL,0UL,0UL},{0x5863L,0x249FL,65529UL,0x0662L,1UL,65533UL,1UL,0x4299L,0UL,65529UL},{65529UL,1UL,0UL,65529UL,0UL,0x3961L,0x6881L,0x5863L,0x6881L,0x3961L},{65535UL,0x5A9AL,0UL,0x5A9AL,65535UL,0x85C1L,1UL,0x3961L,0x86CEL,0x471BL},{0x88DAL,8UL,2UL,1UL,1UL,0UL,0UL,0x86CEL,0x4299L,0x471BL},{0UL,1UL,0x6881L,0xD58DL,65535UL,0x249FL,0x3961L,2UL,2UL,0x3961L},{1UL,0UL,1UL,1UL,0UL,1UL,0x85C1L,0UL,0UL,65529UL}}}; + int32_t l_460 = (-1L); + int8_t *l_482[1]; + int32_t l_508 = 0x3A6073A7L; + int32_t l_509 = 0xB077D1D3L; + struct S1 l_543 = {0,351,736,11,1,5,139,11262,32,-1324}; + int16_t *l_546 = &g_118; + union U4 *l_554 = (void*)0; + int i, j, k; + for (i = 0; i < 1; i++) + l_482[i] = &g_359; +lbl_466: + for (g_359 = 26; (g_359 == 28); g_359 = safe_add_func_uint64_t_u_u(g_359, 6)) + { /* block id: 211 */ + uint16_t l_432 = 0x339CL; + int32_t *l_433 = &g_104; + int32_t *l_434 = &l_400[6]; + int32_t *l_435 = &l_418; + int32_t *l_436 = &l_419[1]; + int32_t *l_437 = &l_400[0]; + int32_t *l_438[1]; + int32_t l_439 = 0L; + uint64_t *l_456 = (void*)0; + uint64_t *l_457 = &g_226[4]; + uint16_t *l_458 = (void*)0; + uint16_t *l_459[3][7][6] = {{{&g_440,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440},{&g_440,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_385.f1,&l_453[0][1][3]},{&g_385.f1,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_440,&g_440},{&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440,&l_453[0][1][3]},{&g_440,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440},{&g_440,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_385.f1,&l_453[0][1][3]},{&g_385.f1,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_440,&g_440}},{{&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440,&l_453[0][1][3]},{&g_440,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440},{&g_440,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_385.f1,&l_453[0][1][3]},{&g_385.f1,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_440,&g_440},{&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440,&l_453[0][1][3]},{&g_440,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440},{&g_440,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_385.f1,&l_453[0][1][3]}},{{&g_385.f1,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_440,&g_440},{&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440,&l_453[0][1][3]},{&g_440,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440},{&g_440,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_385.f1,&l_453[0][1][3]},{&g_385.f1,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_440,&g_440},{&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440,&l_453[0][1][3]},{&g_440,&g_385.f1,&l_453[0][1][3],&l_453[0][1][3],&g_385.f1,&g_440}}}; + int i, j, k; + for (i = 0; i < 1; i++) + l_438[i] = &l_419[0]; + l_432 |= 0xA38C4A00L; + g_440++; + (*l_433) = 0x07817498L; + l_460 ^= ((((~(safe_rshift_func_uint16_t_u_u((l_408 = (((p_43.f2 , (++(**g_191))) & p_43.f2) >= 1L)), 11))) == (p_44 < (((safe_add_func_uint64_t_u_u(((p_43.f1 = (((safe_add_func_uint64_t_u_u(p_43.f0, ((safe_sub_func_int32_t_s_s(l_453[0][1][3], 0x5648E4A5L)) < (safe_div_func_uint64_t_u_u(((*l_457) ^= p_43.f0), (l_402.f0 , 0x087EAC859CBEDF93LL)))))) , (*l_437)) != p_43.f0)) , g_249.f1), l_419[0])) <= 0x8A1056ECL) == 9UL))) ^ 0L) != 65532UL); + } + for (g_348 = (-9); (g_348 == 50); g_348++) + { /* block id: 223 */ + int32_t *l_463[1]; + int32_t l_487 = 0x4A774B48L; + int i; + for (i = 0; i < 1; i++) + l_463[i] = (void*)0; + l_408 &= (l_419[0] = 1L); + for (g_287 = 0; (g_287 >= 44); g_287 = safe_add_func_uint8_t_u_u(g_287, 9)) + { /* block id: 228 */ + uint16_t l_479 = 0UL; + int16_t *l_485 = (void*)0; + int16_t *l_486 = &g_249.f3; + int32_t l_488 = (-1L); + if (p_43.f2) + goto lbl_466; + l_400[2] |= (l_488 = (safe_mod_func_int64_t_s_s((((0x78A555A7ADC6A9D2LL < (((safe_rshift_func_int16_t_s_s(((*l_486) &= ((safe_mul_func_uint16_t_u_u((255UL || 0xAAL), (((safe_div_func_uint8_t_u_u(l_475, g_476)) ^ (((safe_div_func_uint32_t_u_u(l_479, p_43.f0)) || (safe_mod_func_int16_t_s_s((l_482[0] != ((((safe_rshift_func_int8_t_s_s(l_479, 7)) ^ 4294967295UL) || l_453[0][7][7]) , (void*)0)), 65535UL))) | (*g_358))) ^ 0xF3EEA663L))) != g_104)), l_487)) , p_44) < g_476)) , &g_355) != (void*)0), 0x800DAFAC68343BF5LL))); + g_252[1].f0 = p_44; + } + if (p_43.f3) + break; + } + l_460 = p_43.f1; + for (g_385.f1 = (-12); (g_385.f1 > 30); ++g_385.f1) + { /* block id: 240 */ + uint64_t *l_502 = &g_226[1]; + int8_t *l_524 = &g_359; + int8_t *l_525[8] = {&l_417,&l_417,&g_359,&l_417,&l_417,&g_359,&l_417,&l_417}; + int32_t l_533[4] = {0x88058637L,0x88058637L,0x88058637L,0x88058637L}; + union U4 *l_555 = &g_213; + struct S0 l_562 = {-527,2L,0x0448252815FAD88CLL}; + int i; + if ((((*g_358) = (**g_357)) == (safe_rshift_func_int16_t_s_u(((*l_403) , (!(((0x87FC26D02DDA595BLL || (p_44 > (safe_mod_func_uint32_t_u_u(l_495[0], (p_43.f1 || ((safe_sub_func_int64_t_s_s(((((safe_add_func_uint64_t_u_u(g_249.f3, (((*l_502) = ((safe_mod_func_uint64_t_u_u((l_502 != (void*)0), 0xA8AA536D568DCC7CLL)) == l_415)) , g_70))) > (-3L)) || l_503) ^ l_504), 0x8DE215AC19E941E3LL)) ^ (*g_240))))))) & g_313.f3) ^ l_419[2]))), l_408)))) + { /* block id: 243 */ + return l_408; + } + else + { /* block id: 245 */ + int32_t *l_505 = &l_408; + int32_t *l_506 = &g_252[1].f0; + int32_t *l_507[10][8] = {{&l_419[3],&l_400[7],&l_418,&l_400[7],&l_419[3],&l_408,&l_418,&l_408},{&l_400[4],&l_419[3],&l_419[3],&l_400[4],&l_400[4],&l_408,&l_400[4],&l_400[4]},{&l_419[3],&l_400[4],&l_419[3],&l_418,&g_104,&g_104,&l_418,&l_419[3]},{&l_400[4],&l_400[4],&g_104,&l_408,&l_400[7],&l_408,&g_104,&l_400[4]},{&l_400[4],&l_419[3],&l_418,&g_104,&g_104,&l_418,&l_419[3],&l_400[4]},{&l_419[3],&l_400[4],&l_400[4],&l_408,&l_400[4],&l_400[4],&l_419[3],&l_419[3]},{&l_400[4],&l_408,&l_418,&l_418,&l_408,&l_400[4],&g_104,&l_400[4]},{&l_408,&l_400[4],&g_104,&l_400[4],&l_408,&l_418,&l_418,&l_408},{&l_400[4],&l_419[3],&l_419[3],&l_400[4],&l_400[4],&l_408,&l_400[4],&l_400[4]},{&l_419[3],&l_400[4],&l_419[3],&l_418,&g_104,&g_104,&l_418,&l_419[3]}}; + int i, j; + g_510[1][1][0]++; + } + for (l_509 = 0; (l_509 < 4); l_509++) + { /* block id: 250 */ + uint8_t l_517 = 1UL; + struct S0 l_528 = {-72,-1L,1L}; + if ((safe_mul_func_uint8_t_u_u(l_517, ((0x99CD742BL || (safe_div_func_int64_t_s_s((l_460 , (safe_mod_func_int8_t_s_s((p_43.f3 | p_44), (((((safe_add_func_uint16_t_u_u(((((((l_524 = &l_417) == l_525[5]) && l_509) >= (safe_add_func_int32_t_s_s(((((*g_357) = (*g_357)) != l_525[1]) ^ p_43.f3), l_508))) | 1L) < 0xE8CF95BAF425CAEBLL), p_43.f0)) ^ 0xB4019FC1L) >= 0L) > 0x2A44L) && 0xFB40FC71L)))), 0x7C2B82F8239DCB01LL))) & g_231.f7)))) + { /* block id: 253 */ + (*l_403) = l_528; + } + else + { /* block id: 255 */ + (*g_395) = (*g_395); + } + } + if ((((!p_44) > g_313.f7) ^ ((safe_mul_func_uint8_t_u_u((g_213 , l_508), (((*g_357) != (void*)0) <= (**g_191)))) >= l_402.f1))) + { /* block id: 259 */ + uint8_t *l_534 = &g_348; + int32_t l_537 = 0L; + int32_t l_544 = 0x3FD6788AL; + int32_t *l_547 = &g_252[1].f0; + int32_t *l_548 = &l_544; + (*l_548) = ((l_509 || 0x6F48L) > (((*l_547) ^= ((((((safe_add_func_uint8_t_u_u(((*l_534) = l_533[1]), (((((*p_42) = (((((safe_add_func_int64_t_s_s((l_537 = g_70), (p_43 , ((!((!g_538) || ((g_313.f3 < (safe_rshift_func_uint16_t_u_s(((((safe_sub_func_uint32_t_u_u(((((*g_230) , l_543) , l_533[1]) > 0x1AD531985BAA7D61LL), l_402.f1)) , l_419[1]) ^ p_44) | l_544), 8))) <= l_544))) | g_106[3])))) , (void*)0) == &g_357) > l_453[0][8][4]) | p_43.f2)) , l_475) && 0xFEL) ^ p_43.f2))) != p_43.f3) , l_545) == l_546) == p_43.f1) < 0x3DL)) >= p_43.f3)); + } + else + { /* block id: 265 */ + uint16_t **l_556 = &g_192[2]; + uint16_t ***l_557 = &l_556; + struct S0 l_561[7][8][4] = {{{{-767,0x505CL,0xE539CD804A26505FLL},{494,-10L,1L},{-329,0L,0x1D82DBE0661AF3EDLL},{-879,9L,9L}},{{-113,1L,-1L},{-901,1L,0xA0C6AE4CC5774106LL},{-68,0L,8L},{291,0x5828L,-1L}},{{494,-10L,1L},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{241,0xF295L,-1L},{908,1L,0L}},{{-735,0L,-1L},{354,4L,0x7F173E63592C050FLL},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{65,0x34A8L,0xA08D63C8F50BC2FALL}},{{253,0x8132L,2L},{450,0xFBD5L,-1L},{151,-6L,8L},{-113,1L,-1L}},{{406,0x01C1L,0xBEC9472EF5B6FFD2LL},{176,-3L,0x24688744FB48E062LL},{-538,1L,0xA1E393B028FD97F9LL},{-1005,0x5704L,0x13A5DCCEEE633110LL}},{{-735,0L,-1L},{-113,1L,-1L},{-703,-3L,0x687A0620666B44E9LL},{-703,-3L,0x687A0620666B44E9LL}},{{736,3L,0xD1007AA9C7DCCA31LL},{736,3L,0xD1007AA9C7DCCA31LL},{-68,0L,8L},{-572,-5L,-1L}}},{{{439,0L,0L},{914,0xB57FL,0xD63F579506923D00LL},{-244,0x29C7L,-4L},{291,0x5828L,-1L}},{{-767,0x505CL,0xE539CD804A26505FLL},{253,0x8132L,2L},{-924,0L,0x99BB936DBD377F37LL},{-244,0x29C7L,-4L}},{{450,0xFBD5L,-1L},{253,0x8132L,2L},{216,-3L,0x2A7A50744A4F9BC4LL},{291,0x5828L,-1L}},{{253,0x8132L,2L},{914,0xB57FL,0xD63F579506923D00LL},{176,-3L,0x24688744FB48E062LL},{-572,-5L,-1L}},{{-538,1L,0xA1E393B028FD97F9LL},{736,3L,0xD1007AA9C7DCCA31LL},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{-703,-3L,0x687A0620666B44E9LL}},{{-901,1L,0xA0C6AE4CC5774106LL},{-113,1L,-1L},{-982,0x3DC5L,0x4EAA50EE89694E8BLL},{-1005,0x5704L,0x13A5DCCEEE633110LL}},{{-666,-1L,-9L},{176,-3L,0x24688744FB48E062LL},{-329,0L,0x1D82DBE0661AF3EDLL},{-113,1L,-1L}},{{-75,0x6D9DL,1L},{450,0xFBD5L,-1L},{-244,0x29C7L,-4L},{65,0x34A8L,0xA08D63C8F50BC2FALL}}},{{{736,3L,0xD1007AA9C7DCCA31LL},{354,4L,0x7F173E63592C050FLL},{-982,0x3DC5L,0x4EAA50EE89694E8BLL},{908,1L,0L}},{{291,0x5828L,-1L},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{-807,-1L,0xAAF149BAF866C8C4LL},{291,0x5828L,-1L}},{{-538,1L,0xA1E393B028FD97F9LL},{-901,1L,0xA0C6AE4CC5774106LL},{-767,0x505CL,0xE539CD804A26505FLL},{-879,9L,9L}},{{406,0x01C1L,0xBEC9472EF5B6FFD2LL},{494,-10L,1L},{216,-3L,0x2A7A50744A4F9BC4LL},{-457,0xCA08L,0x64F3D65C12292D66LL}},{{-901,1L,0xA0C6AE4CC5774106LL},{-918,1L,2L},{241,0xF295L,-1L},{-316,0L,0L}},{{-767,0x505CL,0xE539CD804A26505FLL},{736,3L,0xD1007AA9C7DCCA31LL},{-142,0x65DAL,0x5544DB41C7A80338LL},{-879,9L,9L}},{{-572,-5L,-1L},{450,0xFBD5L,-1L},{-68,0L,8L},{450,0xFBD5L,-1L}},{{-666,-1L,-9L},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{-924,0L,0x99BB936DBD377F37LL},{572,0L,0x475BC0DC96CDBC2ALL}}},{{{-735,0L,-1L},{406,0x01C1L,0xBEC9472EF5B6FFD2LL},{-807,-1L,0xAAF149BAF866C8C4LL},{65,0x34A8L,0xA08D63C8F50BC2FALL}},{{354,4L,0x7F173E63592C050FLL},{291,0x5828L,-1L},{151,-6L,8L},{-572,-5L,-1L}},{{354,4L,0x7F173E63592C050FLL},{176,-3L,0x24688744FB48E062LL},{-807,-1L,0xAAF149BAF866C8C4LL},{-457,0xCA08L,0x64F3D65C12292D66LL}},{{-735,0L,-1L},{-572,-5L,-1L},{-924,0L,0x99BB936DBD377F37LL},{-703,-3L,0x687A0620666B44E9LL}},{{-666,-1L,-9L},{494,-10L,1L},{-68,0L,8L},{439,0L,0L}},{{-572,-5L,-1L},{216,-3L,0x2A7A50744A4F9BC4LL},{151,-6L,8L},{-98,0x673FL,0x401ECBC08E6EC3A9LL}},{{632,-7L,-9L},{-75,0x6D9DL,1L},{-68,0L,8L},{-626,9L,0x8CD98FA9A83281B3LL}},{{-98,0x673FL,0x401ECBC08E6EC3A9LL},{-879,9L,9L},{439,0L,0L},{-807,-1L,0xAAF149BAF866C8C4LL}}},{{{-879,9L,9L},{216,-3L,0x2A7A50744A4F9BC4LL},{632,-7L,-9L},{-703,-3L,0x687A0620666B44E9LL}},{{-454,-10L,1L},{397,-1L,-6L},{-730,1L,0x654DBD5B03048AFCLL},{-9,0xEBA1L,1L}},{{-538,1L,0xA1E393B028FD97F9LL},{-924,0L,0x99BB936DBD377F37LL},{-763,0x2A42L,0x68D4158D25C6EDAELL},{-142,0x65DAL,0x5544DB41C7A80338LL}},{{982,7L,1L},{312,1L,2L},{-626,9L,0x8CD98FA9A83281B3LL},{-924,0L,0x99BB936DBD377F37LL}},{{805,1L,-4L},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{-708,0x9F2DL,0x66AA91EACD9F30CELL},{120,0x90F0L,0xAFB107D5356A8688LL}},{{397,-1L,-6L},{-918,1L,2L},{-763,0x2A42L,0x68D4158D25C6EDAELL},{-767,0x505CL,0xE539CD804A26505FLL}},{{-98,0x673FL,0x401ECBC08E6EC3A9LL},{775,0L,-1L},{775,0L,-1L},{-98,0x673FL,0x401ECBC08E6EC3A9LL}},{{-454,-10L,1L},{-538,1L,0xA1E393B028FD97F9LL},{312,1L,2L},{-848,1L,0L}}},{{{-918,1L,2L},{397,-1L,-6L},{439,0L,0L},{-244,0x29C7L,-4L}},{{-807,-1L,0xAAF149BAF866C8C4LL},{-982,0x3DC5L,0x4EAA50EE89694E8BLL},{131,-1L,0x90F2B9C834FB33DALL},{-244,0x29C7L,-4L}},{{632,-7L,-9L},{397,-1L,-6L},{-626,9L,0x8CD98FA9A83281B3LL},{-848,1L,0L}},{{-924,0L,0x99BB936DBD377F37LL},{-538,1L,0xA1E393B028FD97F9LL},{736,3L,0xD1007AA9C7DCCA31LL},{-98,0x673FL,0x401ECBC08E6EC3A9LL}},{{982,7L,1L},{775,0L,-1L},{-9,0xEBA1L,1L},{-767,0x505CL,0xE539CD804A26505FLL}},{{-448,4L,0x7F6DAF9F91D28E64LL},{-918,1L,2L},{-454,-10L,1L},{120,0x90F0L,0xAFB107D5356A8688LL}},{{-879,9L,9L},{-98,0x673FL,0x401ECBC08E6EC3A9LL},{907,0x3FFEL,0xDD4653E7B281FAA4LL},{-924,0L,0x99BB936DBD377F37LL}},{{-918,1L,2L},{312,1L,2L},{775,0L,-1L},{-142,0x65DAL,0x5544DB41C7A80338LL}}},{{{-448,4L,0x7F6DAF9F91D28E64LL},{-924,0L,0x99BB936DBD377F37LL},{-68,0L,8L},{-9,0xEBA1L,1L}},{{-497,0x0A01L,-1L},{397,-1L,-6L},{736,3L,0xD1007AA9C7DCCA31LL},{-703,-3L,0x687A0620666B44E9LL}},{{-703,-3L,0x687A0620666B44E9LL},{216,-3L,0x2A7A50744A4F9BC4LL},{-708,0x9F2DL,0x66AA91EACD9F30CELL},{-807,-1L,0xAAF149BAF866C8C4LL}},{{632,-7L,-9L},{-879,9L,9L},{-9,0xEBA1L,1L},{-626,9L,0x8CD98FA9A83281B3LL}},{{-538,1L,0xA1E393B028FD97F9LL},{-75,0x6D9DL,1L},{439,0L,0L},{-98,0x673FL,0x401ECBC08E6EC3A9LL}},{{-75,0x6D9DL,1L},{216,-3L,0x2A7A50744A4F9BC4LL},{343,0x6720L,0L},{-924,0L,0x99BB936DBD377F37LL}},{{-454,-10L,1L},{-497,0x0A01L,-1L},{-454,-10L,1L},{-9,0xEBA1L,1L}},{{-807,-1L,0xAAF149BAF866C8C4LL},{241,0xF295L,-1L},{-763,0x2A42L,0x68D4158D25C6EDAELL},{-329,0L,0x1D82DBE0661AF3EDLL}}}}; + int32_t l_565 = 5L; + int32_t l_566 = (-1L); + int32_t l_567 = (-1L); + int32_t l_568 = 0L; + const union U4 *l_585[8][6] = {{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586},{&g_586,&g_586,&g_586,&g_586,&g_586,&g_586}}; + struct S0 ***l_598 = &l_394; + struct S0 **l_600 = &l_403; + struct S0 ***l_599[5][10][5] = {{{&l_600,(void*)0,&l_600,&l_600,&l_600},{&l_600,&l_600,&l_600,&l_600,&l_600},{&l_600,&l_600,(void*)0,(void*)0,&l_600},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,&l_600},{&l_600,&l_600,(void*)0,(void*)0,&l_600},{&l_600,&l_600,(void*)0,&l_600,&l_600},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,(void*)0,&l_600}},{{(void*)0,(void*)0,&l_600,(void*)0,&l_600},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,&l_600},{(void*)0,(void*)0,&l_600,(void*)0,(void*)0},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,&l_600,&l_600},{(void*)0,&l_600,(void*)0,(void*)0,(void*)0},{&l_600,(void*)0,&l_600,&l_600,&l_600},{&l_600,&l_600,&l_600,&l_600,&l_600},{&l_600,(void*)0,&l_600,&l_600,(void*)0}},{{&l_600,(void*)0,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,&l_600,&l_600},{(void*)0,&l_600,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,(void*)0,&l_600},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,(void*)0,&l_600},{(void*)0,(void*)0,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,(void*)0}},{{(void*)0,&l_600,&l_600,(void*)0,&l_600},{(void*)0,(void*)0,&l_600,(void*)0,&l_600},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,&l_600},{(void*)0,(void*)0,&l_600,(void*)0,(void*)0},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,&l_600,&l_600},{(void*)0,&l_600,(void*)0,(void*)0,(void*)0},{&l_600,(void*)0,&l_600,&l_600,&l_600},{&l_600,&l_600,&l_600,&l_600,&l_600}},{{&l_600,(void*)0,&l_600,&l_600,(void*)0},{&l_600,(void*)0,&l_600,&l_600,(void*)0},{(void*)0,&l_600,&l_600,&l_600,&l_600},{(void*)0,&l_600,&l_600,&l_600,(void*)0},{&l_600,&l_600,&l_600,&l_600,(void*)0},{(void*)0,&l_600,(void*)0,&l_600,&l_600},{&l_600,&l_600,(void*)0,&l_600,&l_600},{&l_600,&l_600,&l_600,&l_600,&l_600},{&l_600,&l_600,&l_600,&l_600,(void*)0},{&l_600,&l_600,(void*)0,&l_600,&l_600}}}; + int i, j, k; + if ((((safe_lshift_func_uint16_t_u_s((+0UL), 8)) <= ((safe_mul_func_uint8_t_u_u(l_408, ((l_554 = l_553) != ((*g_230) , l_555)))) != ((g_191 = &g_192[2]) != ((*l_557) = l_556)))) , ((&g_230 == ((safe_sub_func_uint32_t_u_u((l_560 != (void*)0), p_43.f0)) , &g_230)) , p_43.f1))) + { /* block id: 269 */ + int32_t *l_563 = &l_419[0]; + int32_t *l_564[1][1][3]; + int i, j, k; + for (i = 0; i < 1; i++) + { + for (j = 0; j < 1; j++) + { + for (k = 0; k < 3; k++) + l_564[i][j][k] = (void*)0; + } + } + if (p_44) + break; + l_562 = (((&g_226[4] == &g_226[4]) , p_43.f1) , l_561[1][7][0]); + g_143 = l_562; + g_569++; + } + else + { /* block id: 274 */ + int32_t *l_572 = &l_567; + l_561[1][7][0].f0 |= ((*l_572) = l_504); + if (p_43.f1) + break; + (*l_572) = (safe_mod_func_int32_t_s_s(0xDFE086DCL, (safe_unary_minus_func_uint64_t_u(p_43.f1)))); + l_508 = (g_231.f6 <= l_566); + } + for (p_44 = 0; (p_44 <= 0); p_44 += 1) + { /* block id: 283 */ + union U4 **l_577[2]; + union U4 ***l_576 = &l_577[1]; + const union U4 *l_583[6][2][9] = {{{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584},{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,(void*)0,&g_584,&g_584}},{{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584},{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,(void*)0,&g_584,&g_584}},{{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584},{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,(void*)0,&g_584,&g_584}},{{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584},{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,(void*)0,&g_584,&g_584}},{{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584},{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,(void*)0,&g_584,&g_584}},{{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,&g_584},{&g_584,&g_584,&g_584,&g_584,&g_584,&g_584,(void*)0,&g_584,&g_584}}}; + const union U4 **l_582[5] = {&l_583[2][1][3],&l_583[2][1][3],&l_583[2][1][3],&l_583[2][1][3],&l_583[2][1][3]}; + int32_t *l_591 = &l_408; + uint8_t *l_594 = &g_348; + struct S0 l_597[10][7][3] = {{{{-577,3L,1L},{-35,9L,1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{182,0xE94BL,0x6581619EEEF64BCCLL},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{752,0x47DBL,-1L},{955,0x6A92L,-5L},{312,0x2DBAL,0x4E566E280CE23346LL}},{{-577,3L,1L},{182,0xE94BL,0x6581619EEEF64BCCLL},{-129,1L,0x9B1A6D681E34EDD5LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-970,-3L,0x4012CE8C83D07D00LL},{392,0x94C4L,-6L}},{{578,0x76F7L,0L},{-35,9L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}}},{{{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L},{955,0x6A92L,-5L}},{{-577,3L,1L},{851,0xCE60L,-1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{752,0x47DBL,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{955,0x6A92L,-5L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{974,-1L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{955,0x6A92L,-5L},{392,0x94C4L,-6L}},{{-577,3L,1L},{974,-1L,1L},{-129,1L,0x9B1A6D681E34EDD5LL}},{{200,-1L,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{312,0x2DBAL,0x4E566E280CE23346LL}}},{{{578,0x76F7L,0L},{851,0xCE60L,-1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{200,-1L,-1L},{-817,6L,-6L},{-817,6L,-6L}},{{-577,3L,1L},{-35,9L,1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{182,0xE94BL,0x6581619EEEF64BCCLL},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{752,0x47DBL,-1L},{955,0x6A92L,-5L},{312,0x2DBAL,0x4E566E280CE23346LL}},{{-577,3L,1L},{182,0xE94BL,0x6581619EEEF64BCCLL},{-129,1L,0x9B1A6D681E34EDD5LL}}},{{{-970,-3L,0x4012CE8C83D07D00LL},{-970,-3L,0x4012CE8C83D07D00LL},{392,0x94C4L,-6L}},{{578,0x76F7L,0L},{-35,9L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L},{955,0x6A92L,-5L}},{{-577,3L,1L},{851,0xCE60L,-1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{752,0x47DBL,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{955,0x6A92L,-5L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{974,-1L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{955,0x6A92L,-5L},{392,0x94C4L,-6L}}},{{{-577,3L,1L},{974,-1L,1L},{-129,1L,0x9B1A6D681E34EDD5LL}},{{200,-1L,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{312,0x2DBAL,0x4E566E280CE23346LL}},{{578,0x76F7L,0L},{851,0xCE60L,-1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{200,-1L,-1L},{-817,6L,-6L},{-817,6L,-6L}},{{-577,3L,1L},{-35,9L,1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{182,0xE94BL,0x6581619EEEF64BCCLL},{452,-1L,0xD2E197BDA7B8C8D2LL}}},{{{752,0x47DBL,-1L},{955,0x6A92L,-5L},{312,0x2DBAL,0x4E566E280CE23346LL}},{{-577,3L,1L},{182,0xE94BL,0x6581619EEEF64BCCLL},{-129,1L,0x9B1A6D681E34EDD5LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-970,-3L,0x4012CE8C83D07D00LL},{392,0x94C4L,-6L}},{{578,0x76F7L,0L},{-35,9L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L},{955,0x6A92L,-5L}},{{-577,3L,1L},{851,0xCE60L,-1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{752,0x47DBL,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{955,0x6A92L,-5L}}},{{{452,-1L,0xD2E197BDA7B8C8D2LL},{974,-1L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{955,0x6A92L,-5L},{392,0x94C4L,-6L}},{{-577,3L,1L},{974,-1L,1L},{-129,1L,0x9B1A6D681E34EDD5LL}},{{200,-1L,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{312,0x2DBAL,0x4E566E280CE23346LL}},{{578,0x76F7L,0L},{851,0xCE60L,-1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{200,-1L,-1L},{-817,6L,-6L},{-817,6L,-6L}},{{-577,3L,1L},{-35,9L,1L},{48,0xE824L,0xBFE40A9A4990B940LL}}},{{{693,0x5C59L,0x29EEFF1CD204F492LL},{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{182,0xE94BL,0x6581619EEEF64BCCLL},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{752,0x47DBL,-1L},{955,0x6A92L,-5L},{312,0x2DBAL,0x4E566E280CE23346LL}},{{-577,3L,1L},{182,0xE94BL,0x6581619EEEF64BCCLL},{-129,1L,0x9B1A6D681E34EDD5LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-970,-3L,0x4012CE8C83D07D00LL},{392,0x94C4L,-6L}},{{578,0x76F7L,0L},{-35,9L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L},{955,0x6A92L,-5L}}},{{{-577,3L,1L},{851,0xCE60L,-1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{752,0x47DBL,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{955,0x6A92L,-5L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{974,-1L,1L},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{955,0x6A92L,-5L},{392,0x94C4L,-6L}},{{-577,3L,1L},{974,-1L,1L},{-129,1L,0x9B1A6D681E34EDD5LL}},{{200,-1L,-1L},{-970,-3L,0x4012CE8C83D07D00LL},{312,0x2DBAL,0x4E566E280CE23346LL}},{{578,0x76F7L,0L},{851,0xCE60L,-1L},{452,-1L,0xD2E197BDA7B8C8D2LL}}},{{{200,-1L,-1L},{-817,6L,-6L},{-817,6L,-6L}},{{-577,3L,1L},{-35,9L,1L},{48,0xE824L,0xBFE40A9A4990B940LL}},{{693,0x5C59L,0x29EEFF1CD204F492LL},{-970,-3L,0x4012CE8C83D07D00LL},{-817,6L,-6L}},{{452,-1L,0xD2E197BDA7B8C8D2LL},{182,0xE94BL,0x6581619EEEF64BCCLL},{452,-1L,0xD2E197BDA7B8C8D2LL}},{{752,0x47DBL,-1L},{955,0x6A92L,-5L},{312,0x2DBAL,0x4E566E280CE23346LL}},{{-577,3L,1L},{182,0xE94BL,0x6581619EEEF64BCCLL},{-129,1L,0x9B1A6D681E34EDD5LL}},{{-970,-3L,0x4012CE8C83D07D00LL},{-970,-3L,0x4012CE8C83D07D00LL},{392,0x94C4L,-6L}}}}; + int i, j, k; + for (i = 0; i < 2; i++) + l_577[i] = &l_554; + (*l_576) = &l_554; + (*l_591) = (0xA96CL || (((l_400[(p_44 + 6)] | (safe_sub_func_int64_t_s_s(((p_44 , (+(((-1L) != (l_417 && ((safe_add_func_int64_t_s_s(((g_587 = (l_585[2][5] = &g_213)) == l_553), (safe_mul_func_int8_t_s_s(((g_143.f2 = l_417) || p_44), l_400[(p_44 + 6)])))) , 8L))) ^ 0L))) || 0x14DDL), p_43.f0))) , g_313.f7) > g_231.f3)); + g_104 = (+(safe_mul_func_int8_t_s_s((*g_358), ((*l_594)--)))); + l_597[5][6][1] = l_561[4][3][1]; + } + g_601 = (g_395 = ((*l_403) , ((*l_598) = &g_355))); + } + } + } + for (l_401 = 0; (l_401 < 20); l_401 = safe_add_func_int8_t_s_s(l_401, 2)) + { /* block id: 301 */ + uint8_t l_612 = 0x82L; + struct S0 l_620 = {-882,9L,0xFD9F04DBA90F779ELL}; + int32_t **l_622 = &g_139; + for (g_538 = 29; (g_538 < (-10)); g_538--) + { /* block id: 304 */ + int16_t l_615[1][8][7] = {{{1L,(-2L),0xEED0L,0xD448L,0xEED0L,(-2L),1L},{(-9L),1L,0xCEA3L,(-9L),1L,0xCEA3L,0xCEA3L},{1L,0xD448L,0x898AL,0xD448L,1L,0x9E67L,1L},{1L,(-9L),0xCEA3L,1L,(-9L),(-9L),1L},{0xEED0L,0xD448L,0xEED0L,(-2L),1L,(-2L),0xEED0L},{(-9L),0xCEA3L,1L,(-9L),(-9L),1L,0xCEA3L},{0xA006L,0x9E67L,0x898AL,(-2L),0x898AL,0x9E67L,0xA006L},{0x4F31L,(-9L),0xB489L,0xB489L,(-9L),0x4F31L,0xB489L}}}; + int32_t *l_621 = &l_415; + int i, j, k; + (*l_621) |= (safe_mod_func_int8_t_s_s((safe_mul_func_int8_t_s_s(0x95L, (safe_div_func_int16_t_s_s(((l_620.f0 = ((*g_587) , (l_612 > ((safe_mod_func_uint16_t_u_u(l_615[0][0][5], (safe_rshift_func_int8_t_s_s((safe_mod_func_int16_t_s_s((((&g_287 != &g_189) < 0x96L) <= 4294967288UL), (l_620 , l_419[2]))), 5)))) || l_615[0][0][5])))) & (*g_240)), 65531UL)))), p_44)); + } + (*l_622) = (void*)0; + l_620.f0 &= ((g_313.f7 , ((safe_mod_func_int64_t_s_s(g_4, g_440)) >= g_287)) | l_625); + } + --g_629[0]; + return l_401; + } + else + { /* block id: 313 */ + int64_t l_661[6][3]; + int32_t l_674 = 0xBA75351DL; + int32_t l_675[4] = {0xAB758BCBL,0xAB758BCBL,0xAB758BCBL,0xAB758BCBL}; + struct S0 l_692 = {-453,0x9084L,0x0361A15A91EB8A78LL}; + int8_t *l_707 = &l_417; + uint8_t *l_708 = &g_348; + uint8_t *l_709 = &g_189; + int32_t *l_716 = (void*)0; + int32_t *l_717 = &l_675[1]; + struct S1 l_720 = {0,56,1136,29,1,16,13,5413,146,1013}; + int i, j; + for (i = 0; i < 6; i++) + { + for (j = 0; j < 3; j++) + l_661[i][j] = 1L; + } + for (l_417 = (-23); (l_417 < (-17)); ++l_417) + { /* block id: 316 */ + int32_t l_649 = 0x5724EFA7L; + const union U4 *l_654[2][4] = {{(void*)0,&g_586,&g_586,(void*)0},{&g_586,(void*)0,&g_586,&g_586}}; + int32_t l_676 = (-1L); + int i, j; + for (g_79 = 3; (g_79 != 9); ++g_79) + { /* block id: 319 */ + const struct S1 l_638[8] = {{1,148,1905,12,10,10,177,6223,250,1820},{1,242,2018,-26,2,2,103,6046,151,-1950},{1,148,1905,12,10,10,177,6223,250,1820},{1,242,2018,-26,2,2,103,6046,151,-1950},{1,148,1905,12,10,10,177,6223,250,1820},{1,242,2018,-26,2,2,103,6046,151,-1950},{1,148,1905,12,10,10,177,6223,250,1820},{1,242,2018,-26,2,2,103,6046,151,-1950}}; + int16_t *l_665 = &g_249.f3; + union U4 l_668 = {1UL}; + struct S0 l_669 = {-531,0x9EBBL,0xC30C919DD8B6EBE0LL}; + const struct S0 l_694 = {-68,-1L,-10L}; + int i; + if ((safe_div_func_uint8_t_u_u((p_43.f3 < ((0x87CF64C2L == (p_43.f2 , (((void*)0 != &g_355) >= ((l_638[3] , 0x063E04CBL) ^ (safe_add_func_uint32_t_u_u((safe_sub_func_uint16_t_u_u((safe_rshift_func_int16_t_s_u((0x55EB4EC0L && p_43.f3), 10)), (**g_191))), p_44)))))) != (**g_357))), p_43.f0))) + { /* block id: 320 */ + uint64_t *l_659 = &g_249.f0; + int32_t l_660 = 9L; + int32_t l_673[8][5] = {{(-1L),0xE1B6DDE2L,(-4L),0xC38BF662L,6L},{(-2L),0xE121DEA2L,0xE121DEA2L,(-2L),0x2D1B191FL},{(-1L),0xE1B6DDE2L,(-4L),0xC38BF662L,6L},{(-2L),0xE121DEA2L,0xE121DEA2L,(-2L),0x2D1B191FL},{(-1L),0xE1B6DDE2L,(-4L),0xC38BF662L,6L},{(-2L),0xE121DEA2L,0xE121DEA2L,(-2L),0x2D1B191FL},{(-1L),0xE1B6DDE2L,(-4L),0xC38BF662L,6L},{(-2L),0xE121DEA2L,0xE121DEA2L,(-2L),0x2D1B191FL}}; + int i, j; + if ((safe_rshift_func_uint16_t_u_u(1UL, ((((safe_div_func_uint16_t_u_u(l_649, (l_402.f0 = ((safe_mul_func_uint16_t_u_u(0x023DL, (safe_add_func_int8_t_s_s(((p_43.f3 <= 0x919B90891930A0A9LL) , (((((((void*)0 != l_654[0][1]) || ((safe_add_func_int64_t_s_s(((((p_43.f0 |= l_417) <= ((*l_659) = (safe_lshift_func_uint8_t_u_s(0x35L, 6)))) != p_43.f2) != l_660), 0UL)) < 0x65BFL)) && p_43.f0) || 18446744073709551615UL) | 0x43L) && (**g_357))), l_661[3][0])))) | g_143.f0)))) < 0UL) >= l_660) == 0x6BB37CA7F6FECE31LL)))) + { /* block id: 324 */ + int16_t *l_664[10] = {&g_70,&g_70,&g_70,&g_70,&g_70,&g_70,&g_70,&g_70,&g_70,&g_70}; + int8_t *l_666[2]; + uint32_t *l_667[10][9][2] = {{{&g_79,&g_629[1]},{&g_569,&g_629[3]},{&g_79,&g_79},{&g_334,(void*)0},{&g_342,&g_629[0]},{&g_342,&g_339},{(void*)0,&g_339},{&g_334,&g_629[5]},{(void*)0,&g_342}},{{&l_503,&g_334},{&g_569,&g_629[0]},{&g_342,&g_334},{&g_339,&l_503},{(void*)0,&l_503},{&g_339,&g_334},{&g_342,&g_629[0]},{&g_569,&g_334},{&l_503,&g_342}},{{(void*)0,&g_629[5]},{&g_334,&g_339},{(void*)0,&g_339},{&g_342,&g_629[0]},{&g_342,(void*)0},{&g_334,&g_79},{&g_79,&g_629[3]},{&g_569,&g_629[1]},{&g_79,&g_79}},{{(void*)0,(void*)0},{(void*)0,&g_629[3]},{&g_629[0],(void*)0},{&g_629[0],&g_629[0]},{&g_79,&g_569},{&g_79,&g_629[0]},{&g_629[0],(void*)0},{&g_629[0],&g_629[3]},{(void*)0,(void*)0}},{{(void*)0,&g_79},{&g_79,&g_629[1]},{&g_569,&g_629[3]},{&g_79,&g_79},{&g_334,(void*)0},{&g_342,&g_629[0]},{&g_342,&g_339},{(void*)0,&g_339},{&g_334,&g_629[5]}},{{(void*)0,&g_342},{&l_503,&g_334},{&g_569,&g_629[0]},{&g_342,&g_334},{&g_339,&l_503},{&g_334,&g_342},{&g_342,&g_342},{&g_629[0],(void*)0},{&g_339,(void*)0}},{{&g_629[3],&g_569},{&g_629[5],&g_339},{(void*)0,&g_569},{&g_339,&g_629[1]},{&l_503,(void*)0},{&g_569,&g_339},{&g_342,(void*)0},{&g_334,&g_629[0]},{&g_629[0],&g_79}},{{&g_79,&g_79},{(void*)0,&g_339},{&g_339,&g_629[1]},{&g_79,&g_334},{(void*)0,&g_79},{&g_629[5],&g_629[0]},{&g_629[5],&g_79},{(void*)0,&g_334},{&g_79,&g_629[1]}},{{&g_339,&g_339},{(void*)0,&g_79},{&g_79,&g_79},{&g_629[0],&g_629[0]},{&g_334,(void*)0},{&g_342,&g_339},{&g_569,(void*)0},{&l_503,&g_629[1]},{&g_339,&g_569}},{{(void*)0,&g_339},{&g_629[5],&g_569},{&g_629[3],(void*)0},{&g_339,(void*)0},{&g_629[0],&g_342},{&g_342,&g_342},{&g_334,&g_342},{&g_342,&g_342},{&g_629[0],(void*)0}}}; + struct S0 l_670 = {-766,-6L,0xB03AD21F9F4C31E7LL}; + int32_t *l_671 = &g_252[1].f0; + int32_t *l_672[8][3][9] = {{{&g_252[1].f0,&l_400[2],(void*)0,&l_400[2],(void*)0,&g_252[1].f0,&g_252[1].f0,(void*)0,&l_400[2]},{&l_649,&l_649,&l_649,&l_400[4],&l_400[4],&l_400[2],(void*)0,(void*)0,&l_660},{&l_649,(void*)0,&l_400[4],&l_660,(void*)0,&l_400[4],&l_400[2],&l_400[4],(void*)0}},{{&l_400[4],&l_400[2],&l_400[2],&l_400[4],(void*)0,(void*)0,&l_400[4],&l_649,(void*)0},{&l_649,&l_649,(void*)0,&l_400[2],&g_252[1].f0,&l_660,&l_400[4],&l_400[4],&l_660},{(void*)0,&l_649,&l_400[4],&l_649,(void*)0,&l_649,&l_649,(void*)0,&l_400[2]}},{{(void*)0,(void*)0,&l_400[4],&l_649,(void*)0,&l_649,(void*)0,&l_400[2],(void*)0},{&l_649,&l_400[4],&g_252[1].f0,&g_252[1].f0,&l_400[4],&l_649,&l_649,(void*)0,&l_400[4]},{&l_400[4],&l_400[4],&l_400[2],(void*)0,(void*)0,&l_660,&g_252[1].f0,&l_649,&l_649}},{{&l_649,(void*)0,&l_660,(void*)0,&l_660,(void*)0,&l_649,&g_252[1].f0,&l_400[2]},{&l_649,&l_649,&l_660,&l_649,(void*)0,&l_400[4],(void*)0,(void*)0,&l_649},{&g_252[1].f0,&l_649,&l_400[2],(void*)0,(void*)0,&l_400[2],&l_649,&g_252[1].f0,&g_252[1].f0}},{{&l_400[4],&l_400[2],&l_400[4],&l_660,&l_649,&l_649,(void*)0,&l_400[2],&l_649},{&l_649,&l_649,&l_649,&l_400[2],&g_252[1].f0,&l_400[2],&l_649,&l_649,&l_649},{(void*)0,&l_400[2],&l_649,&g_252[1].f0,&g_252[1].f0,(void*)0,&l_400[4],&l_649,(void*)0}},{{&l_400[2],&l_649,&g_252[1].f0,&l_400[4],&l_649,&l_649,&l_400[4],&g_252[1].f0,&l_649},{(void*)0,&g_252[1].f0,&l_400[4],&l_400[4],&l_660,&l_649,&l_649,(void*)0,&l_400[2]},{&l_649,&l_400[4],&g_252[1].f0,(void*)0,&g_252[1].f0,(void*)0,&g_252[1].f0,(void*)0,&g_252[1].f0}},{{&g_252[1].f0,&g_252[1].f0,(void*)0,&l_400[2],(void*)0,&l_400[2],&g_252[1].f0,&l_649,(void*)0},{&l_400[4],&l_649,&l_649,&l_400[4],(void*)0,&l_649,&l_649,(void*)0,&l_400[4]},{(void*)0,&l_400[2],(void*)0,&l_649,(void*)0,&l_649,&l_400[4],(void*)0,(void*)0}},{{&l_400[2],&l_649,&g_252[1].f0,(void*)0,&l_400[4],&l_649,&l_400[4],&l_649,&l_400[4]},{&l_649,&l_400[4],&l_400[4],&l_649,&l_649,&l_660,&l_649,(void*)0,&l_400[4]},{(void*)0,(void*)0,&g_252[1].f0,&l_400[4],&l_649,(void*)0,(void*)0,(void*)0,(void*)0}}}; + int i, j, k; + for (i = 0; i < 2; i++) + l_666[i] = &g_538; + l_670 = (((0x0195L <= ((((g_189 || (safe_sub_func_int64_t_s_s((-6L), (0xC099L && (g_118 = 0x5C68L))))) ^ (g_538 = ((**g_357) = (l_545 != l_665)))) || (l_667[4][2][1] != ((l_400[4] , l_668) , p_42))) > g_231.f6)) > l_649) , l_669); + if (g_106[3]) + continue; + --g_677; + } + else + { /* block id: 331 */ + return (**g_191); + } + } + else + { /* block id: 334 */ + struct S1 ** const l_680 = &g_230; + int32_t l_688[6]; + int i; + for (i = 0; i < 6; i++) + l_688[i] = 3L; + l_681[0][1][0] = l_680; + for (g_385.f1 = 0; (g_385.f1 < 53); ++g_385.f1) + { /* block id: 338 */ + int32_t *l_684 = &l_400[4]; + int32_t *l_685 = &l_400[7]; + int32_t *l_686 = &g_252[1].f0; + int32_t *l_687[4]; + struct S0 *l_693 = &l_669; + int i; + for (i = 0; i < 4; i++) + l_687[i] = &l_400[4]; + --g_689; + (*l_693) = l_692; + (*l_693) = l_694; + if (p_43.f3) + break; + } + return p_43.f2; + } + } + return (**g_191); + } + (*l_717) = (safe_rshift_func_int8_t_s_u((safe_lshift_func_uint16_t_u_s((**g_191), (((l_400[5] = (0xF9F7A78D728946DDLL <= (safe_add_func_uint16_t_u_u(((((*g_358) = l_692.f1) , (((!(l_503 , (0x8A809489DC73D95FLL & ((((((*l_709) = ((*l_708) = ((+0x2E02CB5748B435BELL) , (safe_mul_func_int8_t_s_s(5L, ((*l_707) &= (((safe_mod_func_int32_t_s_s((-1L), (safe_mod_func_int8_t_s_s(l_692.f0, (*g_358))))) , p_44) , 0L))))))) ^ (**g_357)) , l_710) , l_692.f0) == 0xE632L)))) != l_400[4]) , l_711[5][5])) == g_713), p_44)))) && (*g_358)) | l_715))), 6)); + if (((safe_add_func_uint32_t_u_u(((l_720 , (*g_357)) == l_708), (l_401 , 0xBE3A41BFL))) <= (p_43.f1 <= (p_43.f1 , (&g_191 != (((((((*l_717) = p_43.f0) | 0x2D55D67FL) == l_402.f2) , (-1L)) != p_44) , (void*)0)))))) + { /* block id: 356 */ + int32_t **l_721 = &l_716; + (*l_721) = p_42; + } + else + { /* block id: 358 */ + g_139 = &g_104; + } + } + return p_43.f0; +} + + +/* ------------------------------------------ */ +/* + * reads : g_240 g_79 g_313.f5 g_191 g_192 g_97 + * writes: g_104 + */ +static uint32_t * func_45(union U4 p_46, int32_t p_47, uint32_t * p_48, uint32_t * p_49) +{ /* block id: 186 */ + int32_t *l_368 = &g_104; + int32_t *l_369 = &g_104; + int32_t *l_370 = &g_252[1].f0; + int32_t *l_371[10][6] = {{&g_252[1].f0,&g_104,&g_252[1].f0,&g_104,&g_252[1].f0,&g_104},{&g_252[1].f0,(void*)0,&g_104,&g_104,(void*)0,(void*)0},{(void*)0,&g_104,&g_104,(void*)0,&g_252[1].f0,(void*)0},{(void*)0,(void*)0,&g_104,&g_104,&g_104,&g_104},{&g_252[1].f0,(void*)0,&g_252[1].f0,&g_104,&g_104,&g_252[1].f0},{&g_104,(void*)0,(void*)0,&g_252[1].f0,&g_252[1].f0,(void*)0},{&g_104,&g_104,(void*)0,&g_252[1].f0,(void*)0,&g_104},{&g_104,(void*)0,&g_252[1].f0,&g_104,&g_252[1].f0,(void*)0},{&g_252[1].f0,&g_104,&g_252[1].f0,&g_104,&g_104,&g_104},{(void*)0,&g_104,(void*)0,(void*)0,&g_104,(void*)0}}; + uint8_t l_372 = 0UL; + struct S2 l_379 = {0x13EEEFE5E05E85FDLL,0xCD2BL,8L,-2L}; + int16_t l_380 = 0x4745L; + uint16_t **l_382 = &g_192[4]; + uint16_t ***l_381 = &l_382; + uint16_t **l_384[10][4][6] = {{{&g_192[2],&g_192[2],&g_192[2],&g_192[2],&g_192[4],(void*)0},{&g_192[2],&g_192[3],&g_192[3],(void*)0,&g_192[2],&g_192[2]},{&g_192[2],&g_192[2],&g_192[3],&g_192[1],(void*)0,&g_192[2]},{&g_192[2],(void*)0,&g_192[4],&g_192[2],(void*)0,&g_192[1]}},{{&g_192[5],&g_192[2],&g_192[0],&g_192[0],&g_192[3],&g_192[5]},{&g_192[0],&g_192[2],&g_192[2],&g_192[7],&g_192[2],&g_192[3]},{(void*)0,(void*)0,&g_192[2],&g_192[2],&g_192[5],&g_192[2]},{(void*)0,&g_192[1],&g_192[2],&g_192[5],&g_192[2],&g_192[7]}},{{&g_192[2],(void*)0,&g_192[5],&g_192[3],&g_192[0],&g_192[2]},{(void*)0,&g_192[5],&g_192[2],&g_192[5],(void*)0,&g_192[2]},{&g_192[6],&g_192[2],&g_192[4],&g_192[7],&g_192[0],&g_192[2]},{&g_192[5],&g_192[2],&g_192[5],&g_192[2],&g_192[1],&g_192[2]}},{{&g_192[3],&g_192[2],&g_192[4],&g_192[7],&g_192[2],&g_192[2]},{&g_192[1],(void*)0,&g_192[2],&g_192[4],(void*)0,&g_192[2]},{&g_192[2],(void*)0,&g_192[5],&g_192[2],(void*)0,&g_192[7]},{&g_192[2],&g_192[5],&g_192[2],&g_192[2],&g_192[5],&g_192[2]}},{{&g_192[4],&g_192[2],&g_192[2],&g_192[2],(void*)0,&g_192[3]},{&g_192[6],&g_192[2],&g_192[2],(void*)0,&g_192[1],&g_192[5]},{(void*)0,&g_192[6],&g_192[0],(void*)0,(void*)0,&g_192[2]},{(void*)0,&g_192[2],(void*)0,(void*)0,&g_192[1],&g_192[2]}},{{(void*)0,&g_192[1],&g_192[1],&g_192[2],&g_192[3],(void*)0},{&g_192[2],&g_192[5],&g_192[5],&g_192[2],&g_192[7],&g_192[4]},{&g_192[7],&g_192[2],&g_192[2],&g_192[5],&g_192[0],&g_192[2]},{&g_192[2],&g_192[2],(void*)0,&g_192[2],&g_192[0],(void*)0}},{{&g_192[2],&g_192[2],&g_192[3],&g_192[3],&g_192[2],&g_192[2]},{&g_192[2],&g_192[3],&g_192[0],(void*)0,(void*)0,&g_192[2]},{&g_192[1],&g_192[2],(void*)0,&g_192[2],&g_192[2],&g_192[2]},{&g_192[1],(void*)0,&g_192[2],(void*)0,&g_192[1],(void*)0}},{{&g_192[2],(void*)0,&g_192[2],&g_192[3],&g_192[2],&g_192[1]},{&g_192[2],&g_192[5],&g_192[2],&g_192[2],&g_192[0],&g_192[2]},{&g_192[2],&g_192[2],&g_192[7],&g_192[5],&g_192[1],(void*)0},{&g_192[7],&g_192[2],&g_192[2],&g_192[2],&g_192[4],&g_192[2]}},{{&g_192[2],&g_192[3],&g_192[2],&g_192[2],&g_192[1],&g_192[2]},{(void*)0,&g_192[2],&g_192[2],(void*)0,&g_192[2],&g_192[2]},{(void*)0,&g_192[5],&g_192[2],(void*)0,&g_192[1],&g_192[2]},{(void*)0,&g_192[2],&g_192[2],(void*)0,&g_192[7],&g_192[2]}},{{&g_192[2],&g_192[2],&g_192[1],&g_192[2],&g_192[3],(void*)0},{(void*)0,(void*)0,&g_192[1],&g_192[2],&g_192[5],&g_192[2]},{&g_192[2],&g_192[2],&g_192[2],&g_192[2],(void*)0,&g_192[4]},{&g_192[2],&g_192[2],(void*)0,(void*)0,(void*)0,&g_192[2]}}}; + uint16_t ***l_383 = &l_384[6][2][4]; + int i, j, k; + --l_372; + (*l_368) = (safe_add_func_uint16_t_u_u(((((*g_240) ^ (safe_add_func_uint8_t_u_u(p_46.f2, (l_379 , (l_380 ^ p_46.f0))))) , g_313.f5) < (**g_191)), (((*l_383) = ((*l_381) = &g_192[2])) == &g_192[2]))); + return &g_100; +} + + +/* ------------------------------------------ */ +/* + * reads : + * writes: + */ +static union U4 func_50(union U4 p_51, const uint32_t * p_52, uint32_t * const p_53) +{ /* block id: 183 */ + int8_t l_366 = (-8L); + union U4 l_367 = {18446744073709551615UL}; + l_366 = p_51.f0; + return l_367; +} + + +/* ------------------------------------------ */ +/* + * reads : g_287 g_249.f0 g_104 g_231.f3 g_213 g_231.f2 g_231.f1 g_79 g_143.f2 g_252 g_191 g_192 g_97 g_249.f1 g_313.f2 g_143.f0 g_143 g_249.f3 g_240 g_231.f8 g_334 g_348 g_252.f0 g_357 g_362 + * writes: g_287 g_249.f0 g_104 g_79 g_143.f2 g_143.f0 g_328 g_189 g_143 g_334 g_339 g_97 g_249.f1 g_348 g_252.f0 g_355 g_357 g_362 + */ +static union U4 func_54(uint64_t p_55, uint32_t * p_56, uint32_t * p_57, struct S1 p_58, uint32_t * p_59) +{ /* block id: 120 */ + int32_t *l_283 = &g_252[1].f0; + int32_t *l_284 = &g_104; + int32_t *l_285 = &g_104; + int32_t *l_286[10][2] = {{&g_104,&g_252[1].f0},{(void*)0,&g_252[1].f0},{&g_104,(void*)0},{(void*)0,(void*)0},{(void*)0,(void*)0},{&g_104,&g_252[1].f0},{(void*)0,&g_252[1].f0},{&g_104,(void*)0},{(void*)0,(void*)0},{(void*)0,(void*)0}}; + int64_t *l_324 = (void*)0; + union U4 l_365 = {0x6AC2539AL}; + int i, j; + g_287--; + for (g_249.f0 = 0; (g_249.f0 <= 1); g_249.f0 += 1) + { /* block id: 124 */ + uint16_t l_290 = 0x56E6L; + union U4 l_308 = {0UL}; + struct S0 *l_309 = &g_143; + int32_t l_343 = 0x79CF198FL; + --l_290; + (*l_284) ^= 1L; + for (g_79 = 0; (g_79 <= 1); g_79 += 1) + { /* block id: 129 */ + uint32_t l_305 = 0x3041FB20L; + int32_t l_327[5][9][3] = {{{1L,0xB16D34A9L,(-7L)},{0x29FDDACFL,0L,(-1L)},{1L,0xD560236DL,(-1L)},{(-7L),0L,0L},{0xDDEAE75FL,0xB16D34A9L,(-1L)},{(-7L),(-7L),1L},{1L,0x1A3FA46EL,(-1L)},{0x29FDDACFL,0x29FDDACFL,0L},{1L,0x1A3FA46EL,(-1L)}},{{0L,(-7L),(-1L)},{1L,0xB16D34A9L,(-7L)},{0x29FDDACFL,0L,(-1L)},{1L,0xD560236DL,(-1L)},{(-7L),0L,0L},{0xDDEAE75FL,0xB16D34A9L,(-1L)},{(-7L),(-7L),1L},{1L,0x1A3FA46EL,(-1L)},{0x29FDDACFL,0x29FDDACFL,0L}},{{1L,0x1A3FA46EL,(-1L)},{0L,(-7L),(-1L)},{1L,0xB16D34A9L,(-7L)},{0x29FDDACFL,0L,(-1L)},{1L,0xD560236DL,(-1L)},{(-7L),0L,0L},{0xDDEAE75FL,0xB16D34A9L,(-1L)},{(-7L),(-7L),1L},{1L,0x1A3FA46EL,(-1L)}},{{0x29FDDACFL,0x29FDDACFL,0L},{1L,0x1A3FA46EL,(-1L)},{0L,(-7L),(-1L)},{1L,0xB16D34A9L,(-7L)},{0x29FDDACFL,0L,(-1L)},{1L,0xD560236DL,(-1L)},{(-7L),0L,0L},{0xDDEAE75FL,0xB16D34A9L,(-1L)},{(-7L),(-7L),1L}},{{1L,0x1A3FA46EL,(-1L)},{0x29FDDACFL,0x29FDDACFL,0L},{1L,0x1A3FA46EL,(-1L)},{0L,(-7L),(-1L)},{1L,0xB16D34A9L,(-7L)},{0x29FDDACFL,0L,(-1L)},{1L,0xD560236DL,(-1L)},{(-7L),0L,0L},{0xDDEAE75FL,0xB16D34A9L,(-1L)}}}; + int32_t l_347 = 0x1679F912L; + int i, j, k; + if ((safe_div_func_uint8_t_u_u((p_58.f3 ^ ((safe_add_func_uint8_t_u_u((safe_lshift_func_uint8_t_u_s((safe_add_func_uint64_t_u_u((((p_58 , ((p_55 >= (~(safe_sub_func_int64_t_s_s((safe_add_func_int64_t_s_s(g_231.f3, (~(l_305 <= p_58.f1)))), (p_55 <= (safe_sub_func_uint16_t_u_u(((g_213 , g_231.f2) == p_58.f9), p_58.f8))))))) != p_58.f3)) == l_290) | (-2L)), g_231.f1)), (*l_285))), p_58.f8)) <= (*l_285))), g_287))) + { /* block id: 130 */ + int i, j; + l_286[(g_249.f0 + 7)][g_79] = (void*)0; + return l_308; + } + else + { /* block id: 133 */ + struct S0 **l_310 = &l_309; + const struct S1 *l_312 = &g_313; + const struct S1 **l_311 = &l_312; + int64_t *l_345[7][7][5] = {{{&g_143.f2,&g_143.f2,&g_143.f2,(void*)0,&g_4},{(void*)0,(void*)0,&g_4,(void*)0,&g_4},{&g_4,&g_143.f2,(void*)0,&g_4,(void*)0},{&g_143.f2,&g_143.f2,&g_143.f2,&g_4,&g_4},{&g_143.f2,&g_4,&g_4,(void*)0,&g_4},{&g_4,&g_4,&g_143.f2,&g_143.f2,&g_4},{&g_143.f2,(void*)0,&g_4,&g_143.f2,&g_143.f2}},{{&g_4,&g_143.f2,&g_143.f2,&g_4,&g_4},{&g_4,(void*)0,&g_4,&g_143.f2,&g_143.f2},{&g_143.f2,&g_4,&g_4,&g_143.f2,&g_4},{&g_4,&g_4,&g_4,(void*)0,&g_143.f2},{(void*)0,&g_143.f2,&g_4,&g_4,&g_143.f2},{&g_143.f2,&g_143.f2,&g_4,&g_4,&g_4},{&g_143.f2,&g_4,&g_143.f2,&g_143.f2,&g_143.f2}},{{&g_143.f2,&g_4,(void*)0,&g_143.f2,&g_4},{&g_143.f2,&g_4,&g_143.f2,(void*)0,&g_143.f2},{&g_4,&g_143.f2,(void*)0,&g_4,&g_4},{&g_4,&g_4,&g_143.f2,&g_143.f2,&g_4},{(void*)0,&g_143.f2,&g_4,(void*)0,&g_4},{&g_143.f2,&g_4,&g_4,&g_143.f2,(void*)0},{&g_143.f2,&g_4,&g_4,&g_143.f2,(void*)0}},{{(void*)0,&g_4,&g_4,(void*)0,&g_4},{&g_4,(void*)0,&g_4,&g_143.f2,(void*)0},{&g_4,&g_143.f2,&g_143.f2,(void*)0,(void*)0},{&g_143.f2,(void*)0,&g_4,&g_143.f2,&g_4},{&g_143.f2,&g_143.f2,&g_143.f2,(void*)0,&g_143.f2},{&g_143.f2,&g_143.f2,&g_4,&g_143.f2,&g_4},{&g_143.f2,(void*)0,&g_143.f2,&g_143.f2,&g_143.f2}},{{(void*)0,(void*)0,(void*)0,(void*)0,&g_4},{&g_4,&g_143.f2,&g_4,&g_143.f2,&g_4},{&g_143.f2,&g_143.f2,&g_143.f2,&g_4,&g_4},{&g_4,(void*)0,&g_143.f2,(void*)0,(void*)0},{&g_4,&g_143.f2,&g_143.f2,&g_143.f2,&g_4},{&g_143.f2,(void*)0,&g_143.f2,&g_143.f2,&g_4},{&g_4,&g_4,&g_143.f2,&g_4,&g_4}},{{&g_143.f2,&g_4,&g_143.f2,&g_4,&g_143.f2},{&g_143.f2,&g_4,&g_143.f2,(void*)0,&g_4},{&g_4,&g_143.f2,&g_143.f2,&g_143.f2,&g_143.f2},{&g_143.f2,&g_4,&g_143.f2,&g_143.f2,&g_4},{&g_143.f2,&g_143.f2,&g_143.f2,&g_4,(void*)0},{&g_4,&g_4,&g_143.f2,&g_4,&g_4},{(void*)0,&g_4,(void*)0,(void*)0,(void*)0}},{{&g_4,&g_4,(void*)0,&g_143.f2,&g_4},{&g_4,&g_4,&g_4,(void*)0,&g_143.f2},{&g_4,(void*)0,&g_143.f2,(void*)0,&g_4},{(void*)0,&g_143.f2,&g_4,&g_143.f2,&g_4},{&g_143.f2,&g_143.f2,(void*)0,(void*)0,&g_143.f2},{&g_143.f2,&g_4,&g_4,&g_4,&g_4},{(void*)0,&g_143.f2,&g_143.f2,&g_143.f2,&g_143.f2}}}; + int i, j, k; + (*l_285) = p_58.f1; + (*l_310) = l_309; + if ((((*l_311) = &g_231) != (void*)0)) + { /* block id: 137 */ + int64_t *l_319[9][3] = {{&g_4,(void*)0,&g_4},{&g_4,&g_143.f2,&g_4},{&g_4,(void*)0,&g_4},{&g_4,&g_143.f2,&g_4},{&g_4,(void*)0,&g_4},{&g_4,&g_143.f2,&g_4},{&g_4,(void*)0,&g_4},{&g_4,&g_143.f2,&g_4},{&g_4,(void*)0,&g_4}}; + int32_t l_320 = 0xFF86E467L; + int i, j; + if (p_58.f8) + break; + (*l_284) = (g_143.f0 |= (safe_mul_func_uint8_t_u_u((safe_rshift_func_int8_t_s_u((l_308.f0 || (((((safe_unary_minus_func_uint8_t_u(((!(g_143.f2 ^= (*l_285))) & (l_320 & (3L > p_58.f6))))) ^ (safe_unary_minus_func_int16_t_s((safe_mul_func_int16_t_s_s(((g_252[1] , l_324) == (((-3L) >= (((g_213 , 1UL) || l_327[1][2][1]) <= l_308.f0)) , (void*)0)), (**g_191)))))) == 1L) < g_249.f1) && l_290)), 6)), g_313.f2))); + } + else + { /* block id: 142 */ + if (((g_328 = p_56) == &g_100)) + { /* block id: 144 */ + (*l_310) = (void*)0; + } + else + { /* block id: 146 */ + union U4 *l_330 = (void*)0; + union U4 **l_329 = &l_330; + if (p_58.f2) + break; + (*l_329) = &g_213; + } + for (g_189 = 0; (g_189 <= 1); g_189 += 1) + { /* block id: 152 */ + uint32_t *l_333 = &g_334; + uint32_t *l_337 = (void*)0; + uint32_t *l_338 = &g_339; + uint32_t *l_340 = (void*)0; + uint32_t *l_341[9]; + uint16_t *l_344 = &g_249.f1; + int i; + for (i = 0; i < 9; i++) + l_341[i] = &g_342; + g_143 = g_143; + l_327[1][2][1] = ((g_249.f3 == ((*g_240) | (l_290 | ((0x65L != g_231.f8) , ((*l_344) |= ((**g_191) = (safe_div_func_uint32_t_u_u(0x5C0BEE4BL, (l_343 = ((*g_240) , ((*l_338) = (++(*l_333))))))))))))) ^ (p_58.f3 || ((void*)0 != l_345[3][6][2]))); + } + } + } + for (g_249.f1 = 0; (g_249.f1 <= 1); g_249.f1 += 1) + { /* block id: 165 */ + int32_t l_346[3]; + uint8_t *l_351 = &g_189; + uint8_t *l_354 = &g_106[3]; + int i, j; + for (i = 0; i < 3; i++) + l_346[i] = 1L; + l_343 ^= 1L; + --g_348; + (*l_283) ^= ((l_308.f2 , (l_343 ^= ((*l_351) = (*l_285)))) < (safe_div_func_int64_t_s_s(((void*)0 != l_354), 4UL))); + for (l_347 = 0; (l_347 <= 2); l_347 += 1) + { /* block id: 173 */ + struct S2 l_356[3] = {{0xB4CB6625C39C28E8LL,0x8EF0L,0xAFL,0xD0D5L},{0xB4CB6625C39C28E8LL,0x8EF0L,0xAFL,0xD0D5L},{0xB4CB6625C39C28E8LL,0x8EF0L,0xAFL,0xD0D5L}}; + int8_t ***l_360 = &g_357; + int32_t l_361 = (-8L); + int i; + g_355 = l_309; + (*l_360) = (l_356[1] , g_357); + g_362++; + } + } + (*l_285) = p_58.f8; + } + } + return l_365; +} + + +/* ------------------------------------------ */ +/* + * reads : g_70 g_4 g_97 g_100 g_104 g_106 g_118 g_143 g_189 g_191 g_213 g_226 g_230 g_213.f1 g_240 g_231.f9 g_79 g_249 g_252 g_231.f3 g_231.f1 g_252.f0 + * writes: g_70 g_79 g_97 g_104 g_106 g_118 g_139 g_143 g_189 g_226 g_230 g_252.f0 + */ +static uint64_t func_60(uint32_t p_61, uint32_t p_62, uint32_t * p_63, const uint32_t * p_64) +{ /* block id: 7 */ + int8_t l_77 = 0x1BL; + union U4 l_174 = {0UL}; + int32_t l_228[7] = {0xE996AD94L,0xE996AD94L,0xE996AD94L,0xE996AD94L,0xE996AD94L,0xE996AD94L,0xE996AD94L}; + struct S0 l_229 = {560,-10L,0xC330AEBB82BABF48LL}; + const struct S1 l_246 = {0,173,1787,26,0,18,132,4579,132,2555}; + int32_t *l_264 = &g_252[1].f0; + int32_t *l_265 = &l_228[6]; + int32_t *l_266 = &l_228[6]; + int32_t *l_267 = &g_104; + int32_t *l_268 = &g_104; + int32_t *l_269[2][3][7] = {{{&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0},{&g_104,&l_228[6],&g_104,&l_228[6],&g_104,&l_228[6],&g_104},{&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0}},{{&g_104,&l_228[6],&g_104,&l_228[6],&g_104,&l_228[6],&g_104},{&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0,&g_252[1].f0},{&g_104,&l_228[6],&g_104,&l_228[6],&g_104,&l_228[6],&g_104}}}; + uint16_t l_270 = 0x4EA2L; + struct S2 l_273 = {2UL,7UL,1L,-1L}; + uint8_t *l_274 = &g_106[3]; + const union U3 l_280[9][5] = {{{-1L},{0xE9DAC5E5L},{0L},{1L},{0x82091717L}},{{0xF7767CE1L},{0xB7D7F6A1L},{7L},{3L},{0x719AC70EL}},{{0xE9DAC5E5L},{3L},{-1L},{0L},{0L}},{{0xF7767CE1L},{0L},{0xF7767CE1L},{-1L},{0xCBD6449BL}},{{-1L},{0L},{3L},{0xE9DAC5E5L},{0xB7D7F6A1L}},{{0x56022EB1L},{3L},{0L},{7L},{-1L}},{{-1L},{0xB7D7F6A1L},{3L},{0xB7D7F6A1L},{-1L}},{{0x82091717L},{0xE9DAC5E5L},{0xF7767CE1L},{0xB7D7F6A1L},{7L}},{{1L},{0x82091717L},{-1L},{7L},{2L}}}; + int i, j, k; + for (g_70 = 0; (g_70 <= 11); g_70 = safe_add_func_uint64_t_u_u(g_70, 9)) + { /* block id: 10 */ + int8_t l_101 = 0xEDL; + int32_t *l_115 = (void*)0; + union U3 l_130[1] = {{-9L}}; + union U4 l_131[10] = {{0UL},{0x96FBAD4EL},{0UL},{0x105BDF17L},{0x105BDF17L},{0UL},{0x96FBAD4EL},{0UL},{0x105BDF17L},{0x105BDF17L}}; + uint16_t *l_156[2][6] = {{&g_97,&g_97,&g_97,&l_131[8].f2,&l_131[8].f2,&g_97},{(void*)0,(void*)0,&l_131[8].f2,&g_97,&l_131[8].f2,(void*)0}}; + uint16_t **l_155[3]; + const int16_t l_159 = 0x539FL; + int i, j; + for (i = 0; i < 3; i++) + l_155[i] = &l_156[0][0]; + for (p_61 = 0; (p_61 >= 7); p_61 = safe_add_func_int64_t_s_s(p_61, 2)) + { /* block id: 13 */ + int16_t *l_80 = &g_70; + int32_t l_95 = 8L; + int32_t l_133 = 0x0275E99CL; + int32_t *l_163 = (void*)0; + struct S0 l_164 = {974,-1L,-7L}; + for (p_62 = 0; (p_62 <= 38); p_62 = safe_add_func_int8_t_s_s(p_62, 7)) + { /* block id: 16 */ + uint32_t *l_78[7]; + uint16_t *l_96 = &g_97; + int32_t l_102 = 0x0EEEF661L; + int32_t *l_103 = &g_104; + uint8_t *l_105[4] = {&g_106[3],&g_106[3],&g_106[3],&g_106[3]}; + int8_t *l_116 = (void*)0; + int16_t *l_117 = &g_118; + int32_t *l_119 = &l_102; + struct S0 l_137[8] = {{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL},{213,0x47B4L,0x0677A089C8F7CEBBLL}}; + int32_t l_166 = (-2L); + int i; + for (i = 0; i < 7; i++) + l_78[i] = &g_79; + (*l_103) &= (l_102 ^= (((g_79 = l_77) && ((void*)0 == l_80)) != (safe_sub_func_int16_t_s_s(((((((!((safe_add_func_int8_t_s_s((0x2D5F2ABA01C9AC71LL > ((safe_rshift_func_int8_t_s_s((~(g_4 >= (((safe_sub_func_uint64_t_u_u((safe_sub_func_int16_t_s_s((!(safe_mod_func_uint64_t_u_u((((safe_rshift_func_int16_t_s_u(((--(*l_96)) > l_95), 11)) , ((252UL > l_95) == ((g_100 == 0x783651A3L) && p_61))) != 255UL), g_100))), 0L)), p_62)) ^ 0x42B3FDF2DC13529CLL) != l_95))), 3)) & p_62)), p_61)) != 18446744073709551606UL)) != p_61) != l_101) > p_62) | p_61) , 0x9E3CL), g_70)))); + (*l_119) |= ((g_106[3] = (*l_103)) , (~(0xF9L <= (safe_rshift_func_uint16_t_u_s(p_61, ((*l_117) = ((safe_rshift_func_int8_t_s_s((safe_add_func_int64_t_s_s((!3L), 7UL)), ((*l_103) = ((p_62 != 0L) > (l_101 > ((l_115 = &g_104) != (void*)0)))))) > g_106[3]))))))); + if (p_62) + break; + if ((*l_115)) + { /* block id: 27 */ + uint64_t l_132 = 18446744073709551613UL; + struct S0 l_135[6] = {{-975,0xC4DDL,0xE31D749550B438E4LL},{-975,0xC4DDL,0xE31D749550B438E4LL},{-975,0xC4DDL,0xE31D749550B438E4LL},{-975,0xC4DDL,0xE31D749550B438E4LL},{-975,0xC4DDL,0xE31D749550B438E4LL},{-975,0xC4DDL,0xE31D749550B438E4LL}}; + struct S0 *l_136 = (void*)0; + struct S0 *l_138 = &l_135[0]; + int i; + for (g_118 = 0; (g_118 <= 3); g_118 += 1) + { /* block id: 30 */ + int32_t **l_134 = &l_103; + int i; + l_133 |= (safe_div_func_int16_t_s_s((safe_div_func_uint16_t_u_u(((safe_sub_func_uint32_t_u_u(0UL, (((safe_mod_func_int64_t_s_s((((*l_119) = ((g_104 ^= ((safe_add_func_uint32_t_u_u(0xCED91AC4L, (g_106[g_118] == 0x3B74EAE5L))) <= (((l_130[0] , l_131[8]) , (+(&g_106[3] == (void*)0))) , l_132))) <= l_95)) < l_77), 4L)) || (*l_115)) | 1UL))) ^ 0x805AAA48L), p_62)), 0xCB19L)); + if (l_77) + break; + (*l_134) = (void*)0; + return g_70; + } + (*l_138) = (l_137[0] = l_135[1]); + } + else + { /* block id: 40 */ + uint8_t l_153 = 0xE7L; + int32_t l_154 = (-5L); + for (l_101 = 3; (l_101 >= 0); l_101 -= 1) + { /* block id: 43 */ + uint16_t ***l_157 = &l_155[2]; + int i; + g_139 = (void*)0; + l_154 ^= (safe_unary_minus_func_uint64_t_u((+(((safe_div_func_int8_t_s_s(((((g_143 , (safe_div_func_uint8_t_u_u(l_95, (safe_sub_func_uint64_t_u_u(g_104, (l_133 , ((void*)0 == &g_139))))))) , (safe_mul_func_int16_t_s_s(0L, (-7L)))) , ((safe_sub_func_int8_t_s_s((safe_unary_minus_func_int32_t_s((((p_62 != g_100) <= l_153) == g_106[3]))), 0x3BL)) > 0x9CL)) <= g_143.f0), (*l_103))) & 1L) || (*l_119))))); + (*l_157) = l_155[2]; + } + for (g_118 = 3; (g_118 >= 0); g_118 -= 1) + { /* block id: 50 */ + int32_t **l_158 = &l_103; + uint32_t *l_160[10][6][4] = {{{&g_79,(void*)0,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79},{(void*)0,&g_79,&g_79,(void*)0},{(void*)0,&g_79,&g_79,(void*)0}},{{&g_79,(void*)0,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79},{&g_79,(void*)0,&g_79,(void*)0},{&g_79,&g_79,(void*)0,(void*)0},{&g_79,&g_79,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79}},{{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79},{(void*)0,&g_79,(void*)0,(void*)0},{(void*)0,&g_79,&g_79,(void*)0},{&g_79,(void*)0,&g_79,&g_79}},{{&g_79,(void*)0,&g_79,&g_79},{&g_79,(void*)0,(void*)0,(void*)0},{&g_79,&g_79,(void*)0,(void*)0},{(void*)0,&g_79,(void*)0,&g_79},{&g_79,(void*)0,(void*)0,&g_79},{&g_79,&g_79,&g_79,&g_79}},{{&g_79,&g_79,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79},{(void*)0,(void*)0,(void*)0,(void*)0},{(void*)0,&g_79,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79}},{{&g_79,(void*)0,&g_79,&g_79},{&g_79,&g_79,&g_79,(void*)0},{&g_79,(void*)0,(void*)0,&g_79},{&g_79,(void*)0,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79}},{{&g_79,(void*)0,&g_79,&g_79},{(void*)0,&g_79,&g_79,(void*)0},{(void*)0,&g_79,&g_79,(void*)0},{&g_79,(void*)0,&g_79,&g_79},{&g_79,(void*)0,&g_79,&g_79},{&g_79,(void*)0,&g_79,(void*)0}},{{&g_79,&g_79,(void*)0,(void*)0},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,(void*)0},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,(void*)0},{&g_79,&g_79,&g_79,&g_79}},{{&g_79,&g_79,&g_79,&g_79},{(void*)0,(void*)0,&g_79,(void*)0},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,(void*)0},{&g_79,(void*)0,(void*)0,(void*)0},{&g_79,&g_79,&g_79,(void*)0}},{{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,(void*)0,(void*)0},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79},{&g_79,&g_79,&g_79,&g_79},{(void*)0,&g_79,&g_79,(void*)0}}}; + int i, j, k; + (*l_158) = l_115; + if (p_61) + continue; + (*l_103) = (l_159 && (&g_79 == l_160[9][0][1])); + } + for (l_133 = 0; (l_133 <= 2); l_133 += 1) + { /* block id: 57 */ + if (p_61) + break; + } + if ((safe_add_func_uint64_t_u_u(p_62, (~p_61)))) + { /* block id: 60 */ + struct S0 *l_165[6] = {&l_137[3],&l_137[3],&l_137[3],&l_137[3],&l_137[3],&l_137[3]}; + int i; + l_163 = &g_104; + g_143 = l_164; + return l_154; + } + else + { /* block id: 64 */ + if (l_166) + break; + } + } + } + for (g_118 = (-18); (g_118 != 23); g_118++) + { /* block id: 71 */ + uint32_t l_173 = 18446744073709551615UL; + int32_t l_175 = 0x730FBAA5L; + l_175 &= (((safe_mul_func_int8_t_s_s(g_70, l_130[0].f0)) && ((-6L) || ((safe_sub_func_int64_t_s_s(((p_61 && l_131[8].f1) , 0x8D45AB6B2BBD4C00LL), p_61)) | ((+(l_173 != (l_174 , 0UL))) > 0x14784E495FCC9BDCLL)))) < l_173); + } + } + if (p_61) + continue; + for (p_62 = 0; (p_62 <= 1); p_62 += 1) + { /* block id: 78 */ + uint32_t l_182 = 18446744073709551615UL; + uint8_t *l_221 = &g_189; + int32_t l_225 = 0x5969875FL; + for (g_118 = 0; (g_118 <= 1); g_118 += 1) + { /* block id: 81 */ + uint16_t l_193 = 0x88DAL; + struct S0 l_262 = {-329,0xD823L,0x47ADA87189E9F6B4LL}; + uint64_t l_263[10] = {18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL,18446744073709551615UL}; + int i; + for (l_101 = 1; (l_101 >= 0); l_101 -= 1) + { /* block id: 84 */ + int64_t l_183[10][10] = {{0xF287346C39F9920BLL,0xC145D4FDDE0D53B3LL,0x5BF0B686D89AF0E1LL,(-1L),(-1L),0x5BF0B686D89AF0E1LL,0xC145D4FDDE0D53B3LL,0xF287346C39F9920BLL,0x5BF0B686D89AF0E1LL,0xF287346C39F9920BLL},{(-1L),0L,0xF9883E6589940662LL,(-1L),0xF9883E6589940662LL,0L,(-1L),1L,1L,(-1L)},{1L,0xF287346C39F9920BLL,0xF9883E6589940662LL,0xF9883E6589940662LL,0xF287346C39F9920BLL,1L,0L,0xF287346C39F9920BLL,0L,1L},{0xC145D4FDDE0D53B3LL,0xF287346C39F9920BLL,0x5BF0B686D89AF0E1LL,0xF287346C39F9920BLL,0xC145D4FDDE0D53B3LL,0x5BF0B686D89AF0E1LL,(-1L),(-1L),0x5BF0B686D89AF0E1LL,0xC145D4FDDE0D53B3LL},{0xC145D4FDDE0D53B3LL,0L,0L,0xC145D4FDDE0D53B3LL,0xF9883E6589940662LL,1L,0xC145D4FDDE0D53B3LL,1L,0xF9883E6589940662LL,0xC145D4FDDE0D53B3LL},{1L,0xC145D4FDDE0D53B3LL,1L,0xF9883E6589940662LL,0xC145D4FDDE0D53B3LL,0L,0L,0xC145D4FDDE0D53B3LL,0xF9883E6589940662LL,1L},{(-1L),(-1L),0x5BF0B686D89AF0E1LL,0xC145D4FDDE0D53B3LL,0xF287346C39F9920BLL,0x5BF0B686D89AF0E1LL,0xF287346C39F9920BLL,0xC145D4FDDE0D53B3LL,0x5BF0B686D89AF0E1LL,(-1L)},{0xF287346C39F9920BLL,0L,1L,0xF287346C39F9920BLL,0xF9883E6589940662LL,0xF9883E6589940662LL,0xF287346C39F9920BLL,1L,0L,0xF287346C39F9920BLL},{1L,(-1L),0L,0xF9883E6589940662LL,(-1L),0xF9883E6589940662LL,0L,(-1L),1L,1L},{0xF287346C39F9920BLL,0xC145D4FDDE0D53B3LL,0x5BF0B686D89AF0E1LL,(-1L),(-1L),0x5BF0B686D89AF0E1LL,0xC145D4FDDE0D53B3LL,0xF287346C39F9920BLL,0x5BF0B686D89AF0E1LL,0xF287346C39F9920BLL}}; + uint32_t l_188 = 0x78527E74L; + int32_t *l_190[1][8][6]; + struct S0 l_220 = {-495,0L,-8L}; + uint64_t l_227 = 0x32DCA30394C6079CLL; + struct S1 **l_259 = (void*)0; + int i, j, k; + for (i = 0; i < 1; i++) + { + for (j = 0; j < 8; j++) + { + for (k = 0; k < 6; k++) + l_190[i][j][k] = &g_104; + } + } + g_104 = ((~((((((safe_div_func_int64_t_s_s((((p_61 == (safe_mod_func_uint64_t_u_u(p_62, (+(p_61 && 0x054C286EL))))) ^ (safe_sub_func_uint64_t_u_u((g_189 ^= (((((l_182 <= l_183[5][7]) | ((safe_add_func_uint16_t_u_u(4UL, (safe_mul_func_uint8_t_u_u((&l_156[l_101][(l_101 + 4)] != l_155[(l_101 + 1)]), 0xFBL)))) & p_62)) && 4294967288UL) >= 0x64536AC008CE353FLL) >= l_188)), 0UL))) , g_189), g_143.f2)) >= l_182) , p_62) != 0x1E4FL) != p_61) <= p_62)) == g_143.f0); + if (g_143.f0) + { /* block id: 87 */ + int i; + l_155[p_62] = g_191; + if (l_193) + break; + } + else + { /* block id: 90 */ + int32_t **l_194 = &l_190[0][0][4]; + int64_t *l_222 = (void*)0; + int64_t *l_223 = &l_183[5][7]; + int8_t *l_224 = (void*)0; + g_139 = ((*l_194) = p_63); + if (p_62) + continue; + l_228[6] &= (safe_rshift_func_int16_t_s_s((safe_lshift_func_uint8_t_u_s((((g_106[2] | (((((safe_sub_func_uint8_t_u_u(0UL, ((safe_sub_func_uint8_t_u_u((safe_sub_func_int8_t_s_s(g_97, (safe_rshift_func_int8_t_s_u((g_226[4] = (l_225 &= (safe_div_func_int16_t_s_s((((safe_add_func_uint16_t_u_u((safe_div_func_uint16_t_u_u(((g_213 , (+((*l_221) = ((safe_lshift_func_uint8_t_u_u(l_77, (0xA5D863CB28DBC522LL & (-1L)))) >= ((safe_div_func_int64_t_s_s(((*l_223) = (((safe_div_func_uint8_t_u_u((((l_220 , (void*)0) != l_221) , p_62), g_143.f1)) >= 0xEFL) , p_62)), p_62)) != l_174.f1))))) , p_61), 1UL)), g_106[1])) && p_62) <= p_62), 3UL)))), g_97)))), l_193)) | g_100))) >= l_193) != l_227) , g_213) , g_226[2])) ^ 0xCB368D48L) & l_182), 1)), p_61)); + l_229 = l_220; + } + g_143.f0 &= p_62; + for (g_189 = 0; (g_189 <= 1); g_189 += 1) + { /* block id: 104 */ + struct S1 **l_232 = &g_230; + uint8_t *l_237 = &g_106[3]; + struct S0 *l_245 = &l_229; + (*l_232) = g_230; + (*l_245) = (((safe_rshift_func_uint16_t_u_s(((safe_mul_func_uint8_t_u_u(((*l_237) = g_213.f1), p_62)) , 0x1D64L), (g_226[4] | ((safe_mul_func_int8_t_s_s((g_240 == &g_79), ((l_130[0].f0 ^= ((safe_sub_func_uint8_t_u_u(p_61, ((g_213 , (safe_mod_func_int64_t_s_s(g_231.f9, g_79))) != p_62))) <= l_229.f1)) != (*g_240)))) >= (*g_240))))) != (-7L)) , l_220); + (*l_245) = (l_246 , (((*g_240) = (safe_mul_func_uint8_t_u_u((g_249 , (safe_mul_func_int16_t_s_s((g_249 , (g_252[1] , (safe_rshift_func_uint16_t_u_s(((g_249 , (safe_add_func_uint16_t_u_u((safe_sub_func_uint8_t_u_u((l_259 == (void*)0), (+0UL))), (safe_mul_func_int16_t_s_s((l_262 , g_97), l_263[7]))))) & 5L), g_104)))), 0x33B7L))), l_225))) , l_262)); + } + } + } + } + return g_249.f2; + } + ++l_270; + (*l_264) &= ((((1L > g_249.f3) , ((l_273 , (((251UL == ((void*)0 == l_274)) != (safe_mul_func_uint8_t_u_u(((((((g_104 , 65531UL) , ((safe_unary_minus_func_uint32_t_u((safe_lshift_func_uint16_t_u_s(p_62, g_231.f3)))) > p_61)) != 65532UL) , p_63) != (void*)0) < 0x169B939CL), g_231.f1))) != (*g_240))) && 0L)) , l_280[8][2]) , p_61); + return p_61; +} + + + + +/* ---------------------------------------- */ +int main (int argc, char* argv[]) +{ + int i, j, k; + int print_hash_value = 0; + if (argc == 2 && strcmp(argv[1], "1") == 0) print_hash_value = 1; + platform_main_begin(); + crc32_gentab(); + func_1(); + transparent_crc(g_4, "g_4", print_hash_value); + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + for (k = 0; k < 1; k++) + { + transparent_crc(g_14[i][j][k], "g_14[i][j][k]", print_hash_value); + if (print_hash_value) printf("index = [%d][%d][%d]\n", i, j, k); + + } + } + } + for (i = 0; i < 4; i++) + { + transparent_crc(g_17[i], "g_17[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_18, "g_18", print_hash_value); + transparent_crc(g_70, "g_70", print_hash_value); + transparent_crc(g_79, "g_79", print_hash_value); + transparent_crc(g_97, "g_97", print_hash_value); + transparent_crc(g_100, "g_100", print_hash_value); + transparent_crc(g_104, "g_104", print_hash_value); + for (i = 0; i < 4; i++) + { + transparent_crc(g_106[i], "g_106[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_118, "g_118", print_hash_value); + transparent_crc(g_143.f0, "g_143.f0", print_hash_value); + transparent_crc(g_143.f1, "g_143.f1", print_hash_value); + transparent_crc(g_143.f2, "g_143.f2", print_hash_value); + transparent_crc(g_189, "g_189", print_hash_value); + transparent_crc(g_213.f0, "g_213.f0", print_hash_value); + transparent_crc(g_213.f1, "g_213.f1", print_hash_value); + transparent_crc(g_213.f2, "g_213.f2", print_hash_value); + for (i = 0; i < 6; i++) + { + transparent_crc(g_226[i], "g_226[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_231.f0, "g_231.f0", print_hash_value); + transparent_crc(g_231.f1, "g_231.f1", print_hash_value); + transparent_crc(g_231.f2, "g_231.f2", print_hash_value); + transparent_crc(g_231.f3, "g_231.f3", print_hash_value); + transparent_crc(g_231.f4, "g_231.f4", print_hash_value); + transparent_crc(g_231.f5, "g_231.f5", print_hash_value); + transparent_crc(g_231.f6, "g_231.f6", print_hash_value); + transparent_crc(g_231.f7, "g_231.f7", print_hash_value); + transparent_crc(g_231.f8, "g_231.f8", print_hash_value); + transparent_crc(g_231.f9, "g_231.f9", print_hash_value); + transparent_crc(g_249.f0, "g_249.f0", print_hash_value); + transparent_crc(g_249.f1, "g_249.f1", print_hash_value); + transparent_crc(g_249.f2, "g_249.f2", print_hash_value); + transparent_crc(g_249.f3, "g_249.f3", print_hash_value); + for (i = 0; i < 2; i++) + { + transparent_crc(g_252[i].f0, "g_252[i].f0", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_287, "g_287", print_hash_value); + transparent_crc(g_313.f0, "g_313.f0", print_hash_value); + transparent_crc(g_313.f1, "g_313.f1", print_hash_value); + transparent_crc(g_313.f2, "g_313.f2", print_hash_value); + transparent_crc(g_313.f3, "g_313.f3", print_hash_value); + transparent_crc(g_313.f4, "g_313.f4", print_hash_value); + transparent_crc(g_313.f5, "g_313.f5", print_hash_value); + transparent_crc(g_313.f6, "g_313.f6", print_hash_value); + transparent_crc(g_313.f7, "g_313.f7", print_hash_value); + transparent_crc(g_313.f8, "g_313.f8", print_hash_value); + transparent_crc(g_313.f9, "g_313.f9", print_hash_value); + transparent_crc(g_334, "g_334", print_hash_value); + transparent_crc(g_339, "g_339", print_hash_value); + transparent_crc(g_342, "g_342", print_hash_value); + transparent_crc(g_348, "g_348", print_hash_value); + transparent_crc(g_359, "g_359", print_hash_value); + transparent_crc(g_362, "g_362", print_hash_value); + transparent_crc(g_385.f0, "g_385.f0", print_hash_value); + transparent_crc(g_385.f1, "g_385.f1", print_hash_value); + transparent_crc(g_385.f2, "g_385.f2", print_hash_value); + transparent_crc(g_385.f3, "g_385.f3", print_hash_value); + transparent_crc(g_440, "g_440", print_hash_value); + transparent_crc(g_476, "g_476", print_hash_value); + for (i = 0; i < 3; i++) + { + for (j = 0; j < 7; j++) + { + for (k = 0; k < 1; k++) + { + transparent_crc(g_510[i][j][k], "g_510[i][j][k]", print_hash_value); + if (print_hash_value) printf("index = [%d][%d][%d]\n", i, j, k); + + } + } + } + transparent_crc(g_538, "g_538", print_hash_value); + transparent_crc(g_569, "g_569", print_hash_value); + transparent_crc(g_584.f0, "g_584.f0", print_hash_value); + transparent_crc(g_584.f1, "g_584.f1", print_hash_value); + transparent_crc(g_584.f2, "g_584.f2", print_hash_value); + transparent_crc(g_586.f0, "g_586.f0", print_hash_value); + transparent_crc(g_586.f1, "g_586.f1", print_hash_value); + transparent_crc(g_586.f2, "g_586.f2", print_hash_value); + transparent_crc(g_588.f0, "g_588.f0", print_hash_value); + transparent_crc(g_588.f1, "g_588.f1", print_hash_value); + transparent_crc(g_588.f2, "g_588.f2", print_hash_value); + for (i = 0; i < 9; i++) + { + transparent_crc(g_629[i], "g_629[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_677, "g_677", print_hash_value); + transparent_crc(g_689, "g_689", print_hash_value); + transparent_crc(g_723, "g_723", print_hash_value); + transparent_crc(g_733, "g_733", print_hash_value); + transparent_crc(g_736.f0, "g_736.f0", print_hash_value); + transparent_crc(g_736.f1, "g_736.f1", print_hash_value); + transparent_crc(g_736.f2, "g_736.f2", print_hash_value); + for (i = 0; i < 3; i++) + { + transparent_crc(g_846[i], "g_846[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_861, "g_861", print_hash_value); + transparent_crc(g_900.f0, "g_900.f0", print_hash_value); + transparent_crc(g_900.f1, "g_900.f1", print_hash_value); + transparent_crc(g_900.f2, "g_900.f2", print_hash_value); + transparent_crc(g_900.f3, "g_900.f3", print_hash_value); + platform_main_end(crc32_context ^ 0xFFFFFFFFUL, print_hash_value); + return 0; +} + +/************************ statistics ************************* +XXX max struct depth: 1 +breakdown: + depth: 0, occurrence: 200 + depth: 1, occurrence: 33 +XXX total union variables: 12 + +XXX non-zero bitfields defined in structs: 11 +XXX zero bitfields defined in structs: 0 +XXX const bitfields defined in structs: 3 +XXX volatile bitfields defined in structs: 0 +XXX structs with bitfields in the program: 39 +breakdown: + indirect level: 0, occurrence: 25 + indirect level: 1, occurrence: 5 + indirect level: 2, occurrence: 8 + indirect level: 3, occurrence: 1 +XXX full-bitfields structs in the program: 4 +breakdown: + indirect level: 0, occurrence: 4 +XXX times a bitfields struct's address is taken: 16 +XXX times a bitfields struct on LHS: 9 +XXX times a bitfields struct on RHS: 32 +XXX times a single bitfield on LHS: 13 +XXX times a single bitfield on RHS: 47 + +XXX max expression depth: 59 +breakdown: + depth: 1, occurrence: 232 + depth: 2, occurrence: 49 + depth: 3, occurrence: 5 + depth: 4, occurrence: 3 + depth: 5, occurrence: 3 + depth: 6, occurrence: 1 + depth: 7, occurrence: 2 + depth: 8, occurrence: 1 + depth: 11, occurrence: 1 + depth: 12, occurrence: 1 + depth: 14, occurrence: 1 + depth: 15, occurrence: 2 + depth: 16, occurrence: 3 + depth: 17, occurrence: 3 + depth: 18, occurrence: 2 + depth: 19, occurrence: 6 + depth: 20, occurrence: 2 + depth: 21, occurrence: 1 + depth: 22, occurrence: 3 + depth: 23, occurrence: 3 + depth: 24, occurrence: 2 + depth: 25, occurrence: 1 + depth: 26, occurrence: 1 + depth: 28, occurrence: 1 + depth: 29, occurrence: 1 + depth: 32, occurrence: 1 + depth: 35, occurrence: 1 + depth: 37, occurrence: 1 + depth: 59, occurrence: 1 + +XXX total number of pointers: 241 + +XXX times a variable address is taken: 671 +XXX times a pointer is dereferenced on RHS: 71 +breakdown: + depth: 1, occurrence: 48 + depth: 2, occurrence: 23 +XXX times a pointer is dereferenced on LHS: 97 +breakdown: + depth: 1, occurrence: 93 + depth: 2, occurrence: 4 +XXX times a pointer is compared with null: 18 +XXX times a pointer is compared with address of another variable: 6 +XXX times a pointer is compared with another pointer: 5 +XXX times a pointer is qualified to be dereferenced: 1851 + +XXX max dereference level: 3 +breakdown: + level: 0, occurrence: 0 + level: 1, occurrence: 278 + level: 2, occurrence: 63 + level: 3, occurrence: 1 +XXX number of pointers point to pointers: 59 +XXX number of pointers point to scalars: 155 +XXX number of pointers point to structs: 15 +XXX percent of pointers has null in alias set: 31.1 +XXX average alias set size: 1.48 + +XXX times a non-volatile is read: 735 +XXX times a non-volatile is write: 363 +XXX times a volatile is read: 0 +XXX times read thru a pointer: 0 +XXX times a volatile is write: 0 +XXX times written thru a pointer: 0 +XXX times a volatile is available for access: 0 +XXX percentage of non-volatile access: 100 + +XXX forward jumps: 0 +XXX backward jumps: 1 + +XXX stmts: 218 +XXX max block depth: 5 +breakdown: + depth: 0, occurrence: 26 + depth: 1, occurrence: 27 + depth: 2, occurrence: 31 + depth: 3, occurrence: 43 + depth: 4, occurrence: 36 + depth: 5, occurrence: 55 + +XXX percentage a fresh-made variable is used: 20.7 +XXX percentage an existing variable is used: 79.3 +FYI: the random generator makes assumptions about the integer size. See platform.info for more details. +********************* end of statistics **********************/ + diff --git a/tests/fuzz/22.c.txt b/tests/fuzz/22.c.txt new file mode 100644 index 0000000000000..482d0c3eec7f3 --- /dev/null +++ b/tests/fuzz/22.c.txt @@ -0,0 +1 @@ +checksum = 95563BAB diff --git a/tests/gl_textures.cpp b/tests/gl_textures.cpp new file mode 100644 index 0000000000000..c309b7bc6b258 --- /dev/null +++ b/tests/gl_textures.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include +#include + +void report_result(int result) +{ + if (result == 0) { + printf("Test successful!\n"); + } else { + printf("Test failed!\n"); + } +#ifdef REPORT_RESULT + REPORT_RESULT(); +#endif +} + +GLuint program; + +#define PIX_C(x, y) ((x)/256.0f + (y)/256.0f) +#define CLAMP(c) ((c) < 0.f ? 0.f : ((c) > 1.f ? 1.f : (c))) +#define PIX(x, y) CLAMP(PIX_C(x, y)) + +void draw() +{ + int w, h, fs; + emscripten_get_canvas_size(&w, &h, &fs); + float xs = (float)h / w; + float ys = 1.0f; + float mat[] = { xs, 0, 0, 0, 0, ys, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + glUniformMatrix4fv(glGetUniformLocation(program, "mat"), 1, 0, mat); + glClearColor(0,0,1,1); + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_TRIANGLES, 0, 6); + + unsigned char imageData[256*256*4]; + glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, imageData); + for(int y = 0; y < 256; ++y) + for(int x = 0; x < 256; ++x) + { + unsigned char red = imageData[(y*256+x)*4]; + float expectedRed = PIX(x, y); + unsigned char eRed = (unsigned char)(expectedRed * 255.0f); + assert(fabs((int)eRed - red) <= 2); + } + emscripten_cancel_main_loop(); + report_result(0); +} + +int main() +{ + emscripten_set_canvas_size(256, 256); + EmscriptenWebGLContextAttributes attr; + emscripten_webgl_init_context_attributes(&attr); + attr.alpha = attr.depth = attr.stencil = attr.antialias = attr.preserveDrawingBuffer = attr.preferLowPowerToHighPerformance = attr.failIfMajorPerformanceCaveat = 0; + attr.enableExtensionsByDefault = 1; + attr.premultipliedAlpha = 0; + attr.majorVersion = 1; + attr.minorVersion = 0; + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(0, &attr); + emscripten_webgl_make_context_current(ctx); + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + const char *vss = "attribute vec4 vPosition; uniform mat4 mat; varying vec2 texCoord; void main() { gl_Position = vPosition; texCoord = (vPosition.xy + vec2(1.0)) * vec2(0.5); }"; + glShaderSource(vs, 1, &vss, 0); + glCompileShader(vs); + GLint isCompiled = 0; + glGetShaderiv(vs, GL_COMPILE_STATUS, &isCompiled); + if (!isCompiled) + { + GLint maxLength = 0; + glGetShaderiv(vs, GL_INFO_LOG_LENGTH, &maxLength); + char *buf = new char[maxLength]; + glGetShaderInfoLog(vs, maxLength, &maxLength, buf); + printf("%s\n", buf); + return 0; + } + + GLuint ps = glCreateShader(GL_FRAGMENT_SHADER); + const char *pss = "precision lowp float; varying vec2 texCoord; uniform vec3 colors[3]; uniform sampler2D tex; void main() { gl_FragColor = texture2D(tex, texCoord); }"; + glShaderSource(ps, 1, &pss, 0); + glCompileShader(ps); + glGetShaderiv(ps, GL_COMPILE_STATUS, &isCompiled); + if (!isCompiled) + { + GLint maxLength = 0; + glGetShaderiv(ps, GL_INFO_LOG_LENGTH, &maxLength); + char *buf = new char[maxLength]; + glGetShaderInfoLog(ps, maxLength, &maxLength, buf); + printf("%s\n", buf); + return 0; + } + + program = glCreateProgram(); + glAttachShader(program, vs); + glAttachShader(program, ps); + glBindAttribLocation(program, 0, "vPosition"); + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &isCompiled); + if (!isCompiled) + { + GLint maxLength = 0; + glGetShaderiv(program, GL_INFO_LOG_LENGTH, &maxLength); + char *buf = new char[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, buf); + printf("%s\n", buf); + return 0; + } + + glUseProgram(program); + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + + float verts[] = { -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1 }; + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, 0, sizeof(float)*2, 0); + glEnableVertexAttribArray(0); + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + float texData[256*256]; + for(int y = 0; y < 256; ++y) + for(int x = 0; x < 256; ++x) + { + texData[y*256+x] = PIX(x, y); + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 256, 256, 0, GL_LUMINANCE, GL_FLOAT, texData); + emscripten_set_main_loop(draw, 0, 0); + return 0; +} diff --git a/tests/runner.py b/tests/runner.py index e223a7300dc9b..61d49d74e5c84 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -329,7 +329,8 @@ def assertTextDataContained(self, text1, text2): def assertContained(self, values, string, additional_info=''): if type(values) not in [list, tuple]: values = [values] for value in values: - if type(string) is not str: string = string() + if type(value) is unicode: string = string.decode('UTF-8') # If we have any non-ASCII chars in the expected string, treat the test string from ASCII as UTF8 as well. + if type(string) is not str and type(string) is not unicode: string = string() if value in string: return # success raise Exception("Expected to find '%s' in '%s', diff:\n\n%s\n%s" % ( limit_size(values[0]), limit_size(string), diff --git a/tests/test_browser.py b/tests/test_browser.py index 61a0bb5b4f982..51f257412a6a4 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1138,6 +1138,10 @@ def test_webgl_context_attributes(self): def test_emscripten_get_now(self): self.btest('emscripten_get_now.cpp', '1') + def test_fflush(self): + return self.skip('Skipping due to https://github.com/kripken/emscripten/issues/2770') + self.btest('test_fflush.cpp', '0', args=['-s', 'NO_EXIT_RUNTIME=1', '--shell-file', path_from_root('tests', 'test_fflush.html')]) + def test_file_db(self): secret = str(time.time()) open('moar.txt', 'w').write(secret) @@ -1498,6 +1502,9 @@ def test_sdlglshader2(self): def test_gl_glteximage(self): self.btest('gl_teximage.c', '1') + def test_gl_textures(self): + self.btest('gl_textures.cpp', '0') + def test_gl_ps(self): # pointers and a shader shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) diff --git a/tests/test_core.py b/tests/test_core.py index fd5d1ccd46416..7e297b434094f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4931,6 +4931,20 @@ def test_js_libraries(self): self.emcc_args += ['--js-library', os.path.join(self.get_dir(), 'mylib1.js'), '--js-library', os.path.join(self.get_dir(), 'mylib2.js')] self.do_run(open(os.path.join(self.get_dir(), 'main.cpp'), 'r').read(), 'hello from lib!\n*32*\n') + def test_unicode_js_library(self): + open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(''' + #include + extern "C" { + extern void printey(); + } + int main() { + printey(); + return 0; + } + ''') + self.emcc_args += ['--js-library', path_from_root('tests', 'unicode_library.js')] + self.do_run(open(os.path.join(self.get_dir(), 'main.cpp'), 'r').read(), u'Unicode snowman \u2603 says hello!') + def test_constglobalunion(self): if self.emcc_args is None: return self.skip('needs emcc') self.emcc_args += ['-s', 'EXPORT_ALL=1'] @@ -5144,6 +5158,17 @@ def test_cubescript(self): main = main[:main.find('\n}')] assert main.count('\n') <= 7, ('must not emit too many postSets: %d' % main.count('\n')) + ' : ' + main + # Tests the full SSE1 API. + def test_sse1(self): + return self.skip('TODO: This test fails due to bugs #2840, #3044, #3045, #3046 and #3048 (also see #3043 and #3049)') + if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate + Settings.PRECISE_F32 = 1 # SIMD currently requires Math.fround + + orig_args = self.emcc_args + for mode in [[], ['-s', 'SIMD=1']]: + self.emcc_args = orig_args + mode + self.do_run(open(path_from_root('tests', 'test_sse1.cpp'), 'r').read(), 'Success!') + def test_simd(self): if self.is_emterpreter(): return self.skip('todo') if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('needs fastcomp') @@ -5216,8 +5241,10 @@ def test_simd6(self): def test_simd7(self): # test_simd7 is to test negative zero handling. + if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('needs fastcomp') + if self.is_emterpreter(): return self.skip('todo') test_path = path_from_root('tests', 'core', 'test_simd7') src, output = (test_path + s for s in ('.in', '.out')) @@ -5735,7 +5762,7 @@ def run_all(x): #if os.path.basename(name) != '4.c': continue if 'newfail' in name: continue if os.environ.get('EMCC_FAST_COMPILER') == '0' and os.path.basename(name) in [ - '18.cpp', '15.c', '21.c' + '18.cpp', '15.c', '21.c', '22.c' ]: continue # works only in fastcomp if x == 'lto' and self.run_name == 'default' and os.path.basename(name) in [ '19.c', '18.cpp' @@ -5863,6 +5890,8 @@ def test_corruption_3(self): ### Integration tests def test_ccall(self): + if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('needs fastcomp') + post = ''' def process(filename): src = \'\'\' @@ -5890,19 +5919,19 @@ def process(filename): Module.print(multi(2, 1.4, 3, 'atr')); Module.print(multi(8, 5.4, 4, 'bret')); Module.print('*'); - // part 3: avoid stack explosion + // part 3: avoid stack explosion and check it's restored correctly for (var i = 0; i < TOTAL_STACK/60; i++) { ccall('multi', 'number', ['number', 'number', 'number', 'string'], [0, 0, 0, '123456789012345678901234567890123456789012345678901234567890']); } Module.print('stack is ok.'); + ccall('call_ccall_again', null); }); Module.callMain(); \'\'\' open(filename, 'w').write(src) ''' - Settings.EXPORTED_FUNCTIONS += ['_get_int', '_get_float', '_get_string', '_print_int', '_print_float', '_print_string', '_multi', '_pointer', '_malloc'] - + Settings.EXPORTED_FUNCTIONS += ['_get_int', '_get_float', '_get_string', '_print_int', '_print_float', '_print_string', '_multi', '_pointer', '_call_ccall_again', '_malloc'] test_path = path_from_root('tests', 'core', 'test_ccall') src, output = (test_path + s for s in ('.in', '.out')) diff --git a/tests/test_fflush.cpp b/tests/test_fflush.cpp new file mode 100644 index 0000000000000..623c69ebc7037 --- /dev/null +++ b/tests/test_fflush.cpp @@ -0,0 +1,13 @@ +#include +#include + +int main() +{ + std::cout << "Print in " << "two parts." << '\n'; + std::cerr << "std::cerr in " << "two parts." << '\n'; + + printf("hello!"); + fflush(stdout); + fprintf(stderr, "hello from stderr too!"); + fflush(stderr); +} diff --git a/tests/test_fflush.html b/tests/test_fflush.html new file mode 100644 index 0000000000000..8065717eca8fa --- /dev/null +++ b/tests/test_fflush.html @@ -0,0 +1,165 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + {{{ SCRIPT }}} + + diff --git a/tests/test_other.py b/tests/test_other.py index 0fbd4b401eba6..6b5807f05ee9e 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1905,13 +1905,15 @@ def test_js_optimizer(self): ['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(), ['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(), + (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()], ['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(), ['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(), ['asm', 'asmPreciseF32', 'optimizeFrounds']), - (path_from_root('tools', 'test-js-optimizer-asm-last.js'), open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(), + (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()], + ['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()], ['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(), ['asm', 'relocate']), @@ -1933,13 +1935,25 @@ def test_js_optimizer(self): ['asm', 'ensureLabelSet']), ]: print input, passes + + if type(expected) == str: expected = [expected] + expected = map(lambda out: out.replace('\n\n', '\n').replace('\n\n', '\n'), expected) + # test calling js optimizer print ' js' output = Popen(NODE_JS + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] - self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n')) + + def check_js(js): + self.assertIdentical(expected, js.replace('\r\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')) + check_js(output) + if js_optimizer.use_native(passes): # test calling native - print ' native' + def check_json(): + Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), output_temp, 'receiveJSON'], stdin=PIPE, stdout=open(output_temp + '.js', 'w')).communicate() + output = open(output_temp + '.js').read() + self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')) + self.clear() input_temp = 'temp.js' output_temp = 'output.js' @@ -1950,10 +1964,19 @@ def test_js_optimizer(self): json = open(input_temp + '.js').read() json += '\n' + original[original.find('// EXTRA_INFO:'):] open(input_temp + '.js', 'w').write(json) - output = Popen([js_optimizer.get_native_optimizer(), input_temp + '.js'] + passes, stdin=PIPE, stdout=open(output_temp, 'w')).communicate()[0] - Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), output_temp, 'receiveJSON'], stdin=PIPE, stdout=open(output_temp + '.js', 'w')).communicate() - output = open(output_temp + '.js').read() - self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n')) + + if 'last' not in passes: # last is only relevant when we emit JS + print ' native (receiveJSON)' + output = Popen([js_optimizer.get_native_optimizer(), input_temp + '.js'] + passes + ['receiveJSON', 'emitJSON'], stdin=PIPE, stdout=open(output_temp, 'w')).communicate()[0] + check_json() + + print ' native (parsing JS)' + output = Popen([js_optimizer.get_native_optimizer(), input] + passes + ['emitJSON'], stdin=PIPE, stdout=open(output_temp, 'w')).communicate()[0] + check_json() + + print ' native (emitting JS)' + output = Popen([js_optimizer.get_native_optimizer(), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] + check_js(output) def test_m_mm(self): open(os.path.join(self.get_dir(), 'foo.c'), 'w').write('''#include ''') @@ -4397,20 +4420,25 @@ def test_require(self): assert output == ('hello, world!\n \n', ''), 'expected no output, got\n===\nSTDOUT\n%s\n===\nSTDERR\n%s\n===\n' % output def test_native_optimizer(self): - old_debug = os.environ.get('EMCC_DEBUG') - old_native = os.environ.get('EMCC_NATIVE_OPTIMIZER') - try: - os.environ['EMCC_DEBUG'] = '1' - os.environ['EMCC_NATIVE_OPTIMIZER'] = '1' - out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O2'], stderr=PIPE).communicate() - finally: - if old_debug: os.environ['EMCC_DEBUG'] = old_debug - else: del os.environ['EMCC_DEBUG'] - if old_native: os.environ['EMCC_NATIVE_OPTIMIZER'] = old_native - else: del os.environ['EMCC_NATIVE_OPTIMIZER'] - self.assertContained('js optimizer using native', err) - assert os.path.exists('a.out.js'), err - self.assertContained('hello, world!', run_js('a.out.js')) + def test(args, expected): + print args, expected + old_debug = os.environ.get('EMCC_DEBUG') + old_native = os.environ.get('EMCC_NATIVE_OPTIMIZER') + try: + os.environ['EMCC_DEBUG'] = '1' + os.environ['EMCC_NATIVE_OPTIMIZER'] = '1' + out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O2',] + args, stderr=PIPE).communicate() + finally: + if old_debug: os.environ['EMCC_DEBUG'] = old_debug + else: del os.environ['EMCC_DEBUG'] + if old_native: os.environ['EMCC_NATIVE_OPTIMIZER'] = old_native + else: del os.environ['EMCC_NATIVE_OPTIMIZER'] + assert err.count('js optimizer using native') == expected, [err, expected] + assert os.path.exists('a.out.js'), err + self.assertContained('hello, world!', run_js('a.out.js')) + + test([], 1) + test(['-s', 'OUTLINING_LIMIT=100000'], 2) # 2, because we run them before and after outline, which is non-native def test_emconfigure_js_o(self): # issue 2994 @@ -4422,3 +4450,46 @@ def test_emconfigure_js_o(self): finally: del os.environ['EMCONFIGURE_JS'] + def test_emcc_c_multi(self): + def test(args, llvm_opts=None): + print args + lib = r''' + int mult() { return 1; } + ''' + + lib_name = 'libA.c' + open(lib_name, 'w').write(lib) + main = r''' + #include + int mult(); + int main() { + printf("result: %d\n", mult()); + return 0; + } + ''' + main_name = 'main.c' + open(main_name, 'w').write(main) + + if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode') + try: + os.environ['EMCC_DEBUG'] = '1' + out, err = Popen([PYTHON, EMCC, '-c', main_name, lib_name] + args, stderr=PIPE).communicate() + finally: + del os.environ['EMCC_DEBUG'] + + if args: + assert err.count('-disable-vectorize') == 2, err # specified twice, once per file + + assert err.count('emcc: LLVM opts: ' + llvm_opts + ' -disable-vectorize') == 2, err # exactly once per invocation of optimizer + else: + assert err.count('-disable-vectorize') == 0, err # no optimizations + + Popen([PYTHON, EMCC, main_name.replace('.c', '.o'), lib_name.replace('.c', '.o')]).communicate() + + self.assertContained('result: 1', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + + test([]) + test(['-O2'], '-O3') + test(['-Oz'], '-Oz') + test(['-Os'], '-Os') + diff --git a/tests/test_sanity.py b/tests/test_sanity.py index d877e66334b09..24b352be3778f 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -617,3 +617,79 @@ def second_use(): second_use() + def test_native_optimizer(self): + restore() + Cache.erase() + + def build(): + return self.check_working([EMCC, '-O2', 'tests/hello_world.c'], 'running js post-opts') + + def test(): + self.assertContained('hello, world!', run_js('a.out.js')) + + try: + os.environ['EMCC_DEBUG'] = '1' + + # basic usage or lack of usage + for native in [None, 0, 1]: + print native + 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) + test() + if native: + assert 'building native optimizer' in output + # compile again, no rebuild of optimizer + output = build() + assert 'building native optimizer' not in output + assert 'js optimizer using native' in output + test() + finally: + if native is not None: del os.environ['EMCC_NATIVE_OPTIMIZER'] + + # force a build failure, see we fall back to non-native + + Cache.erase() + + try: + os.environ['EMCC_NATIVE_OPTIMIZER'] = '1' + + try: + # break it + f = path_from_root('tools', 'optimizer', 'optimizer.cpp') + src = open(f).read() + bad = src.replace('main', '!waka waka<') + assert bad != src + open(f, 'w').write(bad) + # first try + output = build() + assert 'failed to build native optimizer' in output, output + assert 'js optimizer using native' not in output + test() # still works, without native optimizer + # second try, see previous failure + output = build() + assert 'failed to build native optimizer' not in output + assert 'seeing that optimizer could not be built' in output + test() # still works, without native optimizer + # clear cache, try again + Cache.erase() + output = build() + assert 'failed to build native optimizer' in output + test() # still works, without native optimizer + finally: + open(f, 'w').write(src) + + Cache.erase() + + # now it should work again + output = build() + assert 'js optimizer using native' in output + test() # still works, without native optimizer + + finally: + os.environ['EMCC_NATIVE_OPTIMIZER'] = '0' + + finally: + del os.environ['EMCC_DEBUG'] + diff --git a/tests/test_sse1.cpp b/tests/test_sse1.cpp new file mode 100644 index 0000000000000..2fd2e937bd93f --- /dev/null +++ b/tests/test_sse1.cpp @@ -0,0 +1,395 @@ +// This file tests full SSE1 compatibility. +// Compile with something like 'clang -msse test_sse1.cpp -o a.out' to build natively, and run './a.out'. +// To test with Emscripten, compile with 'emcc test_sse1.cpp -o a.js' (or -o a.html) and run in SpiderMonkey/node.js/browser. + +#include // Strictly include only this header, which contains the SSE1 intrinsics. Don't include other *intrin.h in this file to not pollute. +#include +#include +#include +#include +#include + +// If defined, tests the section of the SSE1 api that interfaces with the MMX instruction set. +#ifndef __EMSCRIPTEN__ +#define TEST_M64 +#endif + +// Use custom assert macro so that this test is independent to #define NDEBUG and similar. +#define Assert(X) do { if (!(X)) { fprintf(stderr, "Condition '" #X "' failed!\n"); ++numFailures; } } while(0) + +int numFailures = 0; + +// Throughout the file, the notation { a,b,c,d } refers to in-memory array notation, i.e. a is in the lowest memory address, and d is in the highest. +// The notation [a,b,c,d] refers to SIMD channels, where d is the lowest channel 0 (the scalar channel), and a is the highest channel 3. +// Some of the intrinsics in SSE1 augment the previous MMX intrinsics set. Those are marked with a /*M64*/ prefix. + +// Tests if m == [v3, v2, v1, v0] +bool __attribute__((noinline)) aeq_(const char *func, __m128 m, float v3, float v2, float v1, float v0, bool abortOnFailure = true) +{ + float val[4]; + _mm_storeu_ps(val, m); + bool eq = fabs(val[0]-v0) < 1e-5f && fabs(val[1]-v1) < 1e-5f && fabs(val[2]-v2) < 1e-5f && fabs(val[3]-v3) < 1e-5f; + if (!eq && abortOnFailure) + { + fprintf(stderr, "%s failed! [%g, %g, %g, %g] != [%g, %g, %g, %g]\n", func, val[3], val[2], val[1], val[0], v3, v2, v1, v0); + ++numFailures; + } + return eq; +} +#define aeq(m, v3, v2, v1, v0) aeq_(#m, m, v3, v2, v1, v0) + +#ifdef TEST_M64 +bool __attribute__((noinline)) aeq64(__m64 m, uint64_t u, bool abortOnFailure = true) +{ + union { __m64 m; uint64_t u; } c; c.m = m; + bool eq = (c.u == u); + if (!eq && abortOnFailure) + { + fprintf(stderr, "0x%llx != 0x%llx\n", c.u, u); + ++numFailures; + } + return eq; +} +#endif + +// Tests if m == [v3, v2, v1, v0] but where vx are integers. +bool __attribute__((noinline)) aeqi_(const char *func, __m128 m, uint32_t v3, uint32_t v2, uint32_t v1, uint32_t v0, bool abortOnFailure = true) +{ + uint32_t val[4]; + _mm_storeu_ps((float*)val, m); + bool eq = val[0] == v0 && val[1] == v1 && val[2] == v2 && val[3] == v3; + if (!eq && abortOnFailure) + { + fprintf(stderr, "%s failed! [0x%08x, 0x%08x, 0x%08x, 0x%08x] != [0x%08x, 0x%08x, 0x%08x, 0x%08x]\n", func, val[3], val[2], val[1], val[0], v3, v2, v1, v0); + ++numFailures; + } + return eq; +} + +#define aeqi(m, v3, v2, v1, v0) aeqi_(#m, m, v3, v2, v1, v0) + +// Recasts floating point representation of f to an integer. +uint32_t fcastu(float f) { return *(uint32_t*)&f; } +float ucastf(uint32_t t) { return *(float*)&t; } + +#ifdef TEST_M64 +// uint64_t -> __m64. (This is identical to _m_from_int64, but don't want to include mmintrin.h since this is strictly a SSE1 test suite) +__m64 u64castm64(uint64_t x) { union { __m64 m; uint64_t u; } c; c.u = x; return c.m; } +#endif + +// Data used in test. Store them global and access via a getter to confuse optimizer to not "solve" the whole test suite at compile-time, +// so that the operation will actually be performed at runtime, and not at compile-time. (Testing the capacity of the compiler to perform +// SIMD ops at compile-time would be interesting as well, but that's for another test) +float arr_[9]; +float *uarr_ = arr_+1; // Create an unaligned address to test unaligned loads. +float arr2_[9]; // A target for testing aligned stores. +float *uarr2_ = arr2_+1; // An unaligned address for testing unaligned stores. +__m128 a_ = _mm_set_ps(8.f, 6.f, 4.f, 2.f); +__m128 b_ = _mm_set_ps(1.f, 2.f, 3.f, 4.f); +__m128 c_ = _mm_set_ps(1.5f, 2.5f, 3.5f, 4.5f); +__m128 d_ = _mm_set_ps(8.5f, 6.5f, 4.5f, 2.5f); +__m128 e_ = _mm_set_ps(INFINITY, -INFINITY, 2.5f, 3.5f); +__m128 f_ = _mm_set_ps(-1.5f, 1.5f, -2.5f, -9223372036854775808.f); +__m128 nan1_ = _mm_set_ps(NAN, 0, 0, NAN); // All combinations pairwise with nan1 & nan2. +__m128 nan2_ = _mm_set_ps(NAN, NAN, 0, 0); + +bool always_true() { return time(NULL) != 0; } // This function always returns true, but the compiler should not know this. + +// Accessors to the test data in a way that the compiler can't optimize at compile-time. +__attribute__((noinline)) float *get_arr() +{ + float *a = (float*)(((uintptr_t)arr_ + 0xF) & ~0xF); + a[0] = 1.f; + a[1] = 2.f; + a[2] = 3.f; + a[3] = 4.f; + a[4] = 5.f; + + return always_true() ? a : 0; +} + +__attribute__((noinline)) float *get_uarr() { return always_true() ? get_arr()+1 : 0; } +__attribute__((noinline)) float *get_arr2() { return always_true() ? (float*)(((uintptr_t)arr2_ + 0xF) & ~0xF) : 0; } +__attribute__((noinline)) float *get_uarr2() { return always_true() ? get_arr2()+1 : 0; } +__attribute__((noinline)) __m128 get_a() { return always_true() ? a_ : __m128(); } +__attribute__((noinline)) __m128 get_b() { return always_true() ? b_ : __m128(); } +__attribute__((noinline)) __m128 get_c() { return always_true() ? c_ : __m128(); } +__attribute__((noinline)) __m128 get_d() { return always_true() ? d_ : __m128(); } +__attribute__((noinline)) __m128 get_e() { return always_true() ? e_ : __m128(); } +__attribute__((noinline)) __m128 get_f() { return always_true() ? f_ : __m128(); } +__attribute__((noinline)) __m128 get_i1() { return always_true() ? _mm_set_ps(ucastf(0x87654321), ucastf(0x0FEDCBA9), ucastf(0x87654321), ucastf(0xFFEDCBA9)) : __m128(); } +__attribute__((noinline)) __m128 get_i2() { return always_true() ? _mm_set_ps(ucastf(0xBBAA9988), ucastf(0xFFEEDDCC), ucastf(0xF02468BD), ucastf(0x13579ACE)) : __m128(); } +__attribute__((noinline)) __m128 get_nan1() { return always_true() ? nan1_ : __m128(); } +__attribute__((noinline)) __m128 get_nan2() { return always_true() ? nan2_ : __m128(); } +#ifdef TEST_M64 +__attribute__((noinline)) __m64 get_m1() { return always_true() ? u64castm64(0x00FF800110F0377FULL) : __m64(); } +__attribute__((noinline)) __m64 get_m2() { return always_true() ? u64castm64(0xFEDCBA9876543210ULL) : __m64(); } +#endif + +int main() +{ + float *arr = get_arr(); // [4, 3, 2, 1] + float *uarr = get_uarr(); // [5, 4, 3, 2] + float *arr2 = get_arr2(); // [4, 3, 2, 1] + float *uarr2 = get_uarr2(); // [5, 4, 3, 2] + __m128 a = get_a(); // [8, 6, 4, 2] + __m128 b = get_b(); // [1, 2, 3, 4] + + // Check that test data is like expected. + Assert(((uintptr_t)arr & 0xF) == 0); // arr must be aligned by 16. + Assert(((uintptr_t)uarr & 0xF) != 0); // uarr must be unaligned. + Assert(((uintptr_t)arr2 & 0xF) == 0); // arr must be aligned by 16. + Assert(((uintptr_t)uarr2 & 0xF) != 0); // uarr must be unaligned. + + // Test that aeq itself works and does not trivially return true on everything. + Assert(aeq_("",_mm_load_ps(arr), 4.f, 3.f, 2.f, 0.f, false) == false); +#ifdef TEST_M64 + Assert(aeq64(u64castm64(0x22446688AACCEEFFULL), 0xABABABABABABABABULL, false) == false); +#endif + // SSE1 Load instructions: + aeq(_mm_load_ps(arr), 4.f, 3.f, 2.f, 1.f); // 4-wide load from aligned address. + aeq(_mm_load_ps1(uarr), 2.f, 2.f, 2.f, 2.f); // Load scalar from unaligned address and populate 4-wide. + aeq(_mm_load_ss(uarr), 0.f, 0.f, 0.f, 2.f); // Load scalar from unaligned address to lowest, and zero all highest. + aeq(_mm_load1_ps(uarr), 2.f, 2.f, 2.f, 2.f); // _mm_load1_ps == _mm_load_ps1 + aeq(_mm_loadh_pi(a, (__m64*)uarr), 3.f, 2.f, 4.f, 2.f); // Load two highest addresses, preserve two lowest. + aeq(_mm_loadl_pi(a, (__m64*)uarr), 8.f, 6.f, 3.f, 2.f); // Load two lowest addresses, preserve two highest. + aeq(_mm_loadr_ps(arr), 1.f, 2.f, 3.f, 4.f); // 4-wide load from an aligned address, but reverse order. + aeq(_mm_loadu_ps(uarr), 5.f, 4.f, 3.f, 2.f); // 4-wide load from an unaligned address. + + // SSE1 Set instructions: + aeq(_mm_set_ps(uarr[3], 2.f, 3.f, 4.f), 5.f, 2.f, 3.f, 4.f); // 4-wide set by specifying four immediate or memory operands. + aeq(_mm_set_ps1(uarr[3]), 5.f, 5.f, 5.f, 5.f); // 4-wide set by specifying one scalar that is expanded. + aeq(_mm_set_ss(uarr[3]), 0.f, 0.f, 0.f, 5.f); // Set scalar at lowest index, zero all higher. + aeq(_mm_set1_ps(uarr[3]), 5.f, 5.f, 5.f, 5.f); // _mm_set1_ps == _mm_set_ps1 + aeq(_mm_setr_ps(uarr[3], 2.f, 3.f, 4.f), 4.f, 3.f, 2.f, 5.f); // 4-wide set by specifying four immediate or memory operands, but reverse order. + aeq(_mm_setzero_ps(), 0.f, 0.f, 0.f, 0.f); // Returns a new zero register. + + // SSE1 Move instructions: + aeq(_mm_move_ss(a, b), 8.f, 6.f, 4.f, 4.f); // Copy three highest elements from a, and lowest from b. + aeq(_mm_movehl_ps(a, b), 8.f, 6.f, 1.f, 2.f); // Copy two highest elements from a, and take two highest from b and place them to the two lowest in output. + aeq(_mm_movelh_ps(a, b), 3.f, 4.f, 4.f, 2.f); // Copy two lowest elements from a, and take two lowest from b and place them to the two highest in output. + + // SSE1 Store instructions: +#ifdef TEST_M64 + /*M64*/*(uint64_t*)uarr = 0xCDCDCDCDCDCDCDCDULL; _mm_maskmove_si64(u64castm64(0x00EEDDCCBBAA9988ULL), u64castm64(0x0080FF7F01FEFF40ULL), (char*)uarr); Assert(*(uint64_t*)uarr == 0xCDEEDDCDCDAA99CDULL); // _mm_maskmove_si64: Conditionally store bytes of a 64-bit value. + /*M64*/*(uint64_t*)uarr = 0xABABABABABABABABULL; _m_maskmovq(u64castm64(0x00EEDDCCBBAA9988ULL), u64castm64(0x0080FF7F01FEFF40ULL), (char*)uarr); Assert(*(uint64_t*)uarr == 0xABEEDDABABAA99ABULL); // _m_maskmovq is an alias to _mm_maskmove_si64. +#endif + _mm_store_ps(arr2, a); aeq(_mm_load_ps(arr2), 8.f, 6.f, 4.f, 2.f); // _mm_store_ps: 4-wide store to aligned memory address. + _mm_store_ps1(arr2, a); aeq(_mm_load_ps(arr2), 2.f, 2.f, 2.f, 2.f); // _mm_store_ps1: Store lowest scalar to aligned address, duplicating the element 4 times. + _mm_storeu_ps(uarr2, _mm_set1_ps(100.f)); _mm_store_ss(uarr2, b); aeq(_mm_loadu_ps(uarr2), 100.f, 100.f, 100.f, 4.f); // _mm_store_ss: Store lowest scalar to unaligned address. Don't adjust higher addresses in memory. + _mm_store_ps(arr2, _mm_set1_ps(100.f)); _mm_store1_ps(arr2, a); aeq(_mm_load_ps(arr2), 2.f, 2.f, 2.f, 2.f); // _mm_store1_ps == _mm_store_ps1 + _mm_storeu_ps(uarr2, _mm_set1_ps(100.f)); _mm_storeh_pi((__m64*)uarr2, a); aeq(_mm_loadu_ps(uarr2), 100.f, 100.f, 8.f, 6.f); // _mm_storeh_pi: Store two highest elements to memory. + _mm_storeu_ps(uarr2, _mm_set1_ps(100.f)); _mm_storel_pi((__m64*)uarr2, a); aeq(_mm_loadu_ps(uarr2), 100.f, 100.f, 4.f, 2.f); // _mm_storel_pi: Store two lowest elements to memory. + _mm_storer_ps(arr2, a); aeq(_mm_load_ps(arr2), 2.f, 4.f, 6.f, 8.f); // _mm_storer_ps: 4-wide store to aligned memory address, but reverse the elements on output. + _mm_storeu_ps(uarr2, a); aeq(_mm_loadu_ps(uarr2), 8.f, 6.f, 4.f, 2.f); // _mm_storeu_ps: 4-wide store to unaligned memory address. +#ifdef TEST_M64 + /*M64*/_mm_stream_pi((__m64*)uarr, u64castm64(0x0080FF7F01FEFF40ULL)); Assert(*(uint64_t*)uarr == 0x0080FF7F01FEFF40ULL); // _mm_stream_pi: 2-wide store, but with a non-temporal memory cache hint. +#endif + _mm_store_ps(arr2, _mm_set1_ps(100.f)); _mm_stream_ps(arr2, a); aeq(_mm_load_ps(arr2), 8.f, 6.f, 4.f, 2.f); // _mm_stream_ps: 4-wide store, but with a non-temporal memory cache hint. + + // SSE1 Arithmetic instructions: + aeq(_mm_add_ps(a, b), 9.f, 8.f, 7.f, 6.f); // 4-wide add. + aeq(_mm_add_ss(a, b), 8.f, 6.f, 4.f, 6.f); // Add lowest element, preserve three highest unchanged from a. + aeq(_mm_div_ps(a, _mm_set_ps(2.f, 3.f, 8.f, 2.f)), 4.f, 2.f, 0.5f, 1.f); // 4-wide div. + aeq(_mm_div_ss(a, _mm_set_ps(2.f, 3.f, 8.f, 8.f)), 8.f, 6.f, 4.f, 0.25f); // Div lowest element, preserve three highest unchanged from a. + aeq(_mm_mul_ps(a, b), 8.f, 12.f, 12.f, 8.f); // 4-wide mul. + aeq(_mm_mul_ss(a, b), 8.f, 6.f, 4.f, 8.f); // Mul lowest element, preserve three highest unchanged from a. +#ifdef TEST_M64 + __m64 m1 = get_m1(); + /*M64*/aeq64(_mm_mulhi_pu16(m1, u64castm64(0x22446688AACCEEFFULL)), 0x002233440B4C33CFULL); // Multiply u16 channels, and store high parts. + /*M64*/aeq64( _m_pmulhuw(m1, u64castm64(0x22446688AACCEEFFULL)), 0x002233440B4C33CFULL); // _m_pmulhuw is an alias to _mm_mulhi_pu16. + __m64 m2 = get_m2(); + /*M64*/aeq64(_mm_sad_pu8(m1, m2), 0x368ULL); // Compute abs. differences of u8 channels, and sum those up to a single 16-bit scalar. + /*M64*/aeq64( _m_psadbw(m1, m2), 0x368ULL); // _m_psadbw is an alias to _mm_sad_pu8. +#endif + aeq(_mm_sub_ps(a, b), 7.f, 4.f, 1.f, -2.f); // 4-wide sub. + aeq(_mm_sub_ss(a, b), 8.f, 6.f, 4.f, -2.f); // Sub lowest element, preserve three highest unchanged from a. + + // SSE1 Elementary Math functions: +#ifndef __EMSCRIPTEN__ // TODO: Enable support for this to pass. + aeq(_mm_rcp_ps(a), 0.124969f, 0.166626f, 0.249939f, 0.499878f); // Compute 4-wide 1/x. + aeq(_mm_rcp_ss(a), 8.f, 6.f, 4.f, 0.499878f); // Compute 1/x of lowest element, pass higher elements unchanged. + aeq(_mm_rsqrt_ps(a), 0.353455f, 0.408203f, 0.499878f, 0.706909f); // Compute 4-wide 1/sqrt(x). + aeq(_mm_rsqrt_ss(a), 8.f, 6.f, 4.f, 0.706909f); // Compute 1/sqrt(x) of lowest element, pass higher elements unchanged. +#endif + aeq(_mm_sqrt_ps(a), 2.82843f, 2.44949f, 2.f, 1.41421f); // Compute 4-wide sqrt(x). + aeq(_mm_sqrt_ss(a), 8.f, 6.f, 4.f, 1.41421f); // Compute sqrt(x) of lowest element, pass higher elements unchanged. + + __m128 i1 = get_i1(); + __m128 i2 = get_i2(); + + // SSE1 Logical instructions: +#ifndef __EMSCRIPTEN__ // TODO: The polyfill currently does NaN canonicalization and breaks these. + aeqi(_mm_and_ps(i1, i2), 0x83200100, 0x0fecc988, 0x80244021, 0x13458a88); // 4-wide binary AND + aeqi(_mm_andnot_ps(i1, i2), 0x388a9888, 0xf0021444, 0x7000289c, 0x00121046); // 4-wide binary (!i1) & i2 + aeqi(_mm_or_ps(i1, i2), 0xbfefdba9, 0xffefdfed, 0xf7656bbd, 0xffffdbef); // 4-wide binary OR + aeqi(_mm_xor_ps(i1, i2), 0x3ccfdaa9, 0xf0031665, 0x77412b9c, 0xecba5167); // 4-wide binary XOR +#endif + + // SSE1 Compare instructions: + // a = [8, 6, 4, 2], b = [1, 2, 3, 4] + aeqi(_mm_cmpeq_ps(a, _mm_set_ps(8.f, 0.f, 4.f, 0.f)), 0xFFFFFFFF, 0, 0xFFFFFFFF, 0); // 4-wide cmp == + aeqi(_mm_cmpeq_ss(a, _mm_set_ps(8.f, 0.f, 4.f, 2.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0xFFFFFFFF); // scalar cmp ==, pass three highest unchanged. + aeqi(_mm_cmpge_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0xFFFFFFFF, 0, 0xFFFFFFFF, 0); // 4-wide cmp >= + aeqi(_mm_cmpge_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 0.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0xFFFFFFFF); // scalar cmp >=, pass three highest unchanged. + aeqi(_mm_cmpgt_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0, 0, 0xFFFFFFFF, 0); // 4-wide cmp > + aeqi(_mm_cmpgt_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 2.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0); // scalar cmp >, pass three highest unchanged. + aeqi(_mm_cmple_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0xFFFFFFFF, 0xFFFFFFFF, 0, 0xFFFFFFFF); // 4-wide cmp <= + aeqi(_mm_cmple_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 0.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0); // scalar cmp <=, pass three highest unchanged. + aeqi(_mm_cmplt_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0, 0xFFFFFFFF, 0, 0xFFFFFFFF); // 4-wide cmp < + aeqi(_mm_cmplt_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 2.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0); // scalar cmp <, pass three highest unchanged. + aeqi(_mm_cmpneq_ps(a, _mm_set_ps(8.f, 0.f, 4.f, 0.f)), 0, 0xFFFFFFFF, 0, 0xFFFFFFFF); // 4-wide cmp != + aeqi(_mm_cmpneq_ss(a, _mm_set_ps(8.f, 0.f, 4.f, 2.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0); // scalar cmp !=, pass three highest unchanged. + aeqi(_mm_cmpnge_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0, 0xFFFFFFFF, 0, 0xFFFFFFFF); // 4-wide cmp not >= + aeqi(_mm_cmpnge_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 0.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0); // scalar cmp not >=, pass three highest unchanged. + aeqi(_mm_cmpngt_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0xFFFFFFFF, 0xFFFFFFFF, 0, 0xFFFFFFFF); // 4-wide cmp not > + aeqi(_mm_cmpngt_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 2.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0xFFFFFFFF); // scalar cmp not >, pass three highest unchanged. + aeqi(_mm_cmpnle_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0, 0, 0xFFFFFFFF, 0); // 4-wide cmp not <= + aeqi(_mm_cmpnle_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 0.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0xFFFFFFFF); // scalar cmp not <=, pass three highest unchanged. + aeqi(_mm_cmpnlt_ps(a, _mm_set_ps(8.f, 7.f, 3.f, 5.f)), 0xFFFFFFFF, 0, 0xFFFFFFFF, 0); // 4-wide cmp not < + aeqi(_mm_cmpnlt_ss(a, _mm_set_ps(8.f, 7.f, 3.f, 2.f)), fcastu(8.f), fcastu(6.f), fcastu(4.f), 0xFFFFFFFF); // scalar cmp not <, pass three highest unchanged. + + __m128 nan1 = get_nan1(); // [NAN, 0, 0, NAN] + __m128 nan2 = get_nan2(); // [NAN, NAN, 0, 0] + aeqi(_mm_cmpord_ps(nan1, nan2), 0, 0, 0xFFFFFFFF, 0); // 4-wide test if both operands are not nan. + aeqi(_mm_cmpord_ss(nan1, nan2), fcastu(NAN), 0, 0, 0); // scalar test if both operands are not nan, pass three highest unchanged. + // Intel Intrinsics Guide documentation is wrong on _mm_cmpunord_ps and _mm_cmpunord_ss. MSDN is right: http://msdn.microsoft.com/en-us/library/khy6fk1t(v=vs.90).aspx + aeqi(_mm_cmpunord_ps(nan1, nan2), 0xFFFFFFFF, 0xFFFFFFFF, 0, 0xFFFFFFFF); // 4-wide test if one of the operands is nan. +#ifndef __EMSCRIPTEN__ // TODO: The polyfill currently does NaN canonicalization and breaks these. + aeqi(_mm_cmpunord_ss(nan1, nan2), fcastu(NAN), 0, 0, 0xFFFFFFFF); // scalar test if one of the operands is nan, pass three highest unchanged. +#endif + + Assert(_mm_comieq_ss(a, b) == 0); Assert(_mm_comieq_ss(a, a) == 1); // Scalar cmp == of lowest element, return int. + Assert(_mm_comige_ss(a, b) == 0); Assert(_mm_comige_ss(a, a) == 1); // Scalar cmp >= of lowest element, return int. + Assert(_mm_comigt_ss(b, a) == 1); Assert(_mm_comigt_ss(a, a) == 0); // Scalar cmp > of lowest element, return int. + Assert(_mm_comile_ss(b, a) == 0); Assert(_mm_comile_ss(a, a) == 1); // Scalar cmp <= of lowest element, return int. + Assert(_mm_comilt_ss(a, b) == 1); Assert(_mm_comilt_ss(a, a) == 0); // Scalar cmp < of lowest element, return int. + Assert(_mm_comineq_ss(a, b) == 1); Assert(_mm_comineq_ss(a, a) == 0); // Scalar cmp != of lowest element, return int. + + // The ucomi versions are identical to comi, except that ucomi signal a FP exception only if one of the input operands is a SNaN, whereas the comi versions signal a FP + // 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); + 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); + Assert(_mm_ucomineq_ss(a, b) == 1); Assert(_mm_ucomineq_ss(a, a) == 0); Assert(_mm_ucomineq_ss(a, nan1) == 0); +#endif + + // SSE1 Convert instructions: + __m128 c = get_c(); // [1.5, 2.5, 3.5, 4.5] + __m128 e = get_e(); // [INF, -INF, 2.5, 3.5] + __m128 f = get_f(); // [-1.5, 1.5, -2.5, -9223372036854775808] +#ifdef TEST_M64 + /*M64*/aeq(_mm_cvt_pi2ps(a, m2), 8.f, 6.f, -19088744.f, 1985229312.f); // 2-way int32 to float conversion to two lowest channels of m128. + /*M64*/aeq64(_mm_cvt_ps2pi(c), 0x400000004ULL); // 2-way two lowest floats from m128 to integer, return as m64. +#endif + aeq(_mm_cvtsi32_ss(c, -16777215), 1.5f, 2.5f, 3.5f, -16777215.f); // Convert int to float, store in lowest channel of m128. + aeq( _mm_cvt_si2ss(c, -16777215), 1.5f, 2.5f, 3.5f, -16777215.f); // _mm_cvt_si2ss is an alias to _mm_cvtsi32_ss. +#ifndef __EMSCRIPTEN__ // TODO: Fix banker's rounding in cvt functions. + Assert(_mm_cvtss_si32(c) == 4); Assert(_mm_cvtss_si32(e) == 4); // Convert lowest channel of m128 from float to int. + Assert( _mm_cvt_ss2si(c) == 4); Assert( _mm_cvt_ss2si(e) == 4); // _mm_cvt_ss2si is an alias to _mm_cvtss_si32. +#endif +#ifdef TEST_M64 + /*M64*/aeq(_mm_cvtpi16_ps(m1), 255.f , -32767.f, 4336.f, 14207.f); // 4-way convert int16s to floats, return in a m128. + /*M64*/aeq(_mm_cvtpi32_ps(a, m1), 8.f, 6.f, 16744449.f, 284178304.f); // 2-way convert int32s to floats, return in two lowest channels of m128, pass two highest unchanged. + /*M64*/aeq(_mm_cvtpi32x2_ps(m1, m2), -19088744.f, 1985229312.f, 16744449.f, 284178304.f); // 4-way convert int32s from two different m64s to float. + /*M64*/aeq(_mm_cvtpi8_ps(m1), 16.f, -16.f, 55.f, 127.f); // 4-way convert int8s from lowest end of m64 to float in a m128. + /*M64*/aeq64(_mm_cvtps_pi16(c), 0x0002000200040004ULL); // 4-way convert floats to int16s in a m64. + /*M64*/aeq64(_mm_cvtps_pi32(c), 0x0000000400000004ULL); // 2-way convert two lowest floats to int32s in a m64. + /*M64*/aeq64(_mm_cvtps_pi8(c), 0x0000000002020404ULL); // 4-way convert floats to int8s in a m64, zero higher half of the returned m64. + /*M64*/aeq(_mm_cvtpu16_ps(m1), 255.f , 32769.f, 4336.f, 14207.f); // 4-way convert uint16s to floats, return in a m128. + /*M64*/aeq(_mm_cvtpu8_ps(m1), 16.f, 240.f, 55.f, 127.f); // 4-way convert uint8s from lowest end of m64 to float in a m128. +#endif + aeq(_mm_cvtsi64_ss(c, -9223372036854775808ULL), 1.5f, 2.5f, 3.5f, -9223372036854775808.f); // Convert single int64 to float, store in lowest channel of m128, and pass three higher channel unchanged. + Assert(_mm_cvtss_f32(c) == 4.5f); // Extract lowest channel of m128 to a plain old float. + Assert(_mm_cvtss_si64(f) == -9223372036854775808ULL); // Convert lowest channel of m128 from float to int64. +#ifdef TEST_M64 + /*M64*/aeq64(_mm_cvtt_ps2pi(e), 0x0000000200000003ULL); aeq64(_mm_cvtt_ps2pi(f), 0xfffffffe80000000ULL); // Truncating conversion from two lowest floats of m128 to int32s, return in a m64. +#endif + Assert(_mm_cvttss_si32(e) == 3); // Truncating conversion from the lowest float of a m128 to int32. + Assert( _mm_cvtt_ss2si(e) == 3); // _mm_cvtt_ss2si is an alias to _mm_cvttss_si32. +#ifdef TEST_M64 + /*M64*/aeq64(_mm_cvttps_pi32(c), 0x0000000300000004ULL); // Truncating conversion from two lowest floats of m128 to m64. +#endif + Assert(_mm_cvttss_si64(f) == -9223372036854775808ULL); // Truncating conversion from lowest channel of m128 from float to int64. + +#ifndef __EMSCRIPTEN__ // TODO: Not implemented. + // SSE1 General support: + unsigned int mask = _MM_GET_EXCEPTION_MASK(); + _MM_SET_EXCEPTION_MASK(mask); + unsigned int flushZeroMode = _MM_GET_FLUSH_ZERO_MODE(); + _MM_SET_FLUSH_ZERO_MODE(flushZeroMode); + unsigned int roundingMode = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE(roundingMode); + unsigned int csr = _mm_getcsr(); + _mm_setcsr(csr); + unsigned char dummyData[4096]; + _mm_prefetch(dummyData, _MM_HINT_T0); + _mm_prefetch(dummyData, _MM_HINT_T1); + _mm_prefetch(dummyData, _MM_HINT_T2); + _mm_prefetch(dummyData, _MM_HINT_NTA); + _mm_sfence(); +#endif + + // SSE1 Misc instructions: +#ifdef TEST_M64 + /*M64*/Assert(_mm_movemask_pi8(m1) == 100); // Return int with eight lowest bits set depending on the highest bits of the 8 uint8 input channels of the m64. + /*M64*/Assert( _m_pmovmskb(m1) == 100); // _m_pmovmskb is an alias to _mm_movemask_pi8. +#endif + Assert(_mm_movemask_ps(_mm_set_ps(-1.f, 0.f, 1.f, NAN)) == 8); Assert(_mm_movemask_ps(_mm_set_ps(-INFINITY, -0.f, INFINITY, -INFINITY)) == 13); // Return int with four lowest bits set depending on the highest bits of the 4 m128 input channels. + + // SSE1 Probability/Statistics instructions: +#ifdef TEST_M64 + /*M64*/aeq64(_mm_avg_pu16(m1, m2), 0x7FEE9D4D43A234C8ULL); // 4-way average uint16s. + /*M64*/aeq64( _m_pavgw(m1, m2), 0x7FEE9D4D43A234C8ULL); // _m_pavgw is an alias to _mm_avg_pu16. + /*M64*/aeq64(_mm_avg_pu8(m1, m2), 0x7FEE9D4D43A23548ULL); // 8-way average uint8s. + /*M64*/aeq64( _m_pavgb(m1, m2), 0x7FEE9D4D43A23548ULL); // _m_pavgb is an alias to _mm_avg_pu8. + + // SSE1 Special Math instructions: + /*M64*/aeq64(_mm_max_pi16(m1, m2), 0xFFBA987654377FULL); // 4-way average uint16s. + /*M64*/aeq64( _m_pmaxsw(m1, m2), 0xFFBA987654377FULL); // _m_pmaxsw is an alias to _mm_max_pi16. + /*M64*/aeq64(_mm_max_pu8(m1, m2), 0xFEFFBA9876F0377FULL); // 4-way average uint16s. + /*M64*/aeq64( _m_pmaxub(m1, m2), 0xFEFFBA9876F0377FULL); // _m_pmaxub is an alias to _mm_max_pu8. + /*M64*/aeq64(_mm_min_pi16(m1, m2), 0xFEDC800110F03210ULL); // 4-way average uint16s. + /*M64*/aeq64( _m_pminsw(m1, m2), 0xFEDC800110F03210ULL); // is an alias to _mm_min_pi16. + /*M64*/aeq64(_mm_min_pu8(m1, m2), 0xDC800110543210ULL); // 4-way average uint16s. + /*M64*/aeq64( _m_pminub(m1, m2), 0xDC800110543210ULL); // is an alias to _mm_min_pu8. +#endif + // a = [8, 6, 4, 2], b = [1, 2, 3, 4] + aeq(_mm_max_ps(a, b), 8.f, 6.f, 4.f, 4.f); // 4-wide max. + aeq(_mm_max_ss(a, _mm_set1_ps(100.f)), 8.f, 6.f, 4.f, 100.f); // Scalar max, pass three highest unchanged. + aeq(_mm_min_ps(a, b), 1.f, 2.f, 3.f, 2.f); // 4-wide min. + aeq(_mm_min_ss(a, _mm_set1_ps(-100.f)), 8.f, 6.f, 4.f, -100.f); // Scalar min, pass three highest unchanged. + + // SSE1 Swizzle instructions: +#ifdef TEST_M64 + /*M64*/Assert(_mm_extract_pi16(m1, 1) == 4336); // Extract the given int16 channel from a m64. + /*M64*/Assert( _m_pextrw(m1, 1) == 4336); // _m_pextrw is an alias to _mm_extract_pi16. + /*M64*/aeq64(_mm_insert_pi16(m1, 0xABCD, 1), 0xFF8001ABCD377FULL); // Insert a int16 to a specific channel of a m64. + /*M64*/aeq64( _m_pinsrw(m1, 0xABCD, 1), 0xFF8001ABCD377FULL); // _m_pinsrw is an alias to _mm_insert_pi16. + /*M64*/aeq64(_mm_shuffle_pi16(m1, _MM_SHUFFLE(1, 0, 3, 2)), 0x10F0377F00FF8001ULL); // Shuffle int16s around in the 4 channels of the m64. + /*M64*/aeq64( _m_pshufw(m1, _MM_SHUFFLE(1, 0, 3, 2)), 0x10F0377F00FF8001ULL); // _m_pshufw is an alias to _mm_shuffle_pi16. +#endif + aeq(_mm_shuffle_ps(a, b, _MM_SHUFFLE(1, 0, 3, 2)), 3.f, 4.f, 8.f, 6.f); + aeq(_mm_unpackhi_ps(a, b), 1.f , 8.f, 2.f, 6.f); + aeq(_mm_unpacklo_ps(a, b), 3.f , 4.f, 4.f, 2.f); + + // Transposing a matrix via the xmmintrin.h-provided intrinsic. + __m128 c0 = a; // [8, 6, 4, 2] + __m128 c1 = b; // [1, 2, 3, 4] + __m128 c2 = get_c(); // [1.5, 2.5, 3.5, 4.5] + __m128 c3 = get_d(); // [8.5, 6.5, 4.5, 2.5] + _MM_TRANSPOSE4_PS(c0, c1, c2, c3); + aeq(c0, 2.5f, 4.5f, 4.f, 2.f); + aeq(c1, 4.5f, 3.5f, 3.f, 4.f); + aeq(c2, 6.5f, 2.5f, 2.f, 6.f); + aeq(c3, 8.5f, 1.5f, 1.f, 8.f); + + // All done! + if (numFailures == 0) + printf("Success!\n"); + else + printf("%d tests failed!\n", numFailures); +} diff --git a/tests/unicode_library.js b/tests/unicode_library.js new file mode 100644 index 0000000000000..0766f5ff3226c --- /dev/null +++ b/tests/unicode_library.js @@ -0,0 +1,5 @@ +mergeInto(LibraryManager.library, { +printey: function() { + Module.print('Unicode snowman ☃ says hello!'); +} +}); diff --git a/tests/webidl/output.txt b/tests/webidl/output.txt index cb110eae17610..f60e383fcaaaa 100644 --- a/tests/webidl/output.txt +++ b/tests/webidl/output.txt @@ -49,6 +49,10 @@ caught: a JSImplementation must implement all functions, you forgot Child2JS::vi |hello|43|world|41| 12.35 a returned string +C string addresses: "string A" ? "string A" => 0 +C string addresses: "string B" ? "string B" => 0 +C string addresses: "string A" ? "string B" => -1 +C string addresses: "string B" ? "string A" => 1 10 object 10 diff --git a/tests/webidl/post.js b/tests/webidl/post.js index fc072365f3222..8697c1121e118 100644 --- a/tests/webidl/post.js +++ b/tests/webidl/post.js @@ -103,6 +103,12 @@ suser.Print(41, "world"); suser.PrintFloat(12.3456); TheModule.print(suser.returnAString()); +// Verify that subsequent calls with the same string value re-use the string storage. +suser.CompareCStringAddress("string A", "string A"); +suser.CompareCStringAddress("string B", "string B"); +suser.CompareCStringAddress("string A", "string B"); +suser.CompareCStringAddress("string B", "string A"); + var bv = new TheModule.RefUser(10); var bv2 = new TheModule.RefUser(11); TheModule.print(bv2.getValue(bv)); diff --git a/tests/webidl/test.h b/tests/webidl/test.h index c6baef1ccba89..cf3de3997d805 100644 --- a/tests/webidl/test.h +++ b/tests/webidl/test.h @@ -59,6 +59,10 @@ class StringUser { } void PrintFloat(float f) { printf("%.2f\n", f); } const char* returnAString() { return "a returned string"; } + + void CompareCStringAddress(const char* s1, const char* s2) { + printf("C string addresses: \"%s\" ? \"%s\" => %d\n", s1, s2, s1 < s2 ? -1 : (s1 == s2 ? 0 : 1)); + } }; struct RefUser { diff --git a/tests/webidl/test.idl b/tests/webidl/test.idl index 3e8e70226e2b4..9809df86563e2 100644 --- a/tests/webidl/test.idl +++ b/tests/webidl/test.idl @@ -52,6 +52,7 @@ interface StringUser { void Print(long anotherInteger, DOMString anotherString); void PrintFloat(float f); [Const] DOMString returnAString(); + void CompareCStringAddress(DOMString str1, DOMString str2); }; interface RefUser { diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index e3dd0113d2a90..7905fc22d0344 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -79,7 +79,7 @@ function exc($this) { __ZNSt3__114__shared_count12__add_sharedEv($5 | 0); return; } else { - $8$0 = ___cxa_find_matching_catch(HEAP32[(_llvm_eh_exception.buf & 16777215) >> 2] | 0, HEAP32[(_llvm_eh_exception.buf + 4 & 16777215) >> 2] | 0, []); + $8$0 = ___cxa_find_matching_catch(HEAP32[(_llvm_eh_exception_buf & 16777215) >> 2] | 0, HEAP32[(_llvm_eh_exception_buf + 4 & 16777215) >> 2] | 0); $8$1 = tempRet0; ___cxa_call_unexpected($8$0); } @@ -101,7 +101,7 @@ function switchy() { yes = 111; yes = yes * 2; print(yes); - yes--; + yes = yes + 1; print(yes / 2); continue; case 3: diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index 3624536a42471..b4c16bc83d04b 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -112,7 +112,7 @@ function exc($this) { __ZNSt3__114__shared_count12__add_sharedEv($6); return; } else { - $8$0 = ___cxa_find_matching_catch(HEAP32[(_llvm_eh_exception.buf & 16777215) >> 2] | 0, HEAP32[(_llvm_eh_exception.buf + 4 & 16777215) >> 2] | 0, []); + $8$0 = ___cxa_find_matching_catch(HEAP32[(_llvm_eh_exception_buf & 16777215) >> 2] | 0, HEAP32[(_llvm_eh_exception_buf + 4 & 16777215) >> 2] | 0); $8$1 = tempRet0; $9 = $8$0; ___cxa_call_unexpected($9); @@ -140,7 +140,7 @@ function switchy() { yes = 111; yes = yes*2; print(yes); - yes--; + yes = yes + 1; print(yes/2); continue; case 3: diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index f592c7eefe091..a7ba7e9f39fe7 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -333,6 +333,10 @@ function traverseChildrenInExecutionOrder(node, definitely, maybe, arg) { definitely(node[3], arg); break; } + case 'dot': { + definitely(node[1], arg); + break; + } case 'unary-prefix': case 'label': { definitely(node[2], arg); break; @@ -353,7 +357,7 @@ function traverseChildrenInExecutionOrder(node, definitely, maybe, arg) { } case 'defun': case 'func': case 'block': { var stats = getStatements(node); - if (stats.length === 0) break; + if (!stats || stats.length === 0) break; for (var i = 0; i < stats.length; i++) { definitely(stats[i], arg); // check if we might break, if we have more to do @@ -5367,7 +5371,7 @@ function outline(ast) { return ['assign', true, dst, src]; } function makeStackAccess(type, pos) { // TODO: float64, not 32 - return ['sub', ['name', type == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', pos]], ['num', '2']]]; + return ['sub', ['name', type == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', pos]], ['num', 2]]]; } function makeIf(cond, then, else_) { var ret = ['if', cond, ['block', then]]; @@ -5427,7 +5431,7 @@ function outline(ast) { var sortedWrites = keys(codeInfo.writes).sort(orderFunc); sortedReadsAndWrites.forEach(function(v) { if (!(v in owned)) { - reps.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]); + reps.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', 2]]], ['name', v]]]); } }); // wipe out control variable @@ -5438,7 +5442,7 @@ function outline(ast) { // add unspills sortedWrites.forEach(function(v) { if (!(v in owned)) { - reps.push(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]); + reps.push(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', 2]]], getAsmType(v, asmData))]]); } }); @@ -5528,7 +5532,7 @@ function outline(ast) { if (codeInfo.hasReturn) { reps.push(makeIf( makeComparison(makeAsmCoercion(['name', 'tempValue'], ASM_INT), '==', ['num', CONTROL_RETURN_VOID]), - [['stat', ['return']]] + [['stat', ['return', null]]] )); } for (var returnType in codeInfo.hasReturnType) { @@ -5540,7 +5544,7 @@ function outline(ast) { if (codeInfo.hasBreak) { reps.push(makeIf( makeComparison(makeAsmCoercion(['name', 'tempValue'], ASM_INT), '==', ['num', CONTROL_BREAK]), - [['stat', ['break']]] + [['stat', ['break', null]]] )); if (keys(codeInfo.breaks).length > 0) { reps.push(makeIf( @@ -5555,7 +5559,7 @@ function outline(ast) { if (codeInfo.hasContinue) { reps.push(makeIf( makeComparison(makeAsmCoercion(['name', 'tempValue'], ASM_INT), '==', ['num', CONTROL_CONTINUE]), - [['stat', ['continue']]] + [['stat', ['continue', null]]] )); if (keys(codeInfo.continues).length > 0) { reps.push(makeIf( @@ -5572,12 +5576,12 @@ function outline(ast) { sortedReadsAndWrites.reverse(); sortedReadsAndWrites.forEach(function(v) { if (!(v in owned)) { - code.unshift(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]); + code.unshift(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', 2]]], getAsmType(v, asmData))]]); } }); sortedWrites.forEach(function(v) { if (!(v in owned)) { - code.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]); + code.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', 2]]], ['name', v]]]); } }); // finalize @@ -5940,19 +5944,19 @@ function safeHeap(ast) { // SAFE_HEAP_STORE(ptr, value, bytes, isFloat) switch (heap) { case 'HEAP8': case 'HEAPU8': { - return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 1], ['num', '0']]]; + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 1], ['num', 0]]]; } case 'HEAP16': case 'HEAPU16': { - return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 2], ['num', '0']]]; + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 2], ['num', 0]]]; } case 'HEAP32': case 'HEAPU32': { - return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 4], ['num', '0']]]; + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 4], ['num', 0]]]; } case 'HEAPF32': { - return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 4], ['num', '1']]]; + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 4], ['num', 1]]]; } case 'HEAPF64': { - return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 8], ['num', '1']]]; + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 8], ['num', 1]]]; } default: throw 'bad heap ' + heap; } @@ -5966,28 +5970,28 @@ function safeHeap(ast) { // SAFE_HEAP_LOAD(ptr, bytes, isFloat) switch (heap) { case 'HEAP8': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', 0], ['num', 0]]], ASM_INT); } case 'HEAPU8': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', 0], ['num', 1]]], ASM_INT); } case 'HEAP16': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', 0], ['num', 0]]], ASM_INT); } case 'HEAPU16': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', 0], ['num', 1]]], ASM_INT); } case 'HEAP32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', 0], ['num', 0]]], ASM_INT); } case 'HEAPU32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', 0], ['num', 1]]], ASM_INT); } case 'HEAPF32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', 1], ['num', 0]]], ASM_DOUBLE); } case 'HEAPF64': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', 1], ['num', 0]]], ASM_DOUBLE); } default: throw 'bad heap ' + heap; } diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 553a749a34adb..86ff2f8c68f04 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', 'minifyNames', 'minifyLocals', 'minifyWhitespace']) +NATIVE_PASSES = set(['asm', 'asmPreciseF32', 'receiveJSON', 'emitJSON', 'eliminate', 'eliminateMemSafe', 'simplifyExpressions', 'simplifyIfs', 'optimizeFrounds', 'registerize', 'minifyNames', 'minifyLocals', 'minifyWhitespace', 'cleanup', 'asmLastOpts', 'last', 'noop']) JS_OPTIMIZER = path_from_root('tools', 'js-optimizer.js') @@ -28,19 +28,44 @@ def path_from_root(*pathelems): NATIVE_OPTIMIZER = os.environ.get('EMCC_NATIVE_OPTIMIZER') def get_native_optimizer(): - def create_optimizer(): - shared.logging.debug('building native optimizer') - output = shared.Cache.get_path('optimizer.exe') - shared.try_delete(output) - errs = [] - 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) - out, err = subprocess.Popen([compiler, shared.path_from_root('tools', 'optimizer', 'optimizer.cpp'), '-O3', '-std=c++11', '-fno-exceptions', '-fno-rtti', '-o', output], stderr=subprocess.PIPE).communicate() - # for profiling/debugging: '-g', '-fno-omit-frame-pointer' - if os.path.exists(output): return output - errs.append(err) - raise Exception('failed to build native optimizer, errors from each attempt: ' + '\n=================\n'.join(errs)) - return shared.Cache.get('optimizer.exe', create_optimizer, extension='exe') + if os.environ.get('EMCC_FAST_COMPILER') == '0': return None # need fastcomp for native optimizer + + FAIL_MARKER = shared.Cache.get_path('optimizer.building_failed') + if os.path.exists(FAIL_MARKER): + shared.logging.debug('seeing that optimizer could not be built') + return None + + def get_optimizer(name, args): + class NativeOptimizerCreationException(Exception): pass + try: + def create_optimizer(): + shared.logging.debug('building native optimizer: ' + name) + output = shared.Cache.get_path(name) + shared.try_delete(output) + 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() + 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 + raise NativeOptimizerCreationException() + return shared.Cache.get(name, create_optimizer, extension='exe') + except NativeOptimizerCreationException, e: + shared.logging.debug('failed to build native optimizer') + open(FAIL_MARKER, 'w').write(':(') + return None + + if NATIVE_OPTIMIZER == '1': + return get_optimizer('optimizer.exe', []) + elif NATIVE_OPTIMIZER == '2': + return get_optimizer('optimizer.2.exe', ['-DNDEBUG']) + elif NATIVE_OPTIMIZER == 'g': + return get_optimizer('optimizer.g.exe', ['-O0', '-g', '-fno-omit-frame-pointer']) # 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): @@ -120,12 +145,15 @@ def run_on_chunk(command): filename = command[index + 1] else: filename = command[1] - #saved = 'save_' + os.path.basename(filename) - #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)) - output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0] - assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output + if os.environ.get('EMCC_SAVE_OPT_TEMP') and os.environ.get('EMCC_SAVE_OPT_TEMP') != '0': + saved = 'save_' + os.path.basename(filename) + 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)) + proc = subprocess.Popen(command, stdout=subprocess.PIPE) + output = proc.communicate()[0] + 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') f.write(output) @@ -314,7 +342,7 @@ def write_chunk(chunk, i): filenames = [] if len(filenames) > 0: - if not use_native(passes, source_map) or 'receiveJSON' not in passes or 'emitJSON' not in passes: + if not use_native(passes, source_map) or not get_native_optimizer(): commands = map(lambda filename: js_engine + [JS_OPTIMIZER, filename, 'noPrintMetadata'] + (['--debug'] if source_map else []) + passes, filenames) diff --git a/tools/optimizer/istring.h b/tools/optimizer/istring.h new file mode 100644 index 0000000000000..d8cd3cc5e17f0 --- /dev/null +++ b/tools/optimizer/istring.h @@ -0,0 +1,137 @@ +// Interned String type, 100% interned on creation. Comparisons are always just a pointer comparison + +#include +#include + +#include +#include +#include +#include +#include + +namespace cashew { + +struct IString { + const char *str; + + static size_t hash_c(const char *str) { // TODO: optimize? + uint64_t ret = 0; + while (*str) { + ret = (ret*6364136223846793005ULL) + *str; + str++; + } + return (size_t)ret; + } + + class CStringHash : public std::hash { + public: + size_t operator()(const char *str) const { + return IString::hash_c(str); + } + }; + class CStringEqual : public std::equal_to { + public: + bool operator()(const char *x, const char *y) const { + return strcmp(x, y) == 0; + } + }; + + IString() : str(nullptr) {} + IString(const char *s, bool reuse=true) { // if reuse=true, then input is assumed to remain alive; not copied + set(s, reuse); + } + + void set(const char *s, bool reuse=true) { + typedef std::unordered_set StringSet; + static StringSet* strings = new StringSet(); + + if (reuse) { + auto result = strings->insert(s); // if already present, does nothing + str = *(result.first); + } else { + auto existing = strings->find(s); + if (existing == strings->end()) { + char *copy = (char*)malloc(strlen(s)+1); // XXX leaked + strcpy(copy, s); + s = copy; + } else { + s = *existing; + } + strings->insert(s); + str = s; + } + } + + void set(const IString &s) { + str = s.str; + } + + bool operator==(const IString& other) const { + //assert((str == other.str) == !strcmp(str, other.str)); + return str == other.str; // fast! + } + bool operator!=(const IString& other) const { + //assert((str == other.str) == !strcmp(str, other.str)); + return str != other.str; // fast! + } + + char operator[](int x) { + return str[x]; + } + + bool operator!() { // no string, or empty string + return !str || str[0] == 0; + } + + const char *c_str() const { return str; } + + bool isNull() { return str == nullptr; } +}; + +} // namespace cashew + +// Utilities for creating hashmaps/sets over IStrings + +namespace std { + +template <> struct hash : public unary_function { + size_t operator()(const cashew::IString& str) const { + return cashew::IString::hash_c(str.c_str()); + } +}; + +template <> struct equal_to : public binary_function { + bool operator()(const cashew::IString& x, const cashew::IString& y) const { + return x == y; + } +}; + +} // namespace std + +namespace cashew { + +// IStringSet + +class IStringSet : public std::unordered_set { +public: + IStringSet() {} + IStringSet(const char *init) { // comma-delimited list + int size = strlen(init); + char *curr = (char*)malloc(size+1); // leaked! + strcpy(curr, init); + while (1) { + char *end = strchr(curr, ' '); + if (end) *end = 0; + insert(curr); + if (!end) break; + curr = end + 1; + } + } + + bool has(const IString& str) { + return count(str) > 0; + } +}; + +} // namespace cashew + diff --git a/tools/optimizer/minijson.h b/tools/optimizer/minijson.h deleted file mode 100644 index 3745e1549adb0..0000000000000 --- a/tools/optimizer/minijson.h +++ /dev/null @@ -1,654 +0,0 @@ -/* - * Extremely minimal JSON, just enough to manipulate an AST in the format the JS optimizer wants: arrays, strings, numbers, bools (no objects, no non-ascii, etc.). - * Optimized for fast parsing and also manipulation of the AST. - * Uses shared_ptr for simplicity, basically everywhere. TODO: measure impact - */ - -//#define NDEBUG - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define err(str) fprintf(stderr, str "\n"); -#define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__); -#define printErr err - -struct IString; -class Ref; -struct Value; - -void dump(const char *str, Ref node, bool pretty=false); - -// Reference to a value, plus some operators for convenience -struct Ref { - Value* inst; - - Ref(Value *v=nullptr) : inst(v) {} - - Value* get() { return inst; } - - Value& operator*() { return *inst; } - Value* operator->() { return inst; } - Ref& operator[](unsigned x); - Ref& operator[](IString x); - - // special conveniences - bool operator==(const char *str); // comparison to string, which is by value - bool operator!=(const char *str); - bool operator==(const IString &str); - bool operator!=(const IString &str); - bool operator==(double d) { assert(0); return false; } // prevent Ref == number, which is potentially ambiguous; use ->getNumber() == number - bool operator==(Ref other); - bool operator!(); // check if null, in effect -}; - -// Arena allocation, free it all on process exit - -struct Arena { - #define CHUNK_SIZE 1000 - std::vector chunks; - int index; // in last chunk - - Arena() : index(0) {} - - Ref alloc(); -}; - -Arena arena; - -// Interned String type, 100% interned on creation. Comparisons are always just a pointer comparison - -struct IString { - const char *str; - - static size_t hash_c(const char *str) { // TODO: optimize? - uint64_t ret = 0; - while (*str) { - ret = (ret*6364136223846793005ULL) + *str; - str++; - } - return (size_t)ret; - } - - class CStringHash : public std::hash { - public: - size_t operator()(const char *str) const { - return IString::hash_c(str); - } - }; - class CStringEqual : public std::equal_to { - public: - bool operator()(const char *x, const char *y) const { - return strcmp(x, y) == 0; - } - }; - typedef std::unordered_set StringSet; - static StringSet strings; - - IString() : str(nullptr) {} - IString(const char *s) { - set(s); - } - - void set(const char *s) { - auto result = strings.insert(s); // if already present, does nothing - str = *(result.first); - } - - void set(const IString &s) { - str = s.str; - } - - bool operator==(const IString& other) const { - //assert((str == other.str) == !strcmp(str, other.str)); - return str == other.str; // fast! - } - bool operator!=(const IString& other) const { - //assert((str == other.str) == !strcmp(str, other.str)); - return str != other.str; // fast! - } - - char operator[](int x) { - return str[x]; - } - - bool operator!() { // no string, or empty string - return !str || str[0] == 0; - } - - const char *c_str() const { return str; } - - bool isNull() { return str == nullptr; } -}; - -IString::StringSet IString::strings; - -// Utilities for creating hashmaps/sets over IStrings - -namespace std { - - template <> struct hash : public unary_function { - size_t operator()(const IString& str) const { - return IString::hash_c(str.c_str()); - } - }; - - template <> struct equal_to : public binary_function { - bool operator()(const IString& x, const IString& y) const { - return x == y; - } - }; - -} - -// Main value type -struct Value { - enum Type { - String = 0, - Number = 1, - Array = 2, - Null = 3, - Bool = 4, - Object = 5 - }; - - Type type; - - typedef std::vector ArrayStorage; - typedef std::unordered_map ObjectStorage; - - union { // TODO: optimize - IString str; - double num; - ArrayStorage *arr; - bool boo; - ObjectStorage *obj; - }; - - // constructors all copy their input - Value() : type(Null), num(0) {} - explicit Value(const char *s) : type(Null) { - setString(s); - } - explicit Value(double n) : type(Null) { - setNumber(n); - } - explicit Value(ArrayStorage &a) : type(Null) { - setArray(); - *arr = a; - } - // no bool constructor - would endanger the double one (int might convert the wrong way) - - ~Value() { - free(); - } - - void free() { - if (type == Array) delete arr; - else if (type == Object) delete obj; - type = Null; - num = 0; - } - - Value& setString(const char *s) { - free(); - type = String; - str.set(s); - return *this; - } - Value& setString(const IString &s) { - free(); - type = String; - str.set(s); - return *this; - } - Value& setNumber(double n) { - free(); - type = Number; - num = n; - return *this; - } - Value& setArray(ArrayStorage &a) { - free(); - type = Array; - arr = new ArrayStorage(); - *arr = a; - return *this; - } - Value& setArray() { - free(); - type = Array; - arr = new ArrayStorage(); - return *this; - } - Value& setNull() { - free(); - type = Null; - return *this; - } - Value& setBool(bool b) { // Bool in the name, as otherwise might overload over int - free(); - type = Bool; - boo = b; - return *this; - } - Value& setObject() { - free(); - type = Object; - obj = new ObjectStorage(); - return *this; - } - - bool isString() { return type == String; } - bool isNumber() { return type == Number; } - bool isArray() { return type == Array; } - bool isNull() { return type == Null; } - bool isBool() { return type == Bool; } - bool isObject() { return type == Object; } - - bool isBool(bool b) { return type == Bool && b == boo; } // avoid overloading == as it might overload over int - - const char* getCString() { - assert(isString()); - return str.str; - } - IString& getIString() { - assert(isString()); - return str; - } - double& getNumber() { - assert(isNumber()); - return num; - } - ArrayStorage& getArray() { - assert(isArray()); - return *arr; - } - bool& getBool() { - assert(isBool()); - return boo; - } - - Value& operator=(const Value& other) { - free(); - switch (other.type) { - case String: - setString(other.str); - break; - case Number: - setNumber(other.num); - break; - case Array: - setArray(*other.arr); - break; - case Null: - setNull(); - break; - case Bool: - setBool(other.boo); - break; - case Object: - assert(0); // TODO - } - return *this; - } - - bool operator==(const Value& other) { - if (type != other.type) return false; - switch (other.type) { - case String: - return str == other.str; - case Number: - return num == other.num; - case Array: - return this == &other; // if you want a deep compare, use deepCompare - case Null: - break; - case Bool: - return boo == other.boo; - case Object: - return this == &other; // if you want a deep compare, use deepCompare - } - return true; - } - - bool deepCompare(Ref ref) { - Value& other = *ref; - if (*this == other) return true; // either same pointer, or identical value type (string, number, null or bool) - if (type != other.type) return false; - if (type == Array) { - if (arr->size() != other.arr->size()) return false; - for (unsigned i = 0; i < arr->size(); i++) { - if (!(*arr)[i]->deepCompare((*other.arr)[i])) return false; - } - return true; - } else if (type == Object) { - if (obj->size() != other.obj->size()) return false; - for (auto i : *obj) { - if (other.obj->count(i.first) == 0) return false; - if (i.second->deepCompare((*other.obj)[i.first])) return false; - } - return true; - } - return false; - } - - char* parse(char* curr) { - #define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13) /* space, tab, linefeed/newline, or return */ - #define skip() { while (*curr && is_json_space(*curr)) curr++; } - skip(); - if (*curr == '"') { - // String - curr++; - char *close = strchr(curr, '"'); - assert(close); - *close = 0; // end this string, and reuse it straight from the input - setString(curr); - curr = close+1; - } else if (*curr == '[') { - // Array - curr++; - skip(); - setArray(); - while (*curr != ']') { - Ref temp = arena.alloc(); - arr->push_back(temp); - curr = temp->parse(curr); - skip(); - if (*curr == ']') break; - assert(*curr == ','); - curr++; - skip(); - } - curr++; - } else if (*curr == 'n') { - // Null - assert(strncmp(curr, "null", 4) == 0); - setNull(); - curr += 4; - } else if (*curr == 't') { - // Bool true - assert(strncmp(curr, "true", 4) == 0); - setBool(true); - curr += 4; - } else if (*curr == 'f') { - // Bool false - assert(strncmp(curr, "false", 5) == 0); - setBool(false); - curr += 5; - } else if (*curr == '{') { - // Object - curr++; - skip(); - setObject(); - while (*curr != '}') { - assert(*curr == '"'); - curr++; - char *close = strchr(curr, '"'); - assert(close); - *close = 0; // end this string, and reuse it straight from the input - IString key(curr); - curr = close+1; - skip(); - assert(*curr == ':'); - curr++; - skip(); - Ref value = arena.alloc(); - curr = value->parse(curr); - (*obj)[key] = value; - skip(); - if (*curr == '}') break; - assert(*curr == ','); - curr++; - skip(); - } - curr++; - } else { - // Number - char *after; - setNumber(strtod(curr, &after)); - curr = after; - } - return curr; - } - - void stringify(std::ostream &os, bool pretty=false) { - static int indent = 0; - #define indentify() { for (int i = 0; i < indent; i++) os << " "; } - switch (type) { - case String: - os << '"' << str.str << '"'; - break; - case Number: - os << std::setprecision(17) << num; // doubles can have 17 digits of precision - break; - case Array: - os << '['; - if (pretty) { - os << std::endl; - indent++; - } - for (unsigned i = 0; i < arr->size(); i++) { - if (i > 0) { - os << ", "; - if (pretty) os << std::endl; - } - indentify(); - (*arr)[i]->stringify(os, pretty); - } - if (pretty) { - os << std::endl; - indent--; - } - indentify(); - os << ']'; - break; - case Null: - os << "null"; - break; - case Bool: - os << (boo ? "true" : "false"); - break; - case Object: - os << '{'; - if (pretty) { - os << std::endl; - indent++; - } - bool first = true; - for (auto i : *obj) { - if (first) { - first = false; - } else { - os << ", "; - if (pretty) os << std::endl; - } - indentify(); - os << '"' << i.first.c_str() << "\": "; - i.second->stringify(os, pretty); - } - if (pretty) { - os << std::endl; - indent--; - } - indentify(); - os << '}'; - break; - } - } - - // String operations - - // Number operations - - // Array operations - - unsigned size() { - assert(isArray()); - return arr->size(); - } - - void setSize(unsigned size) { - assert(isArray()); - unsigned old = arr->size(); - if (old != size) arr->resize(size); - if (old < size) { - for (unsigned i = old; i < size; i++) { - (*arr)[i] = arena.alloc(); - } - } - } - - Ref& operator[](unsigned x) { - assert(isArray()); - assert(x < arr->size()); - return (*arr)[x]; - } - - Value& push_back(Ref r) { - assert(isArray()); - arr->push_back(r); - return *this; - } - Ref pop_back() { - assert(isArray()); - Ref ret = arr->back(); - arr->pop_back(); - return ret; - } - - Ref back() { - assert(isArray()); - if (arr->size() == 0) return nullptr; - return arr->back(); - } - - void splice(int x, int num) { - assert(isArray()); - arr->erase(arr->begin() + x, arr->begin() + x + num); - } - - void insert(int x, int num) { - arr->insert(arr->begin() + x, num, Ref()); - } - void insert(int x, Ref node) { - arr->insert(arr->begin() + x, 1, node); - } - - int indexOf(Ref other) { - assert(isArray()); - for (unsigned i = 0; i < arr->size(); i++) { - if (other == (*arr)[i]) return i; - } - return -1; - } - - Ref map(std::function func) { - assert(isArray()); - Ref ret = arena.alloc(); - ret->setArray(); - for (unsigned i = 0; i < arr->size(); i++) { - ret->push_back(func((*arr)[i])); - } - return ret; - } - - Ref filter(std::function func) { - assert(isArray()); - Ref ret = arena.alloc(); - ret->setArray(); - for (unsigned i = 0; i < arr->size(); i++) { - Ref curr = (*arr)[i]; - if (func(curr)) ret->push_back(curr); - } - return ret; - } - - /* - void forEach(std::function func) { - for (unsigned i = 0; i < arr->size(); i++) { - func((*arr)[i]); - } - } - */ - - // Null operations - - // Bool operations - - // Object operations - - Ref& operator[](IString x) { - assert(isObject()); - return (*obj)[x]; - } - - bool has(IString x) { - assert(isObject()); - return obj->count(x) > 0; - } -}; - -// Ref methods - -Ref& Ref::operator[](unsigned x) { - return (*get())[x]; -} - -Ref& Ref::operator[](IString x) { - return (*get())[x]; -} - -bool Ref::operator==(const char *str) { - return get()->isString() && !strcmp(get()->str.str, str); -} - -bool Ref::operator!=(const char *str) { - return get()->isString() ? strcmp(get()->str.str, str) : true; -} - -bool Ref::operator==(const IString &str) { - return get()->isString() && get()->str == str; -} - -bool Ref::operator!=(const IString &str) { - return get()->isString() && get()->str != str; -} - -bool Ref::operator==(Ref other) { - return **this == *other; -} - -bool Ref::operator!() { - return !get() || get()->isNull(); -} - -// Arena methods - -Ref Arena::alloc() { - if (chunks.size() == 0 || index == CHUNK_SIZE) { - chunks.push_back(new Value[CHUNK_SIZE]); - index = 0; - } - return &chunks.back()[index++]; -} - -// dump - -void dump(const char *str, Ref node, bool pretty) { - std::cerr << str << ": "; - if (!!node) node->stringify(std::cerr, pretty); - else std::cerr << "(nullptr)"; - std::cerr << std::endl; -} - diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index 72969f16bd65c..b5f7ddfff71e0 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -3,7 +3,7 @@ #include #include -#include "minijson.h" +#include "simple_ast.h" typedef std::vector StringVec; @@ -13,67 +13,6 @@ typedef std::vector StringVec; Ref doc, extraInfo; -IString TOPLEVEL("toplevel"), - DEFUN("defun"), - BLOCK("block"), - STAT("stat"), - ASSIGN("assign"), - NAME("name"), - VAR("var"), - CONDITIONAL("conditional"), - BINARY("binary"), - RETURN("return"), - IF("if"), - WHILE("while"), - DO("do"), - FOR("for"), - SEQ("seq"), - SUB("sub"), - CALL("call"), - NUM("num"), - LABEL("label"), - BREAK("break"), - CONTINUE("continue"), - SWITCH("switch"), - STRING("string"), - INF("inf"), - NaN("nan"), - TEMP_RET0("tempRet0"), - UNARY_PREFIX("unary-prefix"), - UNARY_POSTFIX("unary-postfix"), - MATH_FROUND("Math_fround"), - SIMD_FLOAT32X4("SIMD_float32x4"), - SIMD_INT32X4("SIMD_int32x4"), - PLUS("+"), - MINUS("-"), - OR("|"), - AND("&"), - XOR("^"), - L_NOT("!"), - B_NOT("~"), - LT("<"), - GE(">="), - LE("<="), - GT(">"), - EQ("=="), - NE("!="), - DIV("/"), - MOD("%"), - RSHIFT(">>"), - LSHIFT("<<"), - TRSHIFT(">>>"), - TEMP_DOUBLE_PTR("tempDoublePtr"), - HEAP8("HEAP8"), - HEAP16("HEAP16"), - HEAP32("HEAP32"), - HEAPF32("HEAPF32"), - HEAPU8("HEAPU8"), - HEAPU16("HEAPU16"), - HEAPU32("HEAPU32"), - HEAPF64("HEAPF64"), - F0("f0"), - EMPTY(""); - //================== // Infrastructure //================== @@ -115,144 +54,6 @@ IString getHeapStr(int x, bool unsign) { return ":("; } -// Traversals - -struct TraverseInfo { - Ref node; - int index; -}; - -template -struct StackedStack { // a stack, on the stack - T stackStorage[init]; - T* storage; - int used, available; // used amount, available amount - bool alloced; - - StackedStack() : used(0), available(init), alloced(false) { - storage = stackStorage; - } - ~StackedStack() { - if (alloced) free(storage); - } - - int size() { return used; } - - void push_back(const T& t) { - assert(used <= available); - if (used == available) { - available *= 2; - if (!alloced) { - T* old = storage; - storage = (T*)malloc(sizeof(T)*available); - memcpy(storage, old, sizeof(T)*used); - alloced = true; - } else { - storage = (T*)realloc(storage, sizeof(T)*available); - } - } - assert(used < available); - assert(storage); - storage[used++] = t; - } - - T& back() { - assert(used > 0); - return storage[used-1]; - } - - void pop_back() { - assert(used > 0); - used--; - } -}; - -#define visitable(node) (node->isArray() and node->size() > 0) - -#define TRAV_STACK 40 - -// Traverse, calling visit before the children -void traversePre(Ref node, std::function visit) { - if (!visitable(node)) return; - visit(node); - StackedStack stack; - stack.push_back({ node, 0 }); - while (stack.size() > 0) { - TraverseInfo& top = stack.back(); - if (top.index < top.node->size()) { - Ref sub = top.node[top.index]; - top.index++; - if (visitable(sub)) { - visit(sub); - stack.push_back({ sub, 0 }); - } - } else { - stack.pop_back(); - } - } -} - -// Traverse, calling visitPre before the children and visitPost after -void traversePrePost(Ref node, std::function visitPre, std::function visitPost) { - if (!visitable(node)) return; - visitPre(node); - StackedStack stack; - stack.push_back({ node, 0 }); - while (stack.size() > 0) { - TraverseInfo& top = stack.back(); - if (top.index < top.node->size()) { - Ref sub = top.node[top.index]; - top.index++; - if (visitable(sub)) { - visitPre(sub); - stack.push_back({ sub, 0 }); - } - } else { - visitPost(top.node); - stack.pop_back(); - } - } - visitPost(node); -} - -// Traverse, calling visitPre before the children and visitPost after. If pre returns false, do not traverse children -void traversePrePostConditional(Ref node, std::function visitPre, std::function visitPost) { - if (!visitable(node)) return; - if (!visitPre(node)) return; - StackedStack stack; - stack.push_back({ node, 0 }); - while (stack.size() > 0) { - TraverseInfo& top = stack.back(); - if (top.index < top.node->size()) { - Ref sub = top.node[top.index]; - top.index++; - if (visitable(sub)) { - if (visitPre(sub)) { - stack.push_back({ sub, 0 }); - } - } - } else { - visitPost(top.node); - stack.pop_back(); - } - } - visitPost(node); -} - -// Traverses all the top-level functions in the document -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++) { - Ref curr = stats[i]; - if (curr[0] == DEFUN) visit(curr); - } - } else if (ast[0] == DEFUN) { - visit(ast); - } -} - Ref deStat(Ref node) { if (node[0] == STAT) return node[1]; return node; @@ -916,7 +717,11 @@ int measureCost(Ref ast) { // Params //================== -bool preciseF32 = false; +bool preciseF32 = false, + receiveJSON = false, + emitJSON = false, + minifyWhitespace = false, + last = false; //===================== // Optimization passes @@ -930,21 +735,10 @@ bool preciseF32 = false; return node->isString() && count(node->getIString()) > 0; \ } -class StringSet : public std::unordered_set { +class StringSet : public cashew::IStringSet { public: StringSet() {} - StringSet(const char *init) { // comma-delimited list - int size = strlen(init); - char *curr = (char*)malloc(size+1); // leaked! - strcpy(curr, init); - while (1) { - char *end = strchr(curr, ' '); - if (end) *end = 0; - insert(curr); - if (!end) break; - curr = end + 1; - } - } + StringSet(const char *str) : IStringSet(str) {} HASES @@ -967,7 +761,10 @@ StringSet USEFUL_BINARY_OPS("<< >> | & ^"), StringSet ASSOCIATIVE_BINARIES("+ * | & ^"), CONTROL_FLOW("do while for if switch"), LOOP("do while for"), - NAME_OR_NUM("name num"); + NAME_OR_NUM("name num"), + CONDITION_CHECKERS("if do while switch"), + SAFE_TO_DROP_COERCION("unary-prefix name num"); + bool isFunctionTable(const char *name) { static const char *functionTable = "FUNCTION_TABLE"; @@ -979,6 +776,45 @@ bool isFunctionTable(Ref value) { return value->isString() && isFunctionTable(value->getCString()); } +// Internal utilities + +bool canDropCoercion(Ref node) { + if (SAFE_TO_DROP_COERCION.has(node[0])) return true; + if (node[0] == BINARY) { + switch (node[1]->getCString()[0]) { + case '>': return node[1] == RSHIFT || node[1] == TRSHIFT; + case '<': return node[1] == LSHIFT; + case '|': case '^': case '&': return true; + } + } + return false; +} + +Ref simplifyCondition(Ref node) { + node = simplifyNotCompsDirect(node); + // on integers, if (x == 0) is the same as if (x), and if (x != 0) as if (!x) + if (node[0] == BINARY && (node[1] == EQ || node[1] == NE)) { + Ref target; + if (detectType(node[2]) == ASM_INT && node[3][0] == NUM && node[3][1]->getNumber() == 0) { + target = node[2]; + } else if (detectType(node[3]) == ASM_INT && node[2][0] == NUM && node[2][1]->getNumber() == 0) { + target = node[3]; + } + if (!!target) { + if (target[0] == BINARY && (target[1] == OR || target[1] == TRSHIFT) && target[3][0] == NUM && target[3][1]->getNumber() == 0 && + canDropCoercion(target[2])) { + target = target[2]; // drop the coercion, in a condition it is ok to do if (x) + } + if (node[1] == EQ) { + return make2(UNARY_PREFIX, L_NOT, target); + } else { + return target; + } + } + } + return node; +} + // Passes // Eliminator aka Expressionizer @@ -2740,6 +2576,109 @@ void minifyLocals(Ref ast) { }); } +void asmLastOpts(Ref ast) { + std::vector statsStack; + traverseFunctions(ast, [&](Ref fun) { + traversePrePost(fun, [&](Ref node) { + Ref type = node[0]; + Ref stats = getStatements(node); + if (!!stats) statsStack.push_back(stats); + if (CONDITION_CHECKERS.has(type)) { + node[1] = simplifyCondition(node[1]); + } + if (type == WHILE && node[1][0] == NUM && node[1][1]->getNumber() == 1 && node[2][0] == BLOCK && node[2]->size() == 2) { + // This is at the end of the pipeline, we can assume all other optimizations are done, and we modify loops + // into shapes that might confuse other passes + + // while (1) { .. if (..) { break } } ==> do { .. } while(..) + Ref stats = node[2][1]; + Ref last = stats->back(); + if (!!last && last[0] == IF && (last->size() < 4 || !last[3]) && last[2][0] == BLOCK && !!last[2][1][0]) { + Ref lastStats = last[2][1]; + int lastNum = lastStats->size(); + Ref lastLast = lastStats[lastNum-1]; + if (!(lastLast[0] == BREAK && !lastLast[1])) return;// if not a simple break, dangerous + for (int i = 0; i < lastNum; i++) { + if (lastStats[i][0] != STAT && lastStats[i][0] != BREAK) return; // something dangerous + } + // ok, a bunch of statements ending in a break + bool abort = false; + int stack = 0; + int breaks = 0; + traversePrePost(stats, [&](Ref node) { + Ref type = node[0]; + if (type == CONTINUE) { + if (stack == 0 || !!node[1]) { // abort if labeled (we do not analyze labels here yet), or a continue directly on us + abort = true; + } + } else if (type == BREAK) { + if (stack == 0 || !!node[1]) { // relevant if labeled (we do not analyze labels here yet), or a break directly on us + breaks++; + } + } else if (LOOP.has(type)) { + stack++; + } + }, [&](Ref node) { + if (LOOP.has(node[0])) { + stack--; + } + }); + if (abort) return; + assert(breaks > 0); + if (lastStats->size() > 1 && breaks != 1) return; // if we have code aside from the break, we can only move it out if there is just one break + if (statsStack.size() < 1) return; // no chance we have this stats on hand + // start to optimize + if (lastStats->size() > 1) { + Ref parent = statsStack.back(); + 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++) { + parent[me+1+i] = lastStats[i]; + } + } + Ref conditionToBreak = last[1]; + stats->pop_back(); + node[0]->setString(DO); + node[1] = simplifyNotCompsDirect(make2(UNARY_PREFIX, L_NOT, conditionToBreak)); + } + } else if (type == BINARY) { + if (node[1] == AND) { + if (node[3][0] == UNARY_PREFIX && node[3][1] == MINUS && node[3][2][0] == NUM && node[3][2][1]->getNumber() == 1) { + // Change &-1 into |0, at this point the hint is no longer needed + node[1]->setString(OR); + node[3] = node[3][2]; + node[3][1]->setNumber(0); + } + } else if (node[1] == MINUS && node[3][0] == UNARY_PREFIX) { + // avoid X - (-Y) because some minifiers buggily emit X--Y which is invalid as -- can be a unary. Transform to + // X + Y + if (node[3][1] == MINUS) { // integer + node[1]->setString(PLUS); + node[3] = node[3][2]; + } else if (node[3][1] == PLUS) { // float + if (node[3][2][0] == UNARY_PREFIX && node[3][2][1] == MINUS) { + node[1]->setString(PLUS); + node[3][2] = node[3][2][2]; + } + } + } + } + }, [&](Ref node) { + if (statsStack.size() > 0) { + Ref stats = getStatements(node); + if (!!stats) statsStack.pop_back(); + } + }); + // convert { singleton } into singleton + traversePre(fun, [](Ref node) { + if (node[0] == BLOCK && !!getStatements(node) && node[1]->size() == 1) { + safeCopy(node, node[1][0]); + } + }); + }); +} + //================== // Main //================== @@ -2747,37 +2686,52 @@ void minifyLocals(Ref ast) { #include // only use this for param checking int main(int argc, char **argv) { + // Read directives + for (int i = 2; i < argc; i++) { + std::string str(argv[i]); + if (str == "asm") {} // the only possibility for us + else if (str == "asmPreciseF32") preciseF32 = true; + else if (str == "receiveJSON") receiveJSON = true; + else if (str == "emitJSON") emitJSON = true; + else if (str == "minifyWhitespace") minifyWhitespace = true; + else if (str == "last") last = true; + } + // Read input file FILE *f = fopen(argv[1], "r"); assert(f); fseek(f, 0, SEEK_END); int size = ftell(f); - char *json = new char[size+1]; + char *input = new char[size+1]; rewind(f); - int num = fread(json, 1, size, f); + int num = fread(input, 1, size, f); assert(num == size); fclose(f); - json[size] = 0; + input[size] = 0; - char *comment = strstr(json, "//"); - char *extraInfoStart = strstr(json, "// EXTRA_INFO:"); - if (comment) *comment = 0; // drop off the comments; TODO: parse extra info + char *extraInfoStart = strstr(input, "// EXTRA_INFO:"); if (extraInfoStart) { extraInfo = arena.alloc(); extraInfo->parse(extraInfoStart + 14); + *extraInfoStart = 0; // ignore extra info when parsing } - // Parse JSON source into the document - doc = arena.alloc(); - doc->parse(json); - // do not free json, it's contents are used as strings + if (receiveJSON) { + // Parse JSON source into the document + doc = arena.alloc(); + doc->parse(input); + } else { + cashew::Parser builder; + doc = builder.parseToplevel(input); + } + // do not free input, its contents are used as strings // Run passes on the Document for (int i = 2; i < argc; i++) { std::string str(argv[i]); if (str == "asm") {} // the default for us - else if (str == "asmPreciseF32") preciseF32 = true; - else if (str == "receiveJSON" || str == "emitJSON") {} // the default for us + else if (str == "asmPreciseF32") {} + else if (str == "receiveJSON" || str == "emitJSON") {} else if (str == "eliminate") eliminate(doc); else if (str == "eliminateMemSafe") eliminateMemSafe(doc); else if (str == "simplifyExpressions") simplifyExpressions(doc); @@ -2786,15 +2740,24 @@ int main(int argc, char **argv) { else if (str == "registerize") registerize(doc); else if (str == "minifyLocals") minifyLocals(doc); else if (str == "minifyWhitespace") {} + else if (str == "asmLastOpts") asmLastOpts(doc); + else if (str == "last") {} + else if (str == "noop") {} else { fprintf(stderr, "unrecognized argument: %s\n", str.c_str()); assert(0); } } - // Emit JSON of modified Document - doc->stringify(std::cout); - std::cout << std::endl; + // Emit + if (emitJSON) { + doc->stringify(std::cout); + std::cout << "\n"; + } else { + JSPrinter jser(!minifyWhitespace, last, doc); + jser.printAst(); + std::cout << jser.buffer << "\n"; + } return 0; } diff --git a/tools/optimizer/parser.cpp b/tools/optimizer/parser.cpp new file mode 100644 index 0000000000000..4a642a7103b5b --- /dev/null +++ b/tools/optimizer/parser.cpp @@ -0,0 +1,140 @@ + +#include "parser.h" + +namespace cashew { + +// common strings + +IString TOPLEVEL("toplevel"), + DEFUN("defun"), + BLOCK("block"), + STAT("stat"), + ASSIGN("assign"), + NAME("name"), + VAR("var"), + CONDITIONAL("conditional"), + BINARY("binary"), + RETURN("return"), + IF("if"), + ELSE("else"), + WHILE("while"), + DO("do"), + FOR("for"), + SEQ("seq"), + SUB("sub"), + CALL("call"), + NUM("num"), + LABEL("label"), + BREAK("break"), + CONTINUE("continue"), + SWITCH("switch"), + STRING("string"), + INF("inf"), + NaN("nan"), + TEMP_RET0("tempRet0"), + UNARY_PREFIX("unary-prefix"), + UNARY_POSTFIX("unary-postfix"), + MATH_FROUND("Math_fround"), + SIMD_FLOAT32X4("SIMD_float32x4"), + SIMD_INT32X4("SIMD_int32x4"), + PLUS("+"), + MINUS("-"), + OR("|"), + AND("&"), + XOR("^"), + L_NOT("!"), + B_NOT("~"), + LT("<"), + GE(">="), + LE("<="), + GT(">"), + EQ("=="), + NE("!="), + DIV("/"), + MOD("%"), + MUL("*"), + RSHIFT(">>"), + LSHIFT("<<"), + TRSHIFT(">>>"), + TEMP_DOUBLE_PTR("tempDoublePtr"), + HEAP8("HEAP8"), + HEAP16("HEAP16"), + HEAP32("HEAP32"), + HEAPF32("HEAPF32"), + HEAPU8("HEAPU8"), + HEAPU16("HEAPU16"), + HEAPU32("HEAPU32"), + HEAPF64("HEAPF64"), + F0("f0"), + EMPTY(""), + FUNCTION("function"), + OPEN_PAREN("("), + OPEN_BRACE("["), + OPEN_CURLY("{"), + CLOSE_CURLY("}"), + COMMA(","), + QUESTION("?"), + COLON(":"), + CASE("case"), + DEFAULT("default"), + DOT("dot"), + PERIOD("."), + NEW("new"), + ARRAY("array"), + OBJECT("object"), + 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(". ! ~ - + * / % + - << >> >>> < <= > >= == != & ^ | ? : = ,"); + +const char *OPERATOR_INITS = "+-*/%<>&^|~=!,?:.", + *SEPARATORS = "([;{}"; + +int MAX_OPERATOR_SIZE = 3; + +std::vector operatorClasses; + +static std::vector> precedences; // op, type => prec + +struct Init { + Init() { + // operators, rtl, type + operatorClasses.push_back(OperatorClass(".", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("! ~ + -", true, OperatorClass::Prefix)); + operatorClasses.push_back(OperatorClass("* / %", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("+ -", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("<< >> >>>", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("< <= > >=", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("== !=", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("&", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("^", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("|", false, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass("? :", true, OperatorClass::Tertiary)); + operatorClasses.push_back(OperatorClass("=", true, OperatorClass::Binary)); + operatorClasses.push_back(OperatorClass(",", true, OperatorClass::Binary)); + + precedences.resize(OperatorClass::Tertiary + 1); + + for (int prec = 0; prec < operatorClasses.size(); prec++) { + for (auto curr : operatorClasses[prec].ops) { + precedences[operatorClasses[prec].type][curr] = prec; + } + } + } +}; + +Init init; + +int OperatorClass::getPrecedence(Type type, IString op) { + return precedences[type][op]; +} + +bool OperatorClass::getRtl(int prec) { + return operatorClasses[prec].rtl; +} + +bool isIdentInit(char x) { return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == '_' || x == '$'; } +bool isIdentPart(char x) { return isIdentInit(x) || (x >= '0' && x <= '9'); } + +} // namespace cashew + diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h new file mode 100644 index 0000000000000..1e822e908d6c4 --- /dev/null +++ b/tools/optimizer/parser.h @@ -0,0 +1,835 @@ +// Pure parsing. Calls methods on a Builder (template argument) to actually construct the AST +// +// XXX All parsing methods assume they take ownership of the input string. This lets them reuse +// parts of it. You will segfault if the input string cannot be reused and written to. + +#include +#include + +#include + +#include "istring.h" + +namespace cashew { + +// common strings + +extern IString TOPLEVEL, + DEFUN, + BLOCK, + STAT, + ASSIGN, + NAME, + VAR, + CONDITIONAL, + BINARY, + RETURN, + IF, + ELSE, + WHILE, + DO, + FOR, + SEQ, + SUB, + CALL, + NUM, + LABEL, + BREAK, + CONTINUE, + SWITCH, + STRING, + INF, + NaN, + TEMP_RET0, + UNARY_PREFIX, + UNARY_POSTFIX, + MATH_FROUND, + SIMD_FLOAT32X4, + SIMD_INT32X4, + PLUS, + MINUS, + OR, + AND, + XOR, + L_NOT, + B_NOT, + LT, + GE, + LE, + GT, + EQ, + NE, + DIV, + MOD, + MUL, + RSHIFT, + LSHIFT, + TRSHIFT, + TEMP_DOUBLE_PTR, + HEAP8, + HEAP16, + HEAP32, + HEAPF32, + HEAPU8, + HEAPU16, + HEAPU32, + HEAPF64, + F0, + EMPTY, + FUNCTION, + OPEN_PAREN, + OPEN_BRACE, + OPEN_CURLY, + CLOSE_CURLY, + COMMA, + QUESTION, + COLON, + CASE, + DEFAULT, + DOT, + PERIOD, + NEW, + ARRAY, + OBJECT, + SET; + +extern IStringSet keywords, allOperators; + +extern const char *OPERATOR_INITS, *SEPARATORS; + +extern int MAX_OPERATOR_SIZE, LOWEST_PREC; + +struct OperatorClass { + enum Type { + Binary = 0, + Prefix = 1, + Postfix = 2, + Tertiary = 3 + }; + + IStringSet ops; + bool rtl; + Type type; + + OperatorClass(const char* o, bool r, Type t) : ops(o), rtl(r), type(t) {} + + static int getPrecedence(Type type, IString op); + static bool getRtl(int prec); +}; + +extern std::vector operatorClasses; + +extern bool isIdentInit(char x); +extern bool isIdentPart(char x); + +// parser + +template +class Parser { + + static bool isSpace(char x) { return x == 32 || x == 9 || x == 10 || x == 13; } /* space, tab, linefeed/newline, or return */ + static char* skipSpace(char* curr) { + while (*curr) { + if (isSpace(*curr)) { + curr++; + continue; + } + if (curr[0] == '/' && curr[1] == '/') { + curr += 2; + while (*curr && *curr != '\n') curr++; + if (*curr) curr++; + continue; + } + if (curr[0] == '/' && curr[1] == '*') { + curr += 2; + while (*curr && (curr[0] != '*' || curr[1] != '/')) curr++; + curr += 2; + continue; + } + break; + } + return curr; + } + + static bool isDigit(char x) { return x >= '0' && x <= '9'; } + + static bool hasChar(const char* list, char x) { while (*list) if (*list++ == x) return true; return false; } + + // An atomic fragment of something. Stops at a natural boundary. + enum FragType { + KEYWORD = 0, + OPERATOR = 1, + IDENT = 2, + STRING = 3, // without quotes + NUMBER = 4, + SEPARATOR = 5 + }; + + struct Frag { + union { + IString str; + double num; + }; + int size; + FragType type; + + Frag(char* src) { + assert(!isSpace(*src)); + char *start = src; + if (isIdentInit(*src)) { + // read an identifier or a keyword + src++; + while (isIdentPart(*src)) { + src++; + } + if (*src == 0) { + str.set(start); + } else { + char temp = *src; + *src = 0; + str.set(start, false); + *src = temp; + } + type = keywords.has(str) ? KEYWORD : IDENT; + } else if (*src == '"' || *src == '\'') { + char *end = strchr(src+1, *src); + *end = 0; + str.set(src+1); + src = end+1; + type = STRING; + } else if (isDigit(*src) || (src[0] == '.' && isDigit(src[1]))) { + num = strtod(start, &src); + assert(src > start); + type = NUMBER; + } else if (hasChar(OPERATOR_INITS, *src)) { + switch (*src) { + case '!': str = src[1] == '=' ? str = NE : str = L_NOT; break; + case '%': str = MOD; break; + case '&': str = AND; break; + case '*': str = MUL; break; + case '+': str = PLUS; break; + case ',': str = COMMA; break; + case '-': str = MINUS; break; + case '.': str = PERIOD; break; + case '/': str = DIV; break; + case ':': str = COLON; break; + case '<': str = src[1] == '<' ? LSHIFT : (src[1] == '=' ? LE : LT); break; + case '=': str = src[1] == '=' ? EQ : SET; break; + case '>': str = src[1] == '>' ? (src[2] == '>' ? TRSHIFT : RSHIFT) : (src[1] == '=' ? GE : GT); break; + case '?': str = QUESTION; break; + case '^': str = XOR; break; + case '|': str = OR; break; + case '~': str = B_NOT; break; + } + assert(!str.isNull()); + size = strlen(str.str); +#ifndef NDEBUG + char temp = start[size]; + start[size] = 0; + assert(strcmp(str.str, start) == 0); + start[size] = temp; +#endif + type = OPERATOR; + return; + } else if (hasChar(SEPARATORS, *src)) { + type = SEPARATOR; + char temp = src[1]; + src[1] = 0; + str.set(src, false); + src[1] = temp; + src++; + } else { + dump("frag parsing", src); + assert(0); + } + size = src - start; + } + }; + + // Parses an element in a list of such elements, e.g. list of statements in a block, or list of parameters in a call + NodeRef parseElement(char*& src, const char* seps=";") { + //dump("parseElement", src); + src = skipSpace(src); + Frag frag(src); + src += frag.size; + switch (frag.type) { + case KEYWORD: { + return parseAfterKeyword(frag, src, seps); + } + case IDENT: + case STRING: + case NUMBER: { + src = skipSpace(src); + if (frag.type == IDENT) return parseAfterIdent(frag, src, seps); + else return parseExpression(parseFrag(frag), src, seps); + } + case SEPARATOR: { + if (frag.str == OPEN_PAREN) return parseExpression(parseAfterParen(src), src, seps); + if (frag.str == OPEN_BRACE) return parseExpression(parseAfterBrace(src), src, seps); + if (frag.str == OPEN_CURLY) return parseExpression(parseAfterCurly(src), src, seps); + assert(0); + } + case OPERATOR: { + return parseExpression(frag.str, src, seps); + } + default: /* dump("parseElement", src); printf("bad frag type: %d\n", frag.type); */ assert(0); + } + return nullptr; + } + + NodeRef parseFrag(Frag& frag) { + switch (frag.type) { + case IDENT: return Builder::makeName(frag.str); + case STRING: return Builder::makeString(frag.str); + case NUMBER: return Builder::makeNumber(frag.num); + default: assert(0); + } + return nullptr; + } + + NodeRef parseAfterKeyword(Frag& frag, char*& src, const char* seps) { + src = skipSpace(src); + if (frag.str == FUNCTION) return parseFunction(frag, src, seps); + else if (frag.str == VAR) return parseVar(frag, src, seps); + else if (frag.str == RETURN) return parseReturn(frag, src, seps); + else if (frag.str == IF) return parseIf(frag, src, seps); + else if (frag.str == DO) return parseDo(frag, src, seps); + else if (frag.str == WHILE) return parseWhile(frag, src, seps); + else if (frag.str == BREAK) return parseBreak(frag, src, seps); + else if (frag.str == CONTINUE) return parseContinue(frag, src, seps); + else if (frag.str == SWITCH) return parseSwitch(frag, src, seps); + else if (frag.str == NEW) return parseNew(frag, src, seps); + dump(frag.str.str, src); + assert(0); + return nullptr; + } + + NodeRef parseFunction(Frag& frag, char*& src, const char* seps) { + Frag name(src); + assert(name.type == IDENT); + src += name.size; + NodeRef ret = Builder::makeFunction(name.str); + src = skipSpace(src); + assert(*src == '('); + src++; + while (1) { + src = skipSpace(src); + if (*src == ')') break; + Frag arg(src); + assert(arg.type == IDENT); + src += arg.size; + Builder::appendArgumentToFunction(ret, arg.str); + src = skipSpace(src); + if (*src && *src == ')') break; + if (*src && *src == ',') { + src++; + continue; + } + assert(0); + } + assert(*src == ')'); + src++; + parseBracketedBlock(src, ret); + // TODO: parse expression? + return ret; + } + + NodeRef parseVar(Frag& frag, char*& src, const char* seps) { + NodeRef ret = Builder::makeVar(); + while (1) { + src = skipSpace(src); + if (*src == ';') break; + Frag name(src); + assert(name.type == IDENT); + NodeRef value; + src += name.size; + src = skipSpace(src); + if (*src == '=') { + src++; + src = skipSpace(src); + value = parseElement(src, ";,"); + } + Builder::appendToVar(ret, name.str, value); + src = skipSpace(src); + if (*src && *src == ';') break; + if (*src && *src == ',') { + src++; + continue; + } + assert(0); + } + assert(*src == ';'); + src++; + return ret; + } + + NodeRef parseReturn(Frag& frag, char*& src, const char* seps) { + src = skipSpace(src); + NodeRef value = !hasChar(seps, *src) ? parseElement(src, seps) : nullptr; + src = skipSpace(src); + assert(hasChar(seps, *src)); + if (*src == ';') src++; + return Builder::makeReturn(value); + } + + NodeRef parseIf(Frag& frag, char*& src, const char* seps) { + NodeRef condition = parseParenned(src); + NodeRef ifTrue = parseMaybeBracketed(src, seps); + src = skipSpace(src); + NodeRef ifFalse; + if (*src && !hasChar(seps, *src)) { + Frag next(src); + if (next.type == KEYWORD && next.str == ELSE) { + src += next.size; + ifFalse = parseMaybeBracketed(src, seps); + } + } + return Builder::makeIf(condition, ifTrue, ifFalse); + } + + NodeRef parseDo(Frag& frag, char*& src, const char* seps) { + NodeRef body = parseMaybeBracketed(src, seps); + src = skipSpace(src); + Frag next(src); + assert(next.type == KEYWORD && next.str == WHILE); + src += next.size; + NodeRef condition = parseParenned(src); + return Builder::makeDo(body, condition); + } + + NodeRef parseWhile(Frag& frag, char*& src, const char* seps) { + NodeRef condition = parseParenned(src); + NodeRef body = parseMaybeBracketed(src, seps); + return Builder::makeWhile(condition, body); + } + + NodeRef parseBreak(Frag& frag, char*& src, const char* seps) { + src = skipSpace(src); + Frag next(src); + if (next.type == IDENT) src += next.size; + return Builder::makeBreak(next.type == IDENT ? next.str : IString()); + } + + NodeRef parseContinue(Frag& frag, char*& src, const char* seps) { + src = skipSpace(src); + Frag next(src); + if (next.type == IDENT) src += next.size; + return Builder::makeContinue(next.type == IDENT ? next.str : IString()); + } + + NodeRef parseSwitch(Frag& frag, char*& src, const char* seps) { + NodeRef ret = Builder::makeSwitch(parseParenned(src)); + src = skipSpace(src); + assert(*src == '{'); + src++; + while (1) { + // find all cases and possibly a default + src = skipSpace(src); + if (*src == '}') break; + Frag next(src); + if (next.type == KEYWORD) { + if (next.str == CASE) { + src += next.size; + src = skipSpace(src); + NodeRef arg; + Frag value(src); + if (value.type == NUMBER) { + arg = parseFrag(value); + src += value.size; + } else { + assert(value.type == OPERATOR); + assert(value.str == MINUS); + src += value.size; + src = skipSpace(src); + Frag value2(src); + assert(value2.type == NUMBER); + arg = Builder::makePrefix(MINUS, parseFrag(value2)); + src += value2.size; + } + Builder::appendCaseToSwitch(ret, arg); + src = skipSpace(src); + assert(*src == ':'); + src++; + continue; + } else if (next.str == DEFAULT) { + src += next.size; + Builder::appendDefaultToSwitch(ret); + src = skipSpace(src); + assert(*src == ':'); + src++; + continue; + } + // otherwise, may be some keyword that happens to start a block (e.g. case 1: _return_ 5) + } + // not case X: or default: or }, so must be some code + src = skipSpace(src); + bool explicitBlock = *src == '{'; + Builder::appendCodeToSwitch(ret, parseMaybeBracketedBlock(src, ";}", CASE, DEFAULT), explicitBlock); + } + src = skipSpace(src); + assert(*src == '}'); + src++; + return ret; + } + + NodeRef parseNew(Frag& frag, char*& src, const char* seps) { + return Builder::makeNew(parseElement(src, seps)); + } + + NodeRef parseAfterIdent(Frag& frag, char*& src, const char* seps) { + assert(!isSpace(*src)); + if (*src == '(') return parseExpression(parseCall(parseFrag(frag), src), src, seps); + if (*src == '[') return parseExpression(parseIndexing(parseFrag(frag), src), src, seps); + if (*src == ':' && expressionPartsStack.back().size() == 0) { + src++; + return Builder::makeLabel(frag.str, parseElement(src, seps)); + } + if (*src == '.') return parseExpression(parseDotting(parseFrag(frag), src), src, seps); + return parseExpression(parseFrag(frag), src, seps); + } + + NodeRef parseCall(NodeRef target, char*& src) { + expressionPartsStack.resize(expressionPartsStack.size()+1); + assert(*src == '('); + src++; + NodeRef ret = Builder::makeCall(target); + while (1) { + src = skipSpace(src); + if (*src == ')') break; + Builder::appendToCall(ret, parseElement(src, ",)")); + src = skipSpace(src); + if (*src && *src == ')') break; + if (*src && *src == ',') { + src++; + continue; + } + assert(0); + } + src++; + assert(expressionPartsStack.back().size() == 0); + expressionPartsStack.pop_back(); + return ret; + } + + NodeRef parseIndexing(NodeRef target, char*& src) { + expressionPartsStack.resize(expressionPartsStack.size()+1); + assert(*src == '['); + src++; + NodeRef ret = Builder::makeIndexing(target, parseElement(src, "]")); + src = skipSpace(src); + assert(*src == ']'); + src++; + assert(expressionPartsStack.back().size() == 0); + expressionPartsStack.pop_back(); + return ret; + } + + NodeRef parseDotting(NodeRef target, char*& src) { + assert(*src == '.'); + src++; + Frag key(src); + assert(key.type == IDENT); + src += key.size; + return Builder::makeDot(target, key.str); + } + + NodeRef parseAfterParen(char*& src) { + expressionPartsStack.resize(expressionPartsStack.size()+1); + src = skipSpace(src); + NodeRef ret = parseElement(src, ")"); + src = skipSpace(src); + assert(*src == ')'); + src++; + assert(expressionPartsStack.back().size() == 0); + expressionPartsStack.pop_back(); + return ret; + } + + NodeRef parseAfterBrace(char*& src) { + expressionPartsStack.resize(expressionPartsStack.size()+1); + NodeRef ret = Builder::makeArray(); + while (1) { + src = skipSpace(src); + assert(*src); + if (*src == ']') break; + NodeRef element = parseElement(src, ",]"); + Builder::appendToArray(ret, element); + src = skipSpace(src); + if (*src == ',') { + src++; + continue; + } else assert(*src == ']'); + } + assert(*src == ']'); + src++; + return ret; + } + + NodeRef parseAfterCurly(char*& src) { + expressionPartsStack.resize(expressionPartsStack.size()+1); + NodeRef ret = Builder::makeObject(); + while (1) { + src = skipSpace(src); + assert(*src); + if (*src == '}') break; + Frag key(src); + assert(key.type == IDENT || key.type == STRING); + src += key.size; + src = skipSpace(src); + assert(*src == ':'); + src++; + NodeRef value = parseElement(src, ",}"); + Builder::appendToObject(ret, key.str, value); + src = skipSpace(src); + if (*src == ',') { + src++; + continue; + } else assert(*src == '}'); + } + assert(*src == '}'); + src++; + return ret; + } + + struct ExpressionElement { + bool isNode; + union { + NodeRef node; + IString op; + }; + ExpressionElement(NodeRef n) : isNode(true), node(n) {} + ExpressionElement(IString o) : isNode(false), op(o) {} + + NodeRef getNode() { + assert(isNode); + return node; + } + IString getOp() { + assert(!isNode); + return op; + } + }; + + // This is a list of the current stack of node-operator-node-operator-etc. + // this works by each parseExpression call appending to the vector; then recursing out, and the toplevel sorts it all + typedef std::vector ExpressionParts; + std::vector expressionPartsStack; + + void dumpParts(ExpressionParts& parts, int i) { + printf("expressionparts: %d (at %d)\n", parts.size(), i); + printf("| "); + for (int i = 0; i < parts.size(); i++) { + if (parts[i].isNode) { + parts[i].getNode()->stringify(std::cout); + printf(" "); + } else { + printf(" _%s_ ", parts[i].getOp().str); + } + } + printf("|\n"); + } + + NodeRef parseExpression(ExpressionElement initial, char*&src, const char* seps) { + //dump("parseExpression", src); + ExpressionParts& parts = expressionPartsStack.back(); + src = skipSpace(src); + if (*src == 0 || hasChar(seps, *src)) { + if (parts.size() > 0) { + parts.push_back(initial); // cherry on top of the cake + } + return initial.getNode(); + } + bool top = parts.size() == 0; + if (initial.isNode) { + Frag next(src); + if (next.type == OPERATOR) { + parts.push_back(initial); + src += next.size; + parts.push_back(next.str); + } else { + if (*src == '(') { + initial = parseCall(initial.getNode(), src); + } else if (*src == '[') { + initial = parseIndexing(initial.getNode(), src); + } else { + dump("bad parseExpression state", src); + assert(0); + } + return parseExpression(initial, src, seps); + } + } else { + parts.push_back(initial); + } + NodeRef last = parseElement(src, seps); + if (!top) return last; + { + ExpressionParts& parts = expressionPartsStack.back(); // |parts| may have been invalidated by that call + // we are the toplevel. sort it all out + // collapse right to left, highest priority first + //dumpParts(parts); + for (auto ops : operatorClasses) { + if (ops.rtl) { + // right to left + for (int i = parts.size()-1; i >= 0; 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) { + 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) { + 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); + } else if (ops.type == OperatorClass::Tertiary) { + // we must be at X ? Y : Z + // ^ + //dumpParts(parts, i); + if (op != COLON) continue; + assert(i < 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); + i = parts.size(); // basically a reset, due to things like x ? y ? 1 : 0 : 2 + } // TODO: postfix + } + } else { + // left to right + for (int i = 0; i < 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) { + 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) { + 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); + i = std::max(i-2, 0); // allow a previous prefix operator to cascade + } // TODO: tertiary, postfix + } + } + } + assert(parts.size() == 1); + NodeRef ret = parts[0].getNode(); + parts.clear(); + return ret; + } + } + + // Parses a block of code (e.g. a bunch of statements inside {,}, or the top level of o file) + NodeRef parseBlock(char*& src, NodeRef block=nullptr, const char* seps=";", IString keywordSep1=IString(), IString keywordSep2=IString()) { + //dump("parseBlock", src); + if (!block) block = Builder::makeBlock(); + while (*src) { + src = skipSpace(src); + if (*src == 0) break; + if (*src == ';') { + src++; // skip a statement in this block + continue; + } + if (hasChar(seps, *src)) break; + if (!!keywordSep1) { + Frag next(src); + if (next.type == KEYWORD && next.str == keywordSep1) break; + } + if (!!keywordSep2) { + Frag next(src); + if (next.type == KEYWORD && next.str == keywordSep2) break; + } + NodeRef element = parseElementOrStatement(src, seps); + Builder::appendToBlock(block, element); + } + return block; + } + + NodeRef parseBracketedBlock(char*& src, NodeRef block=nullptr) { + if (!block) block = Builder::makeBlock(); + src = skipSpace(src); + assert(*src == '{'); + src++; + parseBlock(src, block, ";}"); // the two are not symmetrical, ; is just internally separating, } is the final one - parseBlock knows all this + assert(*src == '}'); + src++; + return block; + } + + NodeRef parseElementOrStatement(char*& src, const char *seps) { + NodeRef ret = parseElement(src, seps); + src = skipSpace(src); + if (*src == ';') { + ret = Builder::makeStatement(ret); + src++; + } + return ret; + } + + NodeRef parseMaybeBracketed(char*& src, const char *seps) { + src = skipSpace(src); + return *src == '{' ? parseBracketedBlock(src) : parseElementOrStatement(src, seps); + } + + NodeRef parseMaybeBracketedBlock(char*& src, const char *seps, IString keywordSep1=IString(), IString keywordSep2=IString()) { + src = skipSpace(src); + return *src == '{' ? parseBracketedBlock(src) : parseBlock(src, nullptr, seps, keywordSep1, keywordSep2); + } + + NodeRef parseParenned(char*& src) { + src = skipSpace(src); + assert(*src == '('); + src++; + NodeRef ret = parseElement(src, ")"); + src = skipSpace(src); + assert(*src == ')'); + src++; + return ret; + } + + // Debugging + + char *allSource; + int allSize; + + static void dump(const char *where, char* curr) { + /* + printf("%s:\n=============\n", where); + for (int i = 0; i < allSize; i++) printf("%c", allSource[i] ? allSource[i] : '?'); + printf("\n"); + for (int i = 0; i < (curr - allSource); i++) printf(" "); + printf("^\n=============\n"); + */ + printf("%s:\n==========\n", where); + int newlinesLeft = 2; + int charsLeft = 200; + while (*curr) { + if (*curr == '\n') { + newlinesLeft--; + if (newlinesLeft == 0) break; + } + charsLeft--; + if (charsLeft == 0) break; + printf("%c", *curr++); + } + printf("\n\n"); + } + +public: + + Parser() : allSource(nullptr), allSize(0) { + expressionPartsStack.resize(1); + } + + // Highest-level parsing, as of a JavaScript script file. + NodeRef parseToplevel(char* src) { + allSource = src; + allSize = strlen(src); + return parseBlock(src, Builder::makeToplevel()); + } +}; + +} // namespace cashew + diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp new file mode 100644 index 0000000000000..8aba0b17594c2 --- /dev/null +++ b/tools/optimizer/simple_ast.cpp @@ -0,0 +1,202 @@ + +#include "simple_ast.h" + +// Ref methods + +Ref& Ref::operator[](unsigned x) { + return (*get())[x]; +} + +Ref& Ref::operator[](IString x) { + return (*get())[x]; +} + +bool Ref::operator==(const char *str) { + return get()->isString() && !strcmp(get()->str.str, str); +} + +bool Ref::operator!=(const char *str) { + return get()->isString() ? strcmp(get()->str.str, str) : true; +} + +bool Ref::operator==(const IString &str) { + return get()->isString() && get()->str == str; +} + +bool Ref::operator!=(const IString &str) { + return get()->isString() && get()->str != str; +} + +bool Ref::operator==(Ref other) { + return **this == *other; +} + +bool Ref::operator!() { + return !get() || get()->isNull(); +} + +// Arena + +Arena arena; + +Ref Arena::alloc() { + if (chunks.size() == 0 || index == CHUNK_SIZE) { + chunks.push_back(new Value[CHUNK_SIZE]); + index = 0; + } + return &chunks.back()[index++]; +} + +// dump + +void dump(const char *str, Ref node, bool pretty) { + std::cerr << str << ": "; + if (!!node) node->stringify(std::cerr, pretty); + else std::cerr << "(nullptr)"; + std::cerr << std::endl; +} + +// AST traversals + +// Traversals + +struct TraverseInfo { + Ref node; + int index; +}; + +template +struct StackedStack { // a stack, on the stack + T stackStorage[init]; + T* storage; + int used, available; // used amount, available amount + bool alloced; + + StackedStack() : used(0), available(init), alloced(false) { + storage = stackStorage; + } + ~StackedStack() { + if (alloced) free(storage); + } + + int size() { return used; } + + void push_back(const T& t) { + assert(used <= available); + if (used == available) { + available *= 2; + if (!alloced) { + T* old = storage; + storage = (T*)malloc(sizeof(T)*available); + memcpy(storage, old, sizeof(T)*used); + alloced = true; + } else { + storage = (T*)realloc(storage, sizeof(T)*available); + } + } + assert(used < available); + assert(storage); + storage[used++] = t; + } + + T& back() { + assert(used > 0); + return storage[used-1]; + } + + void pop_back() { + assert(used > 0); + used--; + } +}; + +#define visitable(node) (node->isArray() and node->size() > 0) + +#define TRAV_STACK 40 + +// Traverse, calling visit before the children +void traversePre(Ref node, std::function visit) { + if (!visitable(node)) return; + visit(node); + StackedStack stack; + stack.push_back({ node, 0 }); + while (stack.size() > 0) { + TraverseInfo& top = stack.back(); + if (top.index < top.node->size()) { + Ref sub = top.node[top.index]; + top.index++; + if (visitable(sub)) { + visit(sub); + stack.push_back({ sub, 0 }); + } + } else { + stack.pop_back(); + } + } +} + +// Traverse, calling visitPre before the children and visitPost after +void traversePrePost(Ref node, std::function visitPre, std::function visitPost) { + if (!visitable(node)) return; + visitPre(node); + StackedStack stack; + stack.push_back({ node, 0 }); + while (stack.size() > 0) { + TraverseInfo& top = stack.back(); + if (top.index < top.node->size()) { + Ref sub = top.node[top.index]; + top.index++; + if (visitable(sub)) { + visitPre(sub); + stack.push_back({ sub, 0 }); + } + } else { + visitPost(top.node); + stack.pop_back(); + } + } + visitPost(node); +} + +// Traverse, calling visitPre before the children and visitPost after. If pre returns false, do not traverse children +void traversePrePostConditional(Ref node, std::function visitPre, std::function visitPost) { + if (!visitable(node)) return; + if (!visitPre(node)) return; + StackedStack stack; + stack.push_back({ node, 0 }); + while (stack.size() > 0) { + TraverseInfo& top = stack.back(); + if (top.index < top.node->size()) { + Ref sub = top.node[top.index]; + top.index++; + if (visitable(sub)) { + if (visitPre(sub)) { + stack.push_back({ sub, 0 }); + } + } + } else { + visitPost(top.node); + stack.pop_back(); + } + } + visitPost(node); +} + +// Traverses all the top-level functions in the document +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++) { + Ref curr = stats[i]; + if (curr[0] == DEFUN) visit(curr); + } + } else if (ast[0] == DEFUN) { + visit(ast); + } +} + +// ValueBuilder + +IStringSet ValueBuilder::statable("assign call binary unary-prefix if label name num conditional dot new sub seq string object array"); + diff --git a/tools/optimizer/simple_ast.h b/tools/optimizer/simple_ast.h new file mode 100644 index 0000000000000..25cd1cc682b8a --- /dev/null +++ b/tools/optimizer/simple_ast.h @@ -0,0 +1,1425 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parser.h" + +#define err(str) fprintf(stderr, str "\n"); +#define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__); +#define printErr err + +using namespace cashew; + +class Ref; +struct Value; + +void dump(const char *str, Ref node, bool pretty=false); + +// Reference to a value, plus some operators for convenience +struct Ref { + Value* inst; + + Ref(Value *v=nullptr) : inst(v) {} + + Value* get() { return inst; } + + Value& operator*() { return *inst; } + Value* operator->() { return inst; } + Ref& operator[](unsigned x); + Ref& operator[](IString x); + + // special conveniences + bool operator==(const char *str); // comparison to string, which is by value + bool operator!=(const char *str); + bool operator==(const IString &str); + bool operator!=(const IString &str); + bool operator==(double d) { assert(0); return false; } // prevent Ref == number, which is potentially ambiguous; use ->getNumber() == number + bool operator==(Ref other); + bool operator!(); // check if null, in effect +}; + +// Arena allocation, free it all on process exit + +struct Arena { + #define CHUNK_SIZE 1000 + std::vector chunks; + int index; // in last chunk + + Arena() : index(0) {} + + Ref alloc(); +}; + +extern Arena arena; + +// Main value type +struct Value { + enum Type { + String = 0, + Number = 1, + Array = 2, + Null = 3, + Bool = 4, + Object = 5 + }; + + Type type; + + typedef std::vector ArrayStorage; + typedef std::unordered_map ObjectStorage; + + union { // TODO: optimize + IString str; + double num; + ArrayStorage *arr; + bool boo; + ObjectStorage *obj; + }; + + // constructors all copy their input + Value() : type(Null), num(0) {} + explicit Value(const char *s) : type(Null) { + setString(s); + } + explicit Value(double n) : type(Null) { + setNumber(n); + } + explicit Value(ArrayStorage &a) : type(Null) { + setArray(); + *arr = a; + } + // no bool constructor - would endanger the double one (int might convert the wrong way) + + ~Value() { + free(); + } + + void free() { + if (type == Array) delete arr; + else if (type == Object) delete obj; + type = Null; + num = 0; + } + + Value& setString(const char *s) { + free(); + type = String; + str.set(s); + return *this; + } + Value& setString(const IString &s) { + free(); + type = String; + str.set(s); + return *this; + } + Value& setNumber(double n) { + free(); + type = Number; + num = n; + return *this; + } + Value& setArray(ArrayStorage &a) { + free(); + type = Array; + arr = new ArrayStorage(); + *arr = a; + return *this; + } + Value& setArray() { + free(); + type = Array; + arr = new ArrayStorage(); + return *this; + } + Value& setNull() { + free(); + type = Null; + return *this; + } + Value& setBool(bool b) { // Bool in the name, as otherwise might overload over int + free(); + type = Bool; + boo = b; + return *this; + } + Value& setObject() { + free(); + type = Object; + obj = new ObjectStorage(); + return *this; + } + + bool isString() { return type == String; } + bool isNumber() { return type == Number; } + bool isArray() { return type == Array; } + bool isNull() { return type == Null; } + bool isBool() { return type == Bool; } + bool isObject() { return type == Object; } + + bool isBool(bool b) { return type == Bool && b == boo; } // avoid overloading == as it might overload over int + + const char* getCString() { + assert(isString()); + return str.str; + } + IString& getIString() { + assert(isString()); + return str; + } + double& getNumber() { + assert(isNumber()); + return num; + } + ArrayStorage& getArray() { + assert(isArray()); + return *arr; + } + bool& getBool() { + assert(isBool()); + return boo; + } + + Value& operator=(const Value& other) { + free(); + switch (other.type) { + case String: + setString(other.str); + break; + case Number: + setNumber(other.num); + break; + case Array: + setArray(*other.arr); + break; + case Null: + setNull(); + break; + case Bool: + setBool(other.boo); + break; + case Object: + assert(0); // TODO + } + return *this; + } + + bool operator==(const Value& other) { + if (type != other.type) return false; + switch (other.type) { + case String: + return str == other.str; + case Number: + return num == other.num; + case Array: + return this == &other; // if you want a deep compare, use deepCompare + case Null: + break; + case Bool: + return boo == other.boo; + case Object: + return this == &other; // if you want a deep compare, use deepCompare + } + return true; + } + + bool deepCompare(Ref ref) { + Value& other = *ref; + if (*this == other) return true; // either same pointer, or identical value type (string, number, null or bool) + if (type != other.type) return false; + if (type == Array) { + if (arr->size() != other.arr->size()) return false; + for (unsigned i = 0; i < arr->size(); i++) { + if (!(*arr)[i]->deepCompare((*other.arr)[i])) return false; + } + return true; + } else if (type == Object) { + if (obj->size() != other.obj->size()) return false; + for (auto i : *obj) { + if (other.obj->count(i.first) == 0) return false; + if (i.second->deepCompare((*other.obj)[i.first])) return false; + } + return true; + } + return false; + } + + char* parse(char* curr) { + #define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13) /* space, tab, linefeed/newline, or return */ + #define skip() { while (*curr && is_json_space(*curr)) curr++; } + skip(); + if (*curr == '"') { + // String + curr++; + char *close = strchr(curr, '"'); + assert(close); + *close = 0; // end this string, and reuse it straight from the input + setString(curr); + curr = close+1; + } else if (*curr == '[') { + // Array + curr++; + skip(); + setArray(); + while (*curr != ']') { + Ref temp = arena.alloc(); + arr->push_back(temp); + curr = temp->parse(curr); + skip(); + if (*curr == ']') break; + assert(*curr == ','); + curr++; + skip(); + } + curr++; + } else if (*curr == 'n') { + // Null + assert(strncmp(curr, "null", 4) == 0); + setNull(); + curr += 4; + } else if (*curr == 't') { + // Bool true + assert(strncmp(curr, "true", 4) == 0); + setBool(true); + curr += 4; + } else if (*curr == 'f') { + // Bool false + assert(strncmp(curr, "false", 5) == 0); + setBool(false); + curr += 5; + } else if (*curr == '{') { + // Object + curr++; + skip(); + setObject(); + while (*curr != '}') { + assert(*curr == '"'); + curr++; + char *close = strchr(curr, '"'); + assert(close); + *close = 0; // end this string, and reuse it straight from the input + IString key(curr); + curr = close+1; + skip(); + assert(*curr == ':'); + curr++; + skip(); + Ref value = arena.alloc(); + curr = value->parse(curr); + (*obj)[key] = value; + skip(); + if (*curr == '}') break; + assert(*curr == ','); + curr++; + skip(); + } + curr++; + } else { + // Number + char *after; + setNumber(strtod(curr, &after)); + curr = after; + } + return curr; + } + + void stringify(std::ostream &os, bool pretty=false) { + static int indent = 0; + #define indentify() { for (int i = 0; i < indent; i++) os << " "; } + switch (type) { + case String: + os << '"' << str.str << '"'; + break; + case Number: + os << std::setprecision(17) << num; // doubles can have 17 digits of precision + break; + case Array: + if (arr->size() == 0) { + os << "[]"; + break; + } + os << '['; + if (pretty) { + os << std::endl; + indent++; + } + for (unsigned i = 0; i < arr->size(); i++) { + if (i > 0) { + if (pretty) os << "," << std::endl; + else os << ", "; + } + indentify(); + (*arr)[i]->stringify(os, pretty); + } + if (pretty) { + os << std::endl; + indent--; + } + indentify(); + os << ']'; + break; + case Null: + os << "null"; + break; + case Bool: + os << (boo ? "true" : "false"); + break; + case Object: + os << '{'; + if (pretty) { + os << std::endl; + indent++; + } + bool first = true; + for (auto i : *obj) { + if (first) { + first = false; + } else { + os << ", "; + if (pretty) os << std::endl; + } + indentify(); + os << '"' << i.first.c_str() << "\": "; + i.second->stringify(os, pretty); + } + if (pretty) { + os << std::endl; + indent--; + } + indentify(); + os << '}'; + break; + } + } + + // String operations + + // Number operations + + // Array operations + + unsigned size() { + assert(isArray()); + return arr->size(); + } + + void setSize(unsigned size) { + assert(isArray()); + unsigned old = arr->size(); + if (old != size) arr->resize(size); + if (old < size) { + for (unsigned i = old; i < size; i++) { + (*arr)[i] = arena.alloc(); + } + } + } + + Ref& operator[](unsigned x) { + assert(isArray()); + assert(x < arr->size()); + return (*arr)[x]; + } + + Value& push_back(Ref r) { + assert(isArray()); + arr->push_back(r); + return *this; + } + Ref pop_back() { + assert(isArray()); + Ref ret = arr->back(); + arr->pop_back(); + return ret; + } + + Ref back() { + assert(isArray()); + if (arr->size() == 0) return nullptr; + return arr->back(); + } + + void splice(int x, int num) { + assert(isArray()); + arr->erase(arr->begin() + x, arr->begin() + x + num); + } + + void insert(int x, int num) { + arr->insert(arr->begin() + x, num, Ref()); + } + void insert(int x, Ref node) { + arr->insert(arr->begin() + x, 1, node); + } + + int indexOf(Ref other) { + assert(isArray()); + for (unsigned i = 0; i < arr->size(); i++) { + if (other == (*arr)[i]) return i; + } + return -1; + } + + Ref map(std::function func) { + assert(isArray()); + Ref ret = arena.alloc(); + ret->setArray(); + for (unsigned i = 0; i < arr->size(); i++) { + ret->push_back(func((*arr)[i])); + } + return ret; + } + + Ref filter(std::function func) { + assert(isArray()); + Ref ret = arena.alloc(); + ret->setArray(); + for (unsigned i = 0; i < arr->size(); i++) { + Ref curr = (*arr)[i]; + if (func(curr)) ret->push_back(curr); + } + return ret; + } + + /* + void forEach(std::function func) { + for (unsigned i = 0; i < arr->size(); i++) { + func((*arr)[i]); + } + } + */ + + // Null operations + + // Bool operations + + // Object operations + + Ref& operator[](IString x) { + assert(isObject()); + return (*obj)[x]; + } + + bool has(IString x) { + assert(isObject()); + return obj->count(x) > 0; + } +}; + +// AST traversals + +// Traverse, calling visit before the children +void traversePre(Ref node, std::function visit); + +// Traverse, calling visitPre before the children and visitPost after +void traversePrePost(Ref node, std::function visitPre, std::function visitPost); + +// Traverse, calling visitPre before the children and visitPost after. If pre returns false, do not traverse children +void traversePrePostConditional(Ref node, std::function visitPre, std::function visitPost); + +// Traverses all the top-level functions in the document +void traverseFunctions(Ref ast, std::function visit); + +// JS printer + +struct JSPrinter { + bool pretty, finalize; + + char *buffer; + int size, used; + + int indent; + bool possibleSpace; // add a space to separate identifiers + + Ref ast; + + JSPrinter(bool pretty_, bool finalize_, Ref ast_) : pretty(pretty_), finalize(finalize_), buffer(0), size(0), used(0), indent(0), possibleSpace(false), ast(ast_) {} + + void printAst() { + print(ast); + buffer[used] = 0; + } + + // Utils + + void ensure(int safety=100) { + if (size < used + safety) { + size = std::max(1024, size*2) + safety; + if (!buffer) { + buffer = (char*)malloc(size); + } else { + buffer = (char*)realloc(buffer, size); + } + } + } + + void emit(char c) { + maybeSpace(c); + if (!pretty && c == '}' && buffer[used-1] == ';') used--; // optimize ;} into }, the ; is not separating anything + ensure(1); + buffer[used++] = c; + } + + void emit(const char *s) { + maybeSpace(*s); + int len = strlen(s); + ensure(len); + strcpy(buffer + used, s); + used += len; + } + + void newline() { + if (!pretty) return; + emit('\n'); + for (int i = 0; i < indent; i++) emit(' '); + } + + void space() { + if (pretty) emit(' '); + } + + void safeSpace() { + if (pretty) emit(' '); + else possibleSpace = true; + } + + void maybeSpace(char s) { + if (possibleSpace) { + possibleSpace = false; + if (isIdentPart(s)) emit(' '); + } + } + + void print(Ref node) { + ensure(); + IString type = node[0]->getIString(); + //fprintf(stderr, "printing %s\n", type.str); + switch (type.str[0]) { + case 'a': { + if (type == ASSIGN) printAssign(node); + else if (type == ARRAY) printArray(node); + else assert(0); + break; + } + case 'b': { + if (type == BINARY) printBinary(node); + else if (type == BLOCK) printBlock(node); + else if (type == BREAK) printBreak(node); + else assert(0); + break; + } + case 'c': { + if (type == CALL) printCall(node); + else if (type == CONDITIONAL) printConditional(node); + else if (type == CONTINUE) printContinue(node); + else assert(0); + break; + } + case 'd': { + if (type == DEFUN) printDefun(node); + else if (type == DO) printDo(node); + else if (type == DOT) printDot(node); + else assert(0); + break; + } + case 'i': { + if (type == IF) printIf(node); + else assert(0); + break; + } + case 'l': { + if (type == LABEL) printLabel(node); + else assert(0); + break; + } + case 'n': { + if (type == NAME) printName(node); + else if (type == NUM) printNum(node); + else if (type == NEW) printNew(node); + else assert(0); + break; + } + case 'o': { + if (type == OBJECT) printObject(node); + break; + } + case 'r': { + if (type == RETURN) printReturn(node); + else assert(0); + break; + } + case 's': { + if (type == STAT) printStat(node); + else if (type == SUB) printSub(node); + else if (type == SEQ) printSeq(node); + else if (type == SWITCH) printSwitch(node); + else if (type == STRING) printString(node); + else assert(0); + break; + } + case 't': { + if (type == TOPLEVEL) printToplevel(node); + else assert(0); + break; + } + case 'u': { + if (type == UNARY_PREFIX) printUnaryPrefix(node); + else assert(0); + break; + } + case 'v': { + if (type == VAR) printVar(node); + else assert(0); + break; + } + case 'w': { + if (type == WHILE) printWhile(node); + else assert(0); + break; + } + default: { + printf("cannot yet print %s\n", type.str); + assert(0); + } + } + } + + void printStats(Ref stats) { + bool first = true; + for (int i = 0; i < stats->size(); i++) { + Ref curr = stats[i]; + if (!isNothing(curr)) { + if (first) first = false; + else newline(); + print(stats[i]); + } + } + } + + void printToplevel(Ref node) { + printStats(node[1]); + } + + void printBlock(Ref node) { + if (node->size() == 1 || node[1]->size() == 0) { + emit("{}"); + return; + } + emit('{'); + indent++; + newline(); + printStats(node[1]); + indent--; + newline(); + emit('}'); + } + + void printDefun(Ref node) { + emit("function "); + emit(node[1]->getCString()); + emit('('); + Ref args = node[2]; + for (int i = 0; i < args->size(); i++) { + if (i > 0) (pretty ? emit(", ") : emit(',')); + emit(args[i]->getCString()); + } + emit(')'); + space(); + emit('{'); + indent++; + newline(); + printStats(node[3]); + indent--; + newline(); + emit('}'); + newline(); + } + + bool isNothing(Ref node) { + return (node[0] == TOPLEVEL && node[1]->size() == 0) || (node[0] == STAT && isNothing(node[1])); + } + + void printStat(Ref node) { + if (!isNothing(node[1])) { + print(node[1]); + if (buffer[used-1] != ';') emit(';'); + } + } + + void printAssign(Ref node) { + printChild(node[2], node, -1); + space(); + emit('='); + space(); + printChild(node[3], node, 1); + } + + void printName(Ref node) { + emit(node[1]->getCString()); + } + + void printNum(Ref node) { + double d = node[1]->getNumber(); + bool neg = d < 0; + if (neg) d = -d; + // try to emit the fewest necessary characters + bool integer = fmod(d, 1) == 0; + #define BUFFERSIZE 1000 + static char storage_f[BUFFERSIZE], storage_e[BUFFERSIZE]; // f is normal, e is scientific for float, x for integer + double err_f, err_e; + for (int e = 0; e <= 1; e++) { + char *buffer = e ? storage_e : storage_f; + double temp; + if (!integer) { + static char format[6]; + for (int i = 0; i <= 18; i++) { + format[0] = '%'; + format[1] = '.'; + if (i < 10) { + format[2] = '0' + i; + format[3] = e ? 'e' : 'f'; + format[4] = 0; + } else { + format[2] = '1'; + format[3] = '0' + (i - 10); + format[4] = e ? 'e' : 'f'; + format[5] = 0; + } + snprintf(buffer, BUFFERSIZE-1, format, d); + sscanf(buffer, "%lf", &temp); + //errv("%.18f, %.18e => %s => %.18f, %.18e (%d), ", d, d, buffer, temp, temp, temp == d); + if (temp == d) break; + } + } else { + // integer + 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); + } 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 + sscanf(buffer, "%lf", &temp); + } + //errv("%.18f, %.18e => %s => %.18f, %.18e, %llu (%d)\n", d, d, buffer, temp, temp, uu, temp == d); + } + (e ? err_e : err_f) = fabs(temp - d); + //errv("current attempt: %.18f => %s", d, buffer); + //assert(temp == d); + char *dot = strchr(buffer, '.'); + if (dot) { + // remove trailing zeros + char *end = dot+1; + while (*end >= '0' && *end <= '9') end++; + end--; + while (*end == '0') { + char *copy = end; + do { + copy[0] = copy[1]; + } while (*copy++ != 0); + end--; + } + //errv("%.18f => %s", d, buffer); + // remove preceding zeros + while (*buffer == '0') { + char *copy = buffer; + do { + copy[0] = copy[1]; + } while (*copy++ != 0); + } + //errv("%.18f ===> %s", d, buffer); + } else if (!integer || !e) { + // no dot. try to change 12345000 => 12345e3 + char *end = strchr(buffer, 0); + end--; + char *test = end; + while (*test == '0' && test > buffer) test--; + int num = end - test; + if (num >= 3) { + test++; + test[0] = 'e'; + if (num < 10) { + test[1] = '0' + num; + test[2] = 0; + } else { + assert(num < 100); + test[1] = '0' + (num / 10); + test[2] = '0' + (num % 10); + test[3] = 0; + } + } + } + //errv("..current attempt: %.18f => %s", d, buffer); + } + //fprintf(stderr, "options:\n%s\n%s\n (first? %d)\n", storage_e, storage_f, strlen(storage_e) < strlen(storage_f)); + if (neg) emit('-'); + if (err_e == err_f) { + emit(strlen(storage_e) < strlen(storage_f) ? storage_e : storage_f); + } else { + emit(err_e < err_f ? storage_e : storage_f); + } + } + + void printString(Ref node) { + emit('"'); + emit(node[1]->getCString()); + emit('"'); + } + + // Parens optimizing + + bool capturesOperators(Ref node) { + Ref type = node[0]; + return type == CALL || type == ARRAY || type == OBJECT || type == SEQ; + } + + int getPrecedence(Ref node, bool parent) { + Ref type = node[0]; + if (type == BINARY || type == UNARY_PREFIX) { + return OperatorClass::getPrecedence(type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix, node[1]->getIString()); + } else if (type == SEQ) { + return OperatorClass::getPrecedence(OperatorClass::Binary, COMMA); + } else if (type == CALL) { + return parent ? OperatorClass::getPrecedence(OperatorClass::Binary, COMMA) : -1; // call arguments are split by commas, but call itself is safe + } else if (type == ASSIGN) { + return OperatorClass::getPrecedence(OperatorClass::Binary, SET); + } else if (type == CONDITIONAL) { + return OperatorClass::getPrecedence(OperatorClass::Tertiary, QUESTION); + } + // otherwise, this is something that fixes precedence explicitly, and we can ignore + return -1; // XXX + } + + // check whether we need parens for the child, when rendered in the parent + // @param childPosition -1 means it is printed to the left of parent, 0 means "anywhere", 1 means right + bool needParens(Ref parent, Ref child, int childPosition) { + int parentPrecedence = getPrecedence(parent, true); + int childPrecedence = getPrecedence(child, false); + + if (childPrecedence > parentPrecedence) return true; // child is definitely a danger + if (childPrecedence < parentPrecedence) return false; // definitely cool + // equal precedence, so associativity (rtl/ltr) is what matters + // (except for some exceptions, where multiple operators can combine into confusion) + if (parent[0] == UNARY_PREFIX) { + assert(child[0] == UNARY_PREFIX); + if ((parent[1] == PLUS || parent[1] == MINUS) && child[1] == parent[1]) { + // cannot emit ++x when we mean +(+x) + return true; + } + } + if (childPosition == 0) return true; // child could be anywhere, so always paren + if (childPrecedence < 0) return false; // both precedences are safe + // check if child is on the dangerous side + if (OperatorClass::getRtl(parentPrecedence)) return childPosition < 0; + else return childPosition > 0; + } + + void printChild(Ref child, Ref parent, int childPosition=0) { + bool parens = needParens(parent, child, childPosition); + if (parens) emit('('); + print(child); + if (parens) emit(')'); + } + + void printBinary(Ref node) { + printChild(node[2], node, -1); + space(); + emit(node[1]->getCString()); + space(); + printChild(node[3], node, 1); + } + + void printUnaryPrefix(Ref node) { + if (finalize && node[1] == PLUS && (node[2][0] == NUM || + (node[2][0] == UNARY_PREFIX && node[2][1] == MINUS && node[2][2][0] == NUM))) { + // emit a finalized number + char *curr = buffer + used; + print(node[2]); + buffer[used] = 0; + if (strchr(curr, '.')) return; // already a decimal point, all good + char *e = strchr(curr, 'e'); + if (!e) { + emit(".0"); + return; + } + ensure(3); + char *end = strchr(curr, 0); + while (end >= e) { + end[2] = end[0]; + end--; + } + e[0] = '.'; + e[1] = '0'; + used += 2; + return; + } + if ((buffer[used-1] == '-' && node[1] == MINUS) || + (buffer[used-1] == '+' && node[1] == PLUS)) { + emit(' '); // cannot join - and - to --, looks like the -- operator + } + emit(node[1]->getCString()); + printChild(node[2], node, 1); + } + + void printConditional(Ref node) { + printChild(node[1], node, -1); + space(); + emit('?'); + space(); + printChild(node[2], node, 0); + space(); + emit(':'); + space(); + printChild(node[3], node, 1); + } + + void printCall(Ref node) { + printChild(node[1], node, 0); + emit('('); + Ref args = node[2]; + for (int i = 0; i < args->size(); i++) { + if (i > 0) (pretty ? emit(", ") : emit(',')); + printChild(args[i], node, 0); + } + emit(')'); + } + + void printSeq(Ref node) { + printChild(node[1], node, -1); + emit(','); + space(); + printChild(node[2], node, 1); + } + + void printDot(Ref node) { + print(node[1]); + emit('.'); + emit(node[2]->getCString()); + } + + void printSwitch(Ref node) { + emit("switch"); + space(); + emit('('); + print(node[1]); + emit(')'); + space(); + emit('{'); + newline(); + Ref cases = node[2]; + for (int i = 0; i < cases->size(); i++) { + Ref c = cases[i]; + if (!c[0]) { + emit("default:"); + } else { + emit("case "); + print(c[0]); + emit(':'); + } + if (c[1]->size() > 0) { + indent++; + newline(); + int curr = used; + printStats(c[1]); + indent--; + if (curr != used) newline(); + else used--; // avoid the extra indentation we added tentatively + } else { + newline(); + } + } + emit('}'); + } + + void printSub(Ref node) { + printChild(node[1], node, -1); + emit('['); + print(node[2]); + emit(']'); + } + + void printVar(Ref node) { + emit("var "); + Ref args = node[1]; + for (int i = 0; i < args->size(); i++) { + if (i > 0) (pretty ? emit(", ") : emit(',')); + emit(args[i][0]->getCString()); + if (args[i]->size() > 1) { + space(); + emit('='); + space(); + print(args[i][1]); + } + } + emit(';'); + } + + void printIf(Ref node) { + emit("if"); + safeSpace(); + emit('('); + print(node[1]); + emit(')'); + space(); + // special case: we need braces to save us from ambiguity, if () { if () } else. otherwise else binds to inner if + bool hasElse = node->size() >= 4 && !!node[3]; + bool needBraces = node[2][0] == IF && (node[2]->size() == 3 || !node[2][3]) && hasElse; + if (needBraces) { + emit('{'); + indent++; + newline(); + } + print(node[2]); + if (needBraces) { + indent--; + newline(); + emit('}'); + } + if (hasElse) { + space(); + emit("else"); + safeSpace(); + print(node[3]); + } + } + + void printDo(Ref node) { + emit("do"); + safeSpace(); + print(node[2]); + space(); + emit("while"); + space(); + emit('('); + print(node[1]); + emit(')'); + emit(';'); + } + + void printWhile(Ref node) { + emit("while"); + space(); + emit('('); + print(node[1]); + emit(')'); + space(); + print(node[2]); + } + + void printLabel(Ref node) { + emit(node[1]->getCString()); + space(); + emit(':'); + space(); + print(node[2]); + } + + void printReturn(Ref node) { + emit("return"); + if (!!node[1]) { + emit(' '); + print(node[1]); + } + emit(';'); + } + + void printBreak(Ref node) { + emit("break"); + if (!!node[1]) { + emit(' '); + emit(node[1]->getCString()); + } + emit(';'); + } + + void printContinue(Ref node) { + emit("continue"); + if (!!node[1]) { + emit(' '); + emit(node[1]->getCString()); + } + emit(';'); + } + + void printNew(Ref node) { + emit("new "); + print(node[1]); + } + + void printArray(Ref node) { + emit('['); + Ref args = node[1]; + for (int i = 0; i < args->size(); i++) { + if (i > 0) (pretty ? emit(", ") : emit(',')); + print(args[i]); + } + emit(']'); + } + + void printObject(Ref node) { + emit('{'); + indent++; + newline(); + Ref args = node[1]; + for (int i = 0; i < args->size(); i++) { + if (i > 0) { + pretty ? emit(", ") : emit(','); + newline(); + } + emit('"'); + emit(args[i][0]->getCString()); + emit("\":"); + space(); + print(args[i][1]); + } + indent--; + newline(); + emit('}'); + } +}; + +// cashew builder + +class ValueBuilder { + static IStringSet statable; + + static Ref makeRawString(const IString& s) { + return &arena.alloc()->setString(s); + } + + static Ref makeRawArray() { + return &arena.alloc()->setArray(); + } + + static Ref makeNull() { + return &arena.alloc()->setNull(); + } + +public: + static Ref makeToplevel() { + return &makeRawArray()->push_back(makeRawString(TOPLEVEL)) + .push_back(makeRawArray()); + } + + static Ref makeString(IString str) { + return &makeRawArray()->push_back(makeRawString(STRING)) + .push_back(makeRawString(str)); + } + + static Ref makeBlock() { + return &makeRawArray()->push_back(makeRawString(BLOCK)) + .push_back(makeRawArray()); + } + + static Ref makeName(IString name) { + return &makeRawArray()->push_back(makeRawString(NAME)) + .push_back(makeRawString(name)); + } + + static void appendToBlock(Ref block, Ref element) { + if (block[0] == BLOCK || block[0] == TOPLEVEL) { + block[1]->push_back(element); + } else if (block[0] == DEFUN) { + block[3]->push_back(element); + } else assert(0); + } + + static Ref makeCall(Ref target) { + return &makeRawArray()->push_back(makeRawString(CALL)) + .push_back(target) + .push_back(makeRawArray()); + } + + static void appendToCall(Ref call, Ref element) { + assert(call[0] == CALL); + call[2]->push_back(element); + } + + static Ref makeStatement(Ref contents) { + if (statable.has(contents[0]->getIString())) { + return &makeRawArray()->push_back(makeRawString(STAT)) + .push_back(contents); + } else { + return contents; // only very specific things actually need to be stat'ed + } + } + + static Ref makeNumber(double num) { + return &makeRawArray()->push_back(makeRawString(NUM)) + .push_back(&arena.alloc()->setNumber(num)); + } + + static Ref makeBinary(Ref left, IString op, Ref right) { + if (op == SET) { + return &makeRawArray()->push_back(makeRawString(ASSIGN)) + .push_back(&arena.alloc()->setBool(true)) + .push_back(left) + .push_back(right); + } else if (op == COMMA) { + return &makeRawArray()->push_back(makeRawString(SEQ)) + .push_back(left) + .push_back(right); + } else if (op == PERIOD) { + assert(right[0] == NAME); + return &makeRawArray()->push_back(makeRawString(DOT)) + .push_back(left) + .push_back(makeRawString(right[1]->getIString())); + } else { + return &makeRawArray()->push_back(makeRawString(BINARY)) + .push_back(makeRawString(op)) + .push_back(left) + .push_back(right); + } + } + + static Ref makePrefix(IString op, Ref right) { + return &makeRawArray()->push_back(makeRawString(UNARY_PREFIX)) + .push_back(makeRawString(op)) + .push_back(right); + } + + static Ref makeFunction(IString name) { + return &makeRawArray()->push_back(makeRawString(DEFUN)) + .push_back(makeRawString(name)) + .push_back(makeRawArray()) + .push_back(makeRawArray()); + } + + static void appendArgumentToFunction(Ref func, IString arg) { + assert(func[0] == DEFUN); + func[2]->push_back(makeRawString(arg)); + } + + static Ref makeVar() { + return &makeRawArray()->push_back(makeRawString(VAR)) + .push_back(makeRawArray()); + } + + static void appendToVar(Ref var, IString name, Ref value) { + assert(var[0] == VAR); + Ref array = &makeRawArray()->push_back(makeRawString(name)); + if (!!value) array->push_back(value); + var[1]->push_back(array); + } + + static Ref makeReturn(Ref value) { + return &makeRawArray()->push_back(makeRawString(RETURN)).push_back(!!value ? value : makeNull()); + } + + static Ref makeIndexing(Ref target, Ref index) { + return &makeRawArray()->push_back(makeRawString(SUB)) + .push_back(target) + .push_back(index); + } + + static Ref makeIf(Ref condition, Ref ifTrue, Ref ifFalse) { + return &makeRawArray()->push_back(makeRawString(IF)) + .push_back(condition) + .push_back(ifTrue) + .push_back(!!ifFalse ? ifFalse : makeNull()); + } + + static Ref makeConditional(Ref condition, Ref ifTrue, Ref ifFalse) { + return &makeRawArray()->push_back(makeRawString(CONDITIONAL)) + .push_back(condition) + .push_back(ifTrue) + .push_back(ifFalse); + } + + static Ref makeDo(Ref body, Ref condition) { + return &makeRawArray()->push_back(makeRawString(DO)) + .push_back(condition) + .push_back(body); + } + + static Ref makeWhile(Ref condition, Ref body) { + return &makeRawArray()->push_back(makeRawString(WHILE)) + .push_back(condition) + .push_back(body); + } + + static Ref makeBreak(IString label) { + return &makeRawArray()->push_back(makeRawString(BREAK)).push_back(!!label ? makeRawString(label) : makeNull()); + } + + static Ref makeContinue(IString label) { + return &makeRawArray()->push_back(makeRawString(CONTINUE)).push_back(!!label ? makeRawString(label) : makeNull()); + } + + static Ref makeLabel(IString name, Ref body) { + return &makeRawArray()->push_back(makeRawString(LABEL)) + .push_back(makeRawString(name)) + .push_back(body); + } + + static Ref makeSwitch(Ref input) { + return &makeRawArray()->push_back(makeRawString(SWITCH)) + .push_back(input) + .push_back(makeRawArray()); + } + + static void appendCaseToSwitch(Ref switch_, Ref arg) { + assert(switch_[0] == SWITCH); + switch_[2]->push_back(&makeRawArray()->push_back(arg).push_back(makeRawArray())); + } + + static void appendDefaultToSwitch(Ref switch_) { + assert(switch_[0] == SWITCH); + switch_[2]->push_back(&makeRawArray()->push_back(makeNull()).push_back(makeRawArray())); + } + + static void appendCodeToSwitch(Ref switch_, Ref code, bool explicitBlock) { + assert(switch_[0] == SWITCH); + assert(code[0] == BLOCK); + if (!explicitBlock) { + for (int i = 0; i < code[1]->size(); i++) { + switch_[2]->back()->back()->push_back(code[1][i]); + } + } else { + switch_[2]->back()->back()->push_back(code); + } + } + + static Ref makeDot(Ref obj, IString key) { + return &makeRawArray()->push_back(makeRawString(DOT)) + .push_back(obj) + .push_back(makeRawString(key)); + } + + static Ref makeNew(Ref call) { + return &makeRawArray()->push_back(makeRawString(NEW)) + .push_back(call); + } + + static Ref makeArray() { + return &makeRawArray()->push_back(makeRawString(ARRAY)) + .push_back(makeRawArray()); + } + + static void appendToArray(Ref array, Ref element) { + assert(array[0] == ARRAY); + array[1]->push_back(element); + } + + static Ref makeObject() { + return &makeRawArray()->push_back(makeRawString(OBJECT)) + .push_back(makeRawArray()); + } + + static void appendToObject(Ref array, IString key, Ref value) { + assert(array[0] == OBJECT); + array[1]->push_back(&makeRawArray()->push_back(makeRawString(key)) + .push_back(value)); + } +}; + diff --git a/tools/shared.py b/tools/shared.py index 583a89a89d717..d6c590d2fab84 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -301,8 +301,9 @@ def listify(x): def get_clang_version(): global actual_clang_version if actual_clang_version is None: - ver = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0].split(' ') - actual_clang_version = ver[ver.index('version')+1] + response = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1] + m = re.search(r'[Vv]ersion\s+(\d+\.\d+)', response) + actual_clang_version = m and m.group(1) return actual_clang_version def check_clang_version(): @@ -424,6 +425,8 @@ def generate_sanity(): def check_sanity(force=False): try: + if os.environ.get('EMCC_SKIP_SANITY_CHECK') == '1': + return reason = None if not CONFIG_FILE: return # config stored directly in EM_CONFIG => skip sanity checks @@ -1384,6 +1387,7 @@ def ll_opts(filename): def llvm_opt(filename, opts, out=None): if type(opts) is int: opts = Building.pick_llvm_opts(opts) + opts = opts[:] #opts += ['-debug-pass=Arguments'] if get_clang_version() >= '3.4': if not Settings.SIMD: diff --git a/tools/test-js-optimizer-asm-last-output2.js b/tools/test-js-optimizer-asm-last-output2.js new file mode 100644 index 0000000000000..ee736a4e71a11 --- /dev/null +++ b/tools/test-js-optimizer-asm-last-output2.js @@ -0,0 +1,103 @@ +function finall(x) { + x = +x; + var a = 5.0; + a = +x; + a = 17; + a = 44.0; + a = 44.0; + a = 44.9; + a = 1278.0e3; + a = 12.0e10; + a = -x; + a = -17; + a = -44; + a = -44; + a = -44.9; + a = -1278e3; + a = -12e10; + a = +-x; + a = -17.0; + a = -44.0; + a = -44.0; + a = -44.9; + a = -1278.0e3; + a = -12.0e10; + a = 9223372036854775808.0; + a = -9223372036854775808.0; + a = -9223372036854775808.0; + a = -9223372036854775808; + a = 999999984306749440.0; + a = -999999984306749440.0; + a = -999999984306749440.0; + a = -999999984306749440; + a = 1123456789012345651200.0; + f(g() | 0); + return 12.0e10; +} +function looop() { + do do_it(); while (!condition()); + do do_it(); while (!(a > b)); + do do_it(); while (x()); + while (1) { + do_it(); + if (a()) continue; + if (!x()) break; + } + do { + do_it(); + do if (a()) continue; while (b()); + } while (x()); + do { + do_it(); + while (b()) if (a()) continue; + } while (x()); + X : while (1) { + do_it(); + while (b()) if (a()) continue X; + if (!x()) break; + } + do blah(); while (!shah()); + a = b; + LABELED : while (1) { + blah(); + if (shah()) { + c = d; + break; + } + } + while (1) { + blah(); + if (check) break; + if (shah()) { + e = f; + break; + } + } + do { + blah(); + while (1) if (check) break; + } while (!shah()); + g = h; + if (a) waka(); + if (a) waka(); else wala(); + if (a) if (a) waka(); else wala(); + if (a) { + if (a) waka(); + } else other(); + if (a) if (a) waka(); else wala(); else other(); +} +function conditions() { + if (HEAP32[$incdec_ptr71_i + 8 >> 2] | 0) shoo(); + if (x == 0) y(); + if (!x) y(); + if (!y) z(); + if (x != 0) y(); + if (x) y(); + if (y) z(); + if (x) y(); + if (!x) y(); + if (!(s() | 0)) z(); + if (x + 4 | 0) y(); + if (x & 4) y(); +} + diff --git a/tools/test-js-optimizer-asm-lastOpts-output.js b/tools/test-js-optimizer-asm-lastOpts-output.js new file mode 100644 index 0000000000000..f6f090a6ed558 --- /dev/null +++ b/tools/test-js-optimizer-asm-lastOpts-output.js @@ -0,0 +1,103 @@ +function finall(x) { + x = +x; + var a = +5; + a = +x; + a = 17; + a = +44; + a = +44; + a = +44.9; + a = +1278e3; + a = +12e10; + a = -x; + a = -17; + a = -44; + a = -44; + a = -44.9; + a = -1278e3; + a = -12e10; + a = +-x; + a = +-17; + a = +-44; + a = +-44; + a = +-44.9; + a = +-1278e3; + a = +-12e10; + a = +0x8000000000000000; + a = +-0x8000000000000000; + a = -+0x8000000000000000; + a = -0x8000000000000000; + a = +0xde0b6b000000000; + a = +-0xde0b6b000000000; + a = -+0xde0b6b000000000; + a = -0xde0b6b000000000; + a = +0x3ce7184d470dd60000; + f(g() | 0); + return +12e10; +} +function looop() { + do do_it(); while (!condition()); + do do_it(); while (!(a > b)); + do do_it(); while (x()); + while (1) { + do_it(); + if (a()) continue; + if (!x()) break; + } + do { + do_it(); + do if (a()) continue; while (b()); + } while (x()); + do { + do_it(); + while (b()) if (a()) continue; + } while (x()); + X : while (1) { + do_it(); + while (b()) if (a()) continue X; + if (!x()) break; + } + do blah(); while (!shah()); + a = b; + LABELED : while (1) { + blah(); + if (shah()) { + c = d; + break; + } + } + while (1) { + blah(); + if (check) break; + if (shah()) { + e = f; + break; + } + } + do { + blah(); + while (1) if (check) break; + } while (!shah()); + g = h; + if (a) waka(); + if (a) waka(); else wala(); + if (a) if (a) waka(); else wala(); + if (a) { + if (a) waka(); + } else other(); + if (a) if (a) waka(); else wala(); else other(); +} +function conditions() { + if (HEAP32[$incdec_ptr71_i + 8 >> 2] | 0) shoo(); + if (x == 0) y(); + if (!x) y(); + if (!y) z(); + if (x != 0) y(); + if (x) y(); + if (y) z(); + if (x) y(); + if (!x) y(); + if (!(s() | 0)) z(); + if (x + 4 | 0) y(); + if (x & 4) y(); +} + diff --git a/tools/test-js-optimizer-asm-lastOpts-output2.js b/tools/test-js-optimizer-asm-lastOpts-output2.js new file mode 100644 index 0000000000000..0c18b8c924a8d --- /dev/null +++ b/tools/test-js-optimizer-asm-lastOpts-output2.js @@ -0,0 +1,103 @@ +function finall(x) { + x = +x; + var a = +5; + a = +x; + a = 17; + a = +44; + a = +44; + a = +44.9; + a = +1278e3; + a = +12e10; + a = -x; + a = -17; + a = -44; + a = -44; + a = -44.9; + a = -1278e3; + a = -12e10; + a = +-x; + a = +-17; + a = +-44; + a = +-44; + a = +-44.9; + a = +-1278e3; + a = +-12e10; + a = +0x8000000000000000; + a = +-0x8000000000000000; + a = -+0x8000000000000000; + a = -0x8000000000000000; + a = +0xde0b6b000000000; + a = +-0xde0b6b000000000; + a = -+0xde0b6b000000000; + a = -0xde0b6b000000000; + a = +1123456789012345651200; + f(g() | 0); + return +12e10; +} +function looop() { + do do_it(); while (!condition()); + do do_it(); while (!(a > b)); + do do_it(); while (x()); + while (1) { + do_it(); + if (a()) continue; + if (!x()) break; + } + do { + do_it(); + do if (a()) continue; while (b()); + } while (x()); + do { + do_it(); + while (b()) if (a()) continue; + } while (x()); + X : while (1) { + do_it(); + while (b()) if (a()) continue X; + if (!x()) break; + } + do blah(); while (!shah()); + a = b; + LABELED : while (1) { + blah(); + if (shah()) { + c = d; + break; + } + } + while (1) { + blah(); + if (check) break; + if (shah()) { + e = f; + break; + } + } + do { + blah(); + while (1) if (check) break; + } while (!shah()); + g = h; + if (a) waka(); + if (a) waka(); else wala(); + if (a) if (a) waka(); else wala(); + if (a) { + if (a) waka(); + } else other(); + if (a) if (a) waka(); else wala(); else other(); +} +function conditions() { + if (HEAP32[$incdec_ptr71_i + 8 >> 2] | 0) shoo(); + if (x == 0) y(); + if (!x) y(); + if (!y) z(); + if (x != 0) y(); + if (x) y(); + if (y) z(); + if (x) y(); + if (!x) y(); + if (!(s() | 0)) z(); + if (x + 4 | 0) y(); + if (x & 4) y(); +} + diff --git a/tools/test-js-optimizer-asm-pre-output2.js b/tools/test-js-optimizer-asm-pre-output2.js new file mode 100644 index 0000000000000..2711d862bf071 --- /dev/null +++ b/tools/test-js-optimizer-asm-pre-output2.js @@ -0,0 +1,605 @@ +function a() { + f((HEAPU8[10202] | 0) + 5 | 0); + f(HEAPU8[10202] | 0); + f(347); + f(351); + f(8); + HEAP[1024] = 5; + HEAP[1024] = 5; + whee(12, 13) | 0; + +whee(12, 13); + f((g = t(), g + g | 0) | 0); + f() | 0; + f((h() | 0) + 5 | 0); + f(x + y + z | 0); + +f(); + f(+(+h() + 5)); + $140 = $p_3_i + (-$mantSize_0_i | 0) | 0; + f(g() | 0); + f(g() | 0 & -1); + f((g() | 0) >> 2); + $56 = _fcntl() | 0 | 1; + FUNCTION_TABLE_ii[55 & 127]() | 0; +} +function b($this, $__n) { + $this = $this | 0; + $__n = $__n | 0; + var $4 = 0, $5 = 0, $10 = 0, $13 = 0, $14 = 0, $15 = 0, $23 = 0, $30 = 0, $38 = 0, $40 = 0; + if (($__n | 0) == 0) { + return; + } + $4 = $this; + $5 = HEAP8[$4 & 16777215] | 0; + if (($5 & 1) == 0) { + $14 = 10; + $13 = $5; + } else { + $10 = HEAP32[($this & 16777215) >> 2] | 0; + $14 = ($10 & -2) - 1 | 0; + $13 = $10 & 255; + } + $15 = $13 & 255; + if (($15 & 1 | 0) == 0) { + $23 = $15 >>> 1; + } else { + $23 = HEAP32[($this + 4 & 16777215) >> 2] | 0; + } + if (($14 - $23 | 0) >>> 0 < $__n >>> 0) { + __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__grow_byEjjjjjj($this, $14, $__n - $14 + $23 | 0, $23, $23); + $30 = HEAP8[$4 & 16777215] | 0; + } else { + $30 = $13; + } + if (($30 & 1) == 0) { + $38 = $this + 1 | 0; + } else { + $38 = HEAP32[($this + 8 & 16777215) >> 2] | 0; + } + _memset($38 + $23 | 0, 0, $__n | 0, 1, 1213141516); + $40 = $23 + $__n | 0; + if ((HEAP8[$4 & 16777215] & 1) == 0) { + HEAP8[$4 & 16777215] = $40 << 1; + } else { + HEAP32[($this + 4 & 16777215) >> 2] = $40; + } + HEAP8[$38 + $40 & 16777215] = 0; + HEAP32[$4] = ~HEAP32[$5]; + HEAP8[$4] = HEAP32[$5]; + HEAP16[$4] = HEAP32[$5]; + HEAP32[$4] = ~HEAP32[$5]; + HEAP32[$4] = ~HEAP32[$5]; + h(~~g ^ -1); + return; +} +function i32_8() { + if ((HEAP8[$4 & 16777215] | 0) == 0) { + print(5); + } + if ((HEAP8[$5 & 16777215] | 0) == 0) { + print(5); + } + if ((HEAP8[$6 & 16777215] | 0) == 0) { + print(5); + } + if ((HEAP8[$7 & 16777215] | 0) == 0) { + print(5); + } + if (HEAPU8[$8 & 16777215] << 24 >> 16 == 0) { + print(5); + } + if (HEAPU8[$9 & 16777215] << 16 >> 16 == 0) { + print(5); + } +} +function sign_extension_simplification() { + if ((HEAP8[$4 & 16777215] & 127) == 0) { + print(5); + } + if ((HEAP8[$4 & 16777215] & 128) << 24 >> 24 == 0) { + print(5); + } + if ((HEAP32[$5 & 16777215] & 32767) == 0) { + print(5); + } + if ((HEAP32[$5 & 16777215] & 32768) << 16 >> 16 == 0) { + print(5); + } +} +function compare_result_simplification() { + f((a > b & 1) + 1 | 0); + f(a > b | z); + f(a > b | c > d); + HEAP32[$4] = HEAP32[$5] < HEAP32[$6] & 1; + var x = HEAP32[$5] != HEAP32[$6] & 1; +} +function tempDoublePtr($45, $14, $28, $42) { + $45 = $45 | 0; + $14 = $14 | 0; + $28 = $28 | 0; + $42 = $42 | 0; + var unelim = +0, bad = 0, unelim2 = +0; + unelim = +(127.5 * +$14); + HEAPF32[$45 >> 2] = ($14 < $28 ? $14 : $28) - $42; + HEAP32[$world + 102916 >> 2] = _malloc(192) | 0; + f(+HEAPF32[$45 >> 2]); + g(HEAP32[$14 >> 2] | 0); + $42 = +HEAPF32[$42 >> 2]; + ch($42); + HEAPF32[$45 >> 2] = unelim; + moar(); + bad = (HEAPF32[tempDoublePtr >> 2] = 127.5 * +$14, HEAP32[tempDoublePtr >> 2] | 0); + func(); + HEAP32[4] = bad; + HEAP32[5] = bad + 1; + moar(); + unelim2 = 127 + $14 | 0; + func(); + HEAP32[4] = unelim2; + barrier(); + $f163 = (HEAP32[tempDoublePtr >> 2] = HEAP32[$f165 >> 2], HEAP32[tempDoublePtr + 4 >> 2] = HEAP32[$f165 + 4 >> 2], +HEAPF64[tempDoublePtr >> 3]); +} +function boxx($this, $aabb, $xf, $childIndex) { + $this = $this | 0; + $aabb = $aabb | 0; + $xf = $xf | 0; + $childIndex = $childIndex | 0; + var $2 = +0, $4 = +0, $7 = +0, $9 = +0, $13 = +0, $14 = +0, $19 = +0, $20 = +0, $22 = +0, $25 = +0, $28 = +0, $32 = +0, $42 = +0, $45 = 0, $_sroa_06_0_insert_insert$1 = +0, $51 = 0, $_sroa_0_0_insert_insert$1 = +0; + $2 = +HEAPF32[$xf + 12 >> 2]; + $4 = +HEAPF32[$this + 12 >> 2]; + $7 = +HEAPF32[$xf + 8 >> 2]; + $9 = +HEAPF32[$this + 16 >> 2]; + $13 = +HEAPF32[$xf >> 2]; + $14 = $13 + ($2 * $4 - $7 * $9); + $19 = +HEAPF32[$xf + 4 >> 2]; + $20 = $4 * $7 + $2 * $9 + $19; + $22 = +HEAPF32[$this + 20 >> 2]; + $25 = +HEAPF32[$this + 24 >> 2]; + $28 = $13 + ($2 * $22 - $7 * $25); + $32 = $19 + ($7 * $22 + $2 * $25); + $42 = +HEAPF32[$this + 8 >> 2]; + $45 = $aabb; + $_sroa_06_0_insert_insert$1 = +(($20 < $32 ? $20 : $32) - $42); + HEAPF32[$45 >> 2] = ($14 < $28 ? $14 : $28) - $42; + HEAPF32[$45 + 4 >> 2] = $_sroa_06_0_insert_insert$1; + $51 = $aabb + 8 | 0; + $_sroa_0_0_insert_insert$1 = +($42 + ($20 > $32 ? $20 : $32)); + HEAPF32[$51 >> 2] = $42 + ($14 > $28 ? $14 : $28); + HEAPF32[$51 + 4 >> 2] = $_sroa_0_0_insert_insert$1; + return; +} +function _main($argc, $argv) { + $argc = $argc | 0; + $argv = $argv | 0; + var $def_i21 = 0, $def_i = 0, $world = 0, $bd = 0, $shape = 0, $shape1 = 0, $bd2 = 0, $result = 0, $6 = 0, $WARMUP_0 = 0, $14 = 0, $15 = 0, $17 = 0, $i_09_i_i = 0, $j_08_i_i = 0, $34 = 0, $j_1_i_i = 0, $38 = 0, $46 = 0, $48 = 0, $50 = 0, $54 = 0, $i_05_i_i_i = 0, $56 = 0, $62 = 0, $_lcssa_i_i_i = 0, $87 = 0, $96 = 0, $97 = 0, $98 = 0, $112 = 0, $115 = 0, $116 = 0, $118 = 0, $121 = 0, $126 = 0, $135 = 0, $137 = 0, $174 = 0, $176 = 0, $177 = 0, $178 = 0, $179 = 0, $180 = 0, $181 = 0, $182 = 0, $183 = 0, $185 = 0, $186 = 0, $188 = 0, $189 = 0, $190 = 0, $191 = 0, $192 = 0, $193 = 0, $194 = 0, $195 = 0, $196 = 0, $i_057 = 0, $x_sroa_0_0_load303656 = +0, $x_sroa_1_4_load313755 = +0, $j_052 = 0, $y_sroa_0_0_load283451 = +0, $y_sroa_1_4_load293550 = +0, $y_sroa_0_0_insert_insert$1 = +0, $205 = 0, $208 = 0, $209 = 0, $213 = 0, $223 = 0, $236 = 0, $i3_042 = 0, $241 = 0, $242 = 0, $243 = 0, $i4_038 = 0, $245 = 0, $260 = +0, $_0 = 0, label = 0, __stackBase__ = 0; + __stackBase__ = STACKTOP; + STACKTOP = STACKTOP + 103416 | 0; + $def_i21 = __stackBase__ | 0; + $def_i = __stackBase__ + 32 | 0; + $world = __stackBase__ + 64 | 0; + $bd = __stackBase__ + 103096 | 0; + $shape = __stackBase__ + 103152 | 0; + $shape1 = __stackBase__ + 103200 | 0; + $bd2 = __stackBase__ + 103352 | 0; + $result = __stackBase__ + 103408 | 0; + do { + if (($argc | 0) > 1) { + $6 = HEAP8[HEAP32[$argv + 4 >> 2] | 0] | 0; + if (($6 | 0) == 49) { + HEAP32[2414] = 35; + $WARMUP_0 = 5; + break; + } else if (($6 | 0) == 50) { + HEAP32[2414] = 161; + $WARMUP_0 = 32; + break; + } else if (($6 | 0) == 51) { + label = 43; + break; + } else if (($6 | 0) == 52) { + HEAP32[2414] = 2331; + $WARMUP_0 = 320; + break; + } else if (($6 | 0) == 53) { + HEAP32[2414] = 5661; + $WARMUP_0 = 640; + break; + } else if (($6 | 0) == 48) { + $_0 = 0; + STACKTOP = __stackBase__; + return $_0 | 0; + } else { + _printf(3512, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[tempInt >> 2] = $6 - 48, tempInt) | 0) | 0; + $_0 = -1; + STACKTOP = __stackBase__; + return $_0 | 0; + } + } else { + label = 43; + } + fsdf} while (0); + if ((label | 0) == 43) { + HEAP32[2414] = 333; + $WARMUP_0 = 64; + } + $14 = $world | 0; + $15 = $world + 8 | 0; + HEAP32[$15 >> 2] = 128; + HEAP32[$world + 4 >> 2] = 0; + $17 = _malloc(1024) | 0; + HEAP32[$world >> 2] = $17; + _memset($17 | 0, 0, HEAP32[$15 >> 2] << 3 | 0); + _memset($world + 12 | 0, 0, 56); + $j_08_i_i = 0; + $i_09_i_i = 1; + while (1) { + if (($j_08_i_i | 0) >= 14) { + label = 49; + break; + } + if (($i_09_i_i | 0) > (HEAP32[9600 + ($j_08_i_i << 2) >> 2] | 0)) { + $34 = $j_08_i_i + 1 | 0; + HEAP8[$i_09_i_i + 8952 | 0] = $34; + $j_1_i_i = $34; + } else { + HEAP8[$i_09_i_i + 8952 | 0] = $j_08_i_i; + $j_1_i_i = $j_08_i_i; + } + $38 = $i_09_i_i + 1 | 0; + if (($38 | 0) < 641) { + $j_08_i_i = $j_1_i_i; + $i_09_i_i = $38; + } else { + break; + } + } + if ((label | 0) == 49) { + ___assert_func(3248, 73, 6448, 3360); + return 0; + } + HEAP32[$world + 102468 >> 2] = 0; + HEAP32[$world + 102472 >> 2] = 0; + HEAP32[$world + 102476 >> 2] = 0; + HEAP32[$world + 102864 >> 2] = 0; + HEAP32[$world + 102872 >> 2] = -1; + $46 = $world + 102884 | 0; + HEAP32[$46 >> 2] = 16; + HEAP32[$world + 102880 >> 2] = 0; + $48 = _malloc(576) | 0; + $50 = $world + 102876 | 0; + HEAP32[$50 >> 2] = $48; + _memset($48 | 0, 0, (HEAP32[$46 >> 2] | 0) * 36 & -1 | 0); + $54 = (HEAP32[$46 >> 2] | 0) - 1 | 0; + if (($54 | 0) > 0) { + $i_05_i_i_i = 0; + while (1) { + $56 = $i_05_i_i_i + 1 | 0; + HEAP32[(HEAP32[$50 >> 2] | 0) + ($i_05_i_i_i * 36 & -1) + 20 >> 2] = $56; + HEAP32[(HEAP32[$50 >> 2] | 0) + ($i_05_i_i_i * 36 & -1) + 32 >> 2] = -1; + $62 = (HEAP32[$46 >> 2] | 0) - 1 | 0; + if (($56 | 0) < ($62 | 0)) { + $i_05_i_i_i = $56; + } else { + $_lcssa_i_i_i = $62; + break; + } + } + } else { + $_lcssa_i_i_i = $54; + } + HEAP32[(HEAP32[$50 >> 2] | 0) + ($_lcssa_i_i_i * 36 & -1) + 20 >> 2] = -1; + HEAP32[(HEAP32[$50 >> 2] | 0) + (((HEAP32[$46 >> 2] | 0) - 1 | 0) * 36 & -1) + 32 >> 2] = -1; + _memset($world + 102888 | 0, 0, 16); + HEAP32[$world + 102920 >> 2] = 16; + HEAP32[$world + 102924 >> 2] = 0; + HEAP32[$world + 102916 >> 2] = _malloc(192) | 0; + HEAP32[$world + 102908 >> 2] = 16; + HEAP32[$world + 102912 >> 2] = 0; + HEAP32[$world + 102904 >> 2] = _malloc(64) | 0; + HEAP32[$world + 102932 >> 2] = 0; + HEAP32[$world + 102936 >> 2] = 0; + HEAP32[$world + 102940 >> 2] = 104; + HEAP32[$world + 102944 >> 2] = 96; + $87 = $world + 102948 | 0; + HEAP32[$world + 102980 >> 2] = 0; + HEAP32[$world + 102984 >> 2] = 0; + _memset($87 | 0, 0, 20); + HEAP8[$world + 102992 | 0] = 1; + HEAP8[$world + 102993 | 0] = 1; + HEAP8[$world + 102994 | 0] = 0; + HEAP8[$world + 102995 | 0] = 1; + $96 = $world + 102976 | 0; + HEAP8[$96] = 1; + $97 = $world + 102968 | 0; + HEAP32[$97 >> 2] = 0; + HEAP32[$97 + 4 >> 2] = -1054867456; + $98 = $world + 102868 | 0; + HEAP32[$98 >> 2] = 4; + HEAPF32[$world + 102988 >> 2] = +0; + HEAP32[$87 >> 2] = $14; + _memset($world + 102996 | 0, 0, 32); + HEAP8[$96] = 0; + HEAP32[$bd + 44 >> 2] = 0; + _memset($bd + 4 | 0, 0, 32); + HEAP8[$bd + 36 | 0] = 1; + HEAP8[$bd + 37 | 0] = 1; + HEAP8[$bd + 38 | 0] = 0; + HEAP8[$bd + 39 | 0] = 0; + HEAP32[$bd >> 2] = 0; + HEAP8[$bd + 40 | 0] = 1; + HEAPF32[$bd + 48 >> 2] = +1; + $112 = __ZN16b2BlockAllocator8AllocateEi($14, 152) | 0; + if (($112 | 0) == 0) { + $116 = 0; + } else { + $115 = $112; + __ZN6b2BodyC2EPK9b2BodyDefP7b2World($115, $bd, $world); + $116 = $115; + } + HEAP32[$116 + 92 >> 2] = 0; + $118 = $world + 102952 | 0; + HEAP32[$116 + 96 >> 2] = HEAP32[$118 >> 2]; + $121 = HEAP32[$118 >> 2] | 0; + if (($121 | 0) != 0) { + HEAP32[$121 + 92 >> 2] = $116; + } + HEAP32[$118 >> 2] = $116; + $126 = $world + 102960 | 0; + HEAP32[$126 >> 2] = (HEAP32[$126 >> 2] | 0) + 1; + HEAP32[$shape >> 2] = 8016; + HEAP32[$shape + 4 >> 2] = 1; + HEAPF32[$shape + 8 >> 2] = +.009999999776482582; + _memset($shape + 28 | 0, 0, 18); + $135 = $shape + 12 | 0; + HEAP32[$135 >> 2] = -1038090240; + HEAP32[$135 + 4 >> 2] = 0; + $137 = $shape + 20 | 0; + HEAP32[$137 >> 2] = 1109393408; + HEAP32[$137 + 4 >> 2] = 0; + HEAP8[$shape + 44 | 0] = 0; + HEAP8[$shape + 45 | 0] = 0; + HEAP16[$def_i + 22 >> 1] = 1; + HEAP16[$def_i + 24 >> 1] = -1; + HEAP16[$def_i + 26 >> 1] = 0; + HEAP32[$def_i + 4 >> 2] = 0; + HEAPF32[$def_i + 8 >> 2] = +.200000002980232239; + HEAPF32[$def_i + 12 >> 2] = +0; + HEAP8[$def_i + 20 | 0] = 0; + HEAP32[$def_i >> 2] = $shape; + HEAPF32[$def_i + 16 >> 2] = +0; + __ZN6b2Body13CreateFixtureEPK12b2FixtureDef($116, $def_i); + HEAP32[$shape1 >> 2] = 7968; + HEAP32[$shape1 + 4 >> 2] = 2; + HEAPF32[$shape1 + 8 >> 2] = +.009999999776482582; + HEAP32[$shape1 + 148 >> 2] = 4; + HEAPF32[$shape1 + 20 >> 2] = +-.5; + HEAPF32[$shape1 + 24 >> 2] = +-.5; + HEAPF32[$shape1 + 28 >> 2] = +.5; + HEAPF32[$shape1 + 32 >> 2] = +-.5; + HEAPF32[$shape1 + 36 >> 2] = +.5; + HEAPF32[$shape1 + 40 >> 2] = +.5; + HEAPF32[$shape1 + 44 >> 2] = +-.5; + HEAPF32[$shape1 + 48 >> 2] = +.5; + HEAPF32[$shape1 + 84 >> 2] = +0; + HEAPF32[$shape1 + 88 >> 2] = +-1; + HEAPF32[$shape1 + 92 >> 2] = +1; + HEAPF32[$shape1 + 96 >> 2] = +0; + HEAPF32[$shape1 + 100 >> 2] = +0; + HEAPF32[$shape1 + 104 >> 2] = +1; + HEAPF32[$shape1 + 108 >> 2] = +-1; + HEAPF32[$shape1 + 112 >> 2] = +0; + HEAPF32[$shape1 + 12 >> 2] = +0; + HEAPF32[$shape1 + 16 >> 2] = +0; + $174 = $bd2 + 44 | 0; + $176 = $bd2 + 36 | 0; + $177 = $bd2 + 4 | 0; + $178 = $bd2 + 37 | 0; + $179 = $bd2 + 38 | 0; + $180 = $bd2 + 39 | 0; + $181 = $bd2 | 0; + $182 = $bd2 + 40 | 0; + $183 = $bd2 + 48 | 0; + $185 = $bd2 + 4 | 0; + $186 = $shape1 | 0; + $188 = $def_i21 + 22 | 0; + $189 = $def_i21 + 24 | 0; + $190 = $def_i21 + 26 | 0; + $191 = $def_i21 | 0; + $192 = $def_i21 + 4 | 0; + $193 = $def_i21 + 8 | 0; + $194 = $def_i21 + 12 | 0; + $195 = $def_i21 + 16 | 0; + $196 = $def_i21 + 20 | 0; + $x_sroa_1_4_load313755 = +.75; + $x_sroa_0_0_load303656 = +-7; + $i_057 = 0; + L82 : while (1) { + $y_sroa_1_4_load293550 = $x_sroa_1_4_load313755; + $y_sroa_0_0_load283451 = $x_sroa_0_0_load303656; + $j_052 = $i_057; + while (1) { + HEAP32[$174 >> 2] = 0; + _memset($177 | 0, 0, 32); + HEAP8[$176] = 1; + HEAP8[$178] = 1; + HEAP8[$179] = 0; + HEAP8[$180] = 0; + HEAP8[$182] = 1; + HEAPF32[$183 >> 2] = +1; + HEAP32[$181 >> 2] = 2; + $y_sroa_0_0_insert_insert$1 = +$y_sroa_1_4_load293550; + HEAPF32[$185 >> 2] = $y_sroa_0_0_load283451; + HEAPF32[$185 + 4 >> 2] = $y_sroa_0_0_insert_insert$1; + if ((HEAP32[$98 >> 2] & 2 | 0) != 0) { + label = 65; + break L82; + } + $205 = __ZN16b2BlockAllocator8AllocateEi($14, 152) | 0; + if (($205 | 0) == 0) { + $209 = 0; + } else { + $208 = $205; + __ZN6b2BodyC2EPK9b2BodyDefP7b2World($208, $bd2, $world); + $209 = $208; + } + HEAP32[$209 + 92 >> 2] = 0; + HEAP32[$209 + 96 >> 2] = HEAP32[$118 >> 2]; + $213 = HEAP32[$118 >> 2] | 0; + if (($213 | 0) != 0) { + HEAP32[$213 + 92 >> 2] = $209; + } + HEAP32[$118 >> 2] = $209; + HEAP32[$126 >> 2] = (HEAP32[$126 >> 2] | 0) + 1; + HEAP16[$188 >> 1] = 1; + HEAP16[$189 >> 1] = -1; + HEAP16[$190 >> 1] = 0; + HEAP32[$192 >> 2] = 0; + HEAPF32[$193 >> 2] = +.200000002980232239; + HEAPF32[$194 >> 2] = +0; + HEAP8[$196] = 0; + HEAP32[$191 >> 2] = $186; + HEAPF32[$195 >> 2] = +5; + __ZN6b2Body13CreateFixtureEPK12b2FixtureDef($209, $def_i21); + $223 = $j_052 + 1 | 0; + if (($223 | 0) < 40) { + $y_sroa_1_4_load293550 = $y_sroa_1_4_load293550 + +0; + $y_sroa_0_0_load283451 = $y_sroa_0_0_load283451 + 1.125; + $j_052 = $223; + } else { + break; + } + } + $236 = $i_057 + 1 | 0; + if (($236 | 0) < 40) { + $x_sroa_1_4_load313755 = $x_sroa_1_4_load313755 + +1; + $x_sroa_0_0_load303656 = $x_sroa_0_0_load303656 + +.5625; + $i_057 = $236; + } else { + $i3_042 = 0; + break; + } + } + if ((label | 0) == 65) { + ___assert_func(112, 109, 5328, 2520); + return 0; + } + while (1) { + __ZN7b2World4StepEfii($world); + $i3_042 = $i3_042 + 1 | 0; + if (($i3_042 | 0) >= ($WARMUP_0 | 0)) { + break; + } + } + $241 = HEAP32[2414] | 0; + $242 = _llvm_stacksave() | 0; + $243 = STACKTOP; + STACKTOP = STACKTOP + ($241 * 4 & -1) | 0; + STACKTOP = STACKTOP + 7 >> 3 << 3; + if (($241 | 0) > 0) { + $i4_038 = 0; + while (1) { + $245 = _clock() | 0; + __ZN7b2World4StepEfii($world); + HEAP32[$243 + ($i4_038 << 2) >> 2] = (_clock() | 0) - $245; + $i4_038 = $i4_038 + 1 | 0; + if (($i4_038 | 0) >= (HEAP32[2414] | 0)) { + break; + } + } + } + __Z7measurePm($result, $243); + $260 = +HEAPF32[$result + 4 >> 2]; + _printf(3480, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[tempInt >> 3] = +HEAPF32[$result >> 2], HEAPF64[tempInt + 8 >> 3] = $260, tempInt) | 0) | 0; + _llvm_stackrestore($242 | 0); + __ZN7b2WorldD2Ev($world); + $_0 = 0; + STACKTOP = __stackBase__; + return $_0 | 0; +} +function badf() { + var $9 = 0; + $9 = $8 | 0; + HEAP32[$gep23_asptr >> 2] = $9; +} +function badf2() { + var $9 = +0; + $9 = +$8; + HEAPF32[$gep23_asptr >> 2] = $9; +} +function fcomp() { + if (!($y < $x)) return 5; + if (!(5 < $x)) return 5; + if (!($y < 5)) return 5; + if (($a | 0) >= ($b | 0)) return 5; + if (($a | 0) >= 5) return 5; + if (5 >= ($b | 0)) return 5; + if (5 >= 5) return 5; +} +function conditionalizeMe() { + if (x > 1 ? x + y + z + w > 12 : 0) { + b(); + } + if (a() > 1 ? x + y + z + w > 12 : 0) { + b(); + } + if (x > 1 & x + y + z + k() > 12) { + b(); + } + if (a() > 1 & x + y + z + k() > 12) { + b(); + } + if (x > 1 ? 1 : x + y + z + w > 12) { + b(); + } + if (a() > 1 ? 1 : x + y + z + w > 12) { + b(); + } + if (x > 1 | x + y + z + k() > 12) { + b(); + } + if (a() > 1 | x + y + z + k() > 12) { + b(); + } + if (x > 1 ? 1 : x + y + z + w > 12) { + b(); + } + if (a() > 1 ? 1 : x + y + z + w > 12) { + b(); + } + if (x + y + z + k() > 12 | x > 1) { + b(); + } + if (x + y + z + k() > 12 | a() > 1) { + b(); + } + while (x > 1 ? x + y + z + w > 12 : 0) { + b(); + } + while (a() > 1 ? x + y + z + w > 12 : 0) { + b(); + } + while (x > 1 & x + y + z + k() > 12) { + b(); + } + while (a() > 1 & x + y + z + k() > 12) { + b(); + } + if (!($sub$i480 >= Math_fround(+0)) | !($sub4$i483 >= Math_fround(+0))) { + b(); + } + if ($sub$i480 >= Math_fround(+0) ? !($sub4$i483 >= Math_fround(HEAPF32[x + y | 0])) : 1) { + b(); + } + if (x > 10 | HEAP[20] + 2 > 5) { + b(); + } + print(((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? 1 : $el) | $cheap > 0); + print(((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? 1 : -1) | $cheap > 0); + print($cheap > 0 ? 1 : (HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? 1 : 0); + print(((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? -1 : 1) | $cheap > 0); + return (((((Math_imul(i6 + 1, i7) | 0) + 17 | 0) % 5 | 0) == 0 ? 1 : ((((Math_imul(i7 + 1, i7) | 0) + 11 | 0) >>> 0) % 3 | 0) == 0) | 0) == 0; +} +function bignum() { + HEAP32[20] = -1515870811; + if (($2814 | 0) < 0) return; +} + diff --git a/tools/validate_asmjs.py b/tools/validate_asmjs.py old mode 100644 new mode 100755 index 3fc08aa277112..b0f2dd66f3b7f --- a/tools/validate_asmjs.py +++ b/tools/validate_asmjs.py @@ -17,7 +17,7 @@ # Given a .js file, returns True/False depending on if that file is valid asm.js def validate_asmjs_jsfile(filename, muteOutput): cmd = shared.SPIDERMONKEY_ENGINE + ['-c', filename] - if cmd[0] == 'js-not-found': + if not shared.SPIDERMONKEY_ENGINE or cmd[0] == 'js-not-found' or len(cmd[0].strip()) == 0: print >> sys.stderr, 'Could not find SpiderMonkey engine! Please set tis location to SPIDERMONKEY_ENGINE in your ~/.emscripten configuration file!' return False try: diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py index 0baa3176cc80d..e2369502ad969 100644 --- a/tools/webidl_binder.py +++ b/tools/webidl_binder.py @@ -128,10 +128,20 @@ def emit_constructor(name): Module['getClass'] = getClass; // Converts a value into a C-style string. -function ensureString(value) { - if (typeof value == 'string') return allocate(intArrayFromString(value), 'i8', ALLOC_STACK); - return value; -} +var ensureString = (function() { + var stringCache = {}; + function ensureString(value) { + if (typeof value == 'string') { + var cachedVal = stringCache[value]; + if (cachedVal) return cachedVal; + var ret = allocate(intArrayFromString(value), 'i8', ALLOC_STACK); + stringCache[value] = ret; + return ret; + } + return value; + } + return ensureString; +})(); ''']