diff options
-rw-r--r-- | AUTHORS | 3 | ||||
-rwxr-xr-x | emcc | 15 | ||||
-rw-r--r-- | src/analyzer.js | 3 | ||||
-rw-r--r-- | src/library.js | 25 | ||||
-rw-r--r-- | src/library_browser.js | 20 | ||||
-rw-r--r-- | src/parseTools.js | 9 | ||||
-rw-r--r-- | src/settings.js | 12 | ||||
-rwxr-xr-x | tests/runner.py | 51 |
8 files changed, 112 insertions, 26 deletions
@@ -1,6 +1,9 @@ The following authors have all licensed their contributions to Emscripten under the licensing terms detailed in LICENSE. +(Authors keep copyright of their contributions, of course; they just grant +a license to everyone to use it as detailed in LICENSE.) + * Alon Zakai <alonzakai@gmail.com> (copyright owned by Mozilla Foundation) * Tim Dawborn <tim.dawborn@gmail.com> * Max Shawabkeh <max99x@gmail.com> @@ -7,7 +7,7 @@ emcc - compiler helper script emcc is a drop-in replacement for a compiler like gcc or clang. Tell your build system to use this instead of the compiler, and similarly -use emar, emld and emranlib instead of the same command without 'em'. +use emar, emranlib etc. instead of the same command without 'em'. Example uses: @@ -32,10 +32,10 @@ Example uses: SET(CMAKE_C_COMPILER "PATH/emcc") SET(CMAKE_CXX_COMPILER "PATH/em++") - SET(CMAKE_LINKER "PATH/emld") - SET(CMAKE_CXX_LINKER "PATH/emld") - SET(CMAKE_C_LINK_EXECUTABLE "PATH/emld") - SET(CMAKE_CXX_LINK_EXECUTABLE "PATH/emld") + SET(CMAKE_LINKER "PATH/emcc") + SET(CMAKE_CXX_LINKER "PATH/emcc") + SET(CMAKE_C_LINK_EXECUTABLE "PATH/emcc") + SET(CMAKE_CXX_LINK_EXECUTABLE "PATH/emcc") SET(CMAKE_AR "PATH/emar") SET(CMAKE_RANLIB "PATH/emranlib") @@ -141,6 +141,9 @@ Options that are modified or new in %s include: or C++ exception catching (to re-enable C++ exception catching, use -s DISABLE_EXCEPTION_CATCHING=0 ). + (For details on the affects of different + opt levels, see apply_opt_level() in + tools/shared.py and also src/settings.js.) Note: Optimizations are only done when compiling to JavaScript, not to intermediate bitcode. @@ -516,6 +519,8 @@ try: elif newargs[i] == '--remove-duplicates': remove_duplicates = True newargs[i] = '' + elif newargs[i].startswith(('-I/', '-L/')): + print >> sys.stderr, 'emcc: warning: -I or -L of an absolute path encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not newargs = [ arg for arg in newargs if arg is not '' ] if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] diff --git a/src/analyzer.js b/src/analyzer.js index 163ff4a8..9bf93c86 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1391,6 +1391,9 @@ function analyzer(data, sidePass) { // Allocas var finishedInitial = false; + + lines = func.lines; // We need to consider all the function lines now, not just the first label + for (var i = 0; i < lines.length; i++) { var item = lines[i]; if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) { diff --git a/src/library.js b/src/library.js index be2e946f..6a94be40 100644 --- a/src/library.js +++ b/src/library.js @@ -3915,26 +3915,13 @@ LibraryManager.library = { return limit; }, - // A glibc-like implementation of the C random number generation functions: - // http://pubs.opengroup.org/onlinepubs/000095399/functions/rand.html - __rand_state: 42, - srand__deps: ['__rand_state'], - srand: function(seed) { - // void srand(unsigned seed); - ___rand_state = seed; - }, - rand__deps: ['__rand_state'], + // Use browser's Math.random(). We can't set a seed, though. + srand: function(seed) {}, // XXX ignored rand: function() { - // int rand(void); - ___rand_state = (1103515245 * ___rand_state + 12345) % 0x100000000; - return ___rand_state & 0x7FFFFFFF; - }, - rand_r: function(seed) { - // int rand_r(unsigned *seed); - var state = {{{ makeGetValue('seed', 0, 'i32') }}}; - state = (1103515245 * state + 12345) % 0x100000000; - {{{ makeSetValue('seed', 0, 'state', 'i32') }}} - return state & 0x7FFFFFFF; + return Math.floor(Math.random()*0x80000000); + }, + rand_r: function(seed) { // XXX ignores the seed + return Math.floor(Math.random()*0x80000000); }, realpath__deps: ['$FS', '__setErrNo'], diff --git a/src/library_browser.js b/src/library_browser.js index f285a6d2..11c9bf2c 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -10,6 +10,10 @@ mergeInto(LibraryManager.library, { $Browser: { mainLoop: { scheduler: null, +#if PROFILE_MAIN_LOOP + meanTime: 0, + lastReport: 0, +#endif shouldPause: false, paused: false, queue: [], @@ -93,7 +97,7 @@ mergeInto(LibraryManager.library, { } if (!b) { var bb = new Browser.BlobBuilder(); - bb.append(byteArray.buffer); + bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range b = bb.getBlob(); } var url = Browser.URLObject.createObjectURL(b); @@ -394,7 +398,21 @@ mergeInto(LibraryManager.library, { Browser.mainLoop.shouldPause = false; return; } + +#if PROFILE_MAIN_LOOP + var start = performance.now(); +#endif jsFunc(); +#if PROFILE_MAIN_LOOP + var now = performance.now(); + var time = now - start; + Browser.mainLoop.meanTime = (Browser.mainLoop.meanTime*9 + time)/10; + if (now - Browser.mainLoop.lastReport > 1000) { + console.log('main loop time: ' + Browser.mainLoop.meanTime); + Browser.mainLoop.lastReport = now; + } +#endif + if (Browser.mainLoop.shouldPause) { // catch pauses from the main loop itself Browser.mainLoop.paused = true; diff --git a/src/parseTools.js b/src/parseTools.js index 86e3c643..e37f3a99 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1794,7 +1794,14 @@ function processMathop(item) { case 'add': return handleOverflow(getFastValue(idents[0], '+', idents[1], item.type), bits); case 'sub': return handleOverflow(getFastValue(idents[0], '-', idents[1], item.type), bits); case 'sdiv': case 'udiv': return makeRounding(getFastValue(idents[0], '/', idents[1], item.type), bits, op[0] === 's'); - case 'mul': return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits); + case 'mul': { + if (bits == 32 && PRECISE_I32_MUL) { + preciseI64MathUsed = true; + return '(i64Math.multiply(' + idents[0] + ',0,' + idents[1] + ',0),i64Math.result[0])'; + } else { + return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits); + } + } case 'urem': case 'srem': return getFastValue(idents[0], '%', idents[1], item.type); case 'or': { if (bits > 32) { diff --git a/src/settings.js b/src/settings.js index 09b17c83..cf329568 100644 --- a/src/settings.js +++ b/src/settings.js @@ -76,6 +76,16 @@ var DOUBLE_MODE = 1; // How to load and store 64-bit doubles. Without typed arra // NaN or an infinite number. var PRECISE_I64_MATH = 1; // If enabled, i64 addition etc. is emulated - which is slow but precise. If disabled, // we use the 'double trick' which is fast but incurs rounding at high values. + // Note that we do not catch 32-bit multiplication by default (which must be done in + // 64 bits for high values for full precision) - you must manually set PRECISE_I32_MUL + // for that. +var PRECISE_I32_MUL = 0; // If enabled, i64 math is done in i32 multiplication. This is necessary if the values + // exceed the JS double-integer limit of ~52 bits. This option can normally be disabled + // because generally i32 multiplication works ok without it, and enabling it has a big + // impact on performance. + // Note that you can hand-optimize your code to avoid the need for this: If you do + // multiplications that actually need 64-bit precision inside 64-bit values, things + // will work properly. (Unless the LLVM optimizer turns them into 32-bit values?) var CLOSURE_ANNOTATIONS = 0; // If set, the generated code will be annotated for the closure // compiler. This potentially lets closure optimize the code better. @@ -115,6 +125,8 @@ var LIBRARY_DEBUG = 0; // Print out when we enter a library call (library*.js). var GL_DEBUG = 0; // Print out all calls into WebGL. As with LIBRARY_DEBUG, you can set a runtime // option, in this case GL.debug. +var PROFILE_MAIN_LOOP = 0; // Profile the function called in set_main_loop + var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catch exceptions. If the code you // are compiling does not actually rely on catching exceptions (but the // compiler generates code for it, maybe because of stdlibc++ stuff), diff --git a/tests/runner.py b/tests/runner.py index b80509ff..7f573952 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -953,6 +953,23 @@ m_divisor is 1091269979 ''' self.do_run(src, 'zero 2, 104', ['hallo']) + def test_i32_mul_precise(self): + if self.emcc_args == None: return self.skip('needs ta2') + + self.emcc_args += ['-s', 'PRECISE_I32_MUL=1'] + src = r''' + #include <stdio.h> + + int main(int argc, char **argv) { + unsigned long d1 = 0x847c9b5d; + unsigned long q = 0x549530e1; + if (argc > 1000) { q += argc; d1 -= argc; } // confuse optimizer + printf("%lu\n", d1*q); + return 0; + } + ''' + self.do_run(src, '3217489085') + def test_i16_emcc_intrinsic(self): Settings.CORRECT_SIGNS = 1 # Relevant to this test @@ -2288,6 +2305,25 @@ c5,de,15,8a Settings.TOTAL_STACK = 1024 self.do_run(src, 'ok!') + def test_stack_void(self): + src = r''' + #include <stdio.h> + + static char s[100]="aaaaa"; + static int func(void) { + if(s[0]!='a') return 0; + printf("iso open %s\n", s, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001); + return 0; + } + int main(){ + int i; + for(i=0;i<5000;i++) + func(); + printf(".ok.\n"); + } + ''' + self.do_run(src, '.ok.\n') + def test_array2(self): src = ''' #include <stdio.h> @@ -3745,6 +3781,8 @@ def process(filename): post_build=add_pre_run_and_checks) def test_rand(self): + return self.skip('rand() is now random') # FIXME + src = r''' #include <stdio.h> #include <stdlib.h> @@ -6968,6 +7006,19 @@ f.close() self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js'))) assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs' + def test_abspaths(self): + # Includes with absolute paths are generally dangerous, things like -I/usr/.. will get to system local headers, not our portable ones. + + shutil.copyfile(path_from_root('tests', 'hello_world.c'), 'main.c') + + for args, expected in [(['-I/usr/something'], True), + (['-L/usr/something'], True), + (['-Isubdir/something'], False), + (['-Lsubdir/something'], False), + ([], False)]: + err = Popen(['python', EMCC, 'main.c'] + args, stderr=PIPE).communicate()[1] + assert ('emcc: warning: -I or -L of an absolute path encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' in err) == expected, err + def test_local_link(self): # Linking a local library directly, like /usr/lib/libsomething.so, cannot work of course since it # doesn't contain bitcode. However, when we see that we should look for a bitcode file for that |