diff options
-rw-r--r-- | src/compiler.js | 8 | ||||
-rw-r--r-- | src/parseTools.js | 8 | ||||
-rw-r--r-- | src/preamble.js | 4 | ||||
-rw-r--r-- | src/settings.js | 13 | ||||
-rw-r--r-- | tests/runner.py | 36 | ||||
-rw-r--r-- | tools/shared.py | 25 |
6 files changed, 64 insertions, 30 deletions
diff --git a/src/compiler.js b/src/compiler.js index 15dd8dc3..3d33ed22 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -47,6 +47,12 @@ if (SAFE_HEAP >= 2) { SAFE_HEAP_LINES = set(SAFE_HEAP_LINES); // for fast checking } +if (PGO) { // by default, correct everything during PGO + CORRECT_SIGNS = CORRECT_SIGNS || 1; + CORRECT_OVERFLOWS = CORRECT_OVERFLOWS || 1; + CORRECT_ROUNDINGS = CORRECT_ROUNDINGS || 1; +} + EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); @@ -57,7 +63,7 @@ assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == // Output some info and warnings based on settings if (!OPTIMIZE || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP || - !SKIP_STACK_IN_SMALL || SAFE_HEAP || AUTO_OPTIMIZE || PROFILE || !DISABLE_EXCEPTION_CATCHING) { + !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) { print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.'); } else { print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code'); diff --git a/src/parseTools.js b/src/parseTools.js index 423ed0cb..d7514ef5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1342,8 +1342,8 @@ function handleOverflow(text, bits) { if (!bits) return text; var correct = correctOverflows(); warn(!correct || bits <= 32, 'Cannot correct overflows of this many bits: ' + bits + ' at line ' + Framework.currItem.lineNum); - if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow() && !AUTO_OPTIMIZE) + ( - AUTO_OPTIMIZE ? ', "' + Debugging.getIdentifier() + '"' : '' + if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow() && !PGO) + ( + PGO ? ', "' + Debugging.getIdentifier() + '"' : '' ) + ')'; if (!correct) return text; if (bits <= 32) { @@ -1398,8 +1398,8 @@ function makeSignOp(value, type, op, force) { var bits, full; if (type in Runtime.INT_TYPES) { bits = parseInt(type.substr(1)); - full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(correctSpecificSign() && !AUTO_OPTIMIZE) + ( - AUTO_OPTIMIZE ? ', "' + Debugging.getIdentifier() + '"' : '' + full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(correctSpecificSign() && !PGO) + ( + PGO ? ', "' + Debugging.getIdentifier() + '"' : '' ) + ')'; // Always sign/unsign constants at compile time, regardless of CHECK/CORRECT if (isNumber(value)) { diff --git a/src/preamble.js b/src/preamble.js index 4bdb4333..9df6bf60 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -187,7 +187,7 @@ function SAFE_HEAP_COPY_HISTORY(dest, src) { #endif var CorrectionsMonitor = { -#if AUTO_OPTIMIZE +#if PGO MAX_ALLOWED: Infinity, #else MAX_ALLOWED: 0, // XXX @@ -200,7 +200,7 @@ var CorrectionsMonitor = { this.corrections++; if (this.corrections >= this.MAX_ALLOWED) abort('\n\nToo many corrections!'); } -#if AUTO_OPTIMIZE +#if PGO if (!sig) sig = (new Error().stack).toString().split('\n')[2].split(':').slice(-1)[0]; // Spidermonkey-specific FIXME sig = type + '|' + sig; diff --git a/src/settings.js b/src/settings.js index e8f65f58..1d64f143 100644 --- a/src/settings.js +++ b/src/settings.js @@ -125,11 +125,14 @@ CORRECT_ROUNDINGS = 1; // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no // Math.floor is to negative, ceil to positive. With CORRECT_ROUNDINGS, // we will do slow but correct C rounding operations. -AUTO_OPTIMIZE = 0; // When run with the CHECK_* options, will not fail on errors. Instead, will - // keep a record of which checks succeeded and which failed. On shutdown, will - // print out that information. This is useful for knowing which lines need - // checking enabled and which do not, that is, this is a way to automate the - // generation of line data for CORRECT_*_LINES options +PGO = 0; // Profile-guided optimization. + // When run with the CHECK_* options, will not fail on errors. Instead, will + // keep a record of which checks succeeded and which failed. On shutdown, will + // print out that information. This is useful for knowing which lines need + // checking enabled and which do not, that is, this is a way to automate the + // generation of line data for CORRECT_*_LINES options. + // All CORRECT_* options default to 1 with PGO builds. + // See https://github.com/kripken/emscripten/wiki/Optimizing-Code for more info PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example. diff --git a/tests/runner.py b/tests/runner.py index 159f7d7b..be77fb7b 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -59,7 +59,9 @@ class RunnerCore(unittest.TestCase): def get_dir(self): return self.working_dir - # Similar to LLVM::createStandardModulePasses() + def get_stdout_path(self): + return os.path.join(self.get_dir(), 'stdout') + def pick_llvm_opts(self, optimization_level, safe=True): global LLVM_OPT_OPTS @@ -3302,10 +3304,10 @@ if 'benchmark' not in str(sys.argv): if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME') Settings.RELOOP = 0 # too slow - auto_optimize_data = read_auto_optimize_data(path_from_root('tests', 'sqlite', 'sqlite-autooptimize.fails.txt')) + pgo_data = read_pgo_data(path_from_root('tests', 'sqlite', 'sqlite-autooptimize.fails.txt')) Settings.CORRECT_SIGNS = 2 - Settings.CORRECT_SIGNS_LINES = auto_optimize_data['signs_lines'] + Settings.CORRECT_SIGNS_LINES = pgo_data['signs_lines'] Settings.CORRECT_OVERFLOWS = 0 Settings.CORRECT_ROUNDINGS = 0 Settings.SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff @@ -4303,10 +4305,10 @@ Child2:9 self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') - def test_autooptimize(self): + def test_pgo(self): if Settings.USE_TYPED_ARRAYS == 2: return self.skip('LLVM opts optimize out the things we check') - Settings.AUTO_OPTIMIZE = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.CORRECT_SIGNS = 1 + Settings.PGO = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.CORRECT_SIGNS = 1 src = ''' #include<stdio.h> @@ -4335,6 +4337,26 @@ Child2:9 self.do_run(src, '*186854335,63*\n', output_nicerizer=check) + Settings.PGO = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.CORRECT_SIGNS = 0 + + # Now, recompile with the PGO data, and it should work + + pgo_data = read_pgo_data(self.get_stdout_path()) + + Settings.CORRECT_SIGNS = 2 + Settings.CORRECT_SIGNS_LINES = pgo_data['signs_lines'] + Settings.CORRECT_OVERFLOWS = 2 + Settings.CORRECT_OVERFLOWS_LINES = pgo_data['overflows_lines'] + + self.do_run(src, '*186854335,63*\n') + + # Sanity check: Without PGO, we will fail + + try: + self.do_run(src, '*186854335,63*\n') + except: + pass + # Generate tests for all our compilers def make_run(name, compiler, llvm_opts, embetter, quantum_size, typed_arrays): @@ -4357,7 +4379,7 @@ class %s(T): Settings.ASSERTIONS = 1-embetter Settings.SAFE_HEAP = 1-(embetter and llvm_opts) Building.LLVM_OPTS = llvm_opts - Settings.AUTO_OPTIMIZE = 0 + Settings.PGO = 0 Settings.CHECK_OVERFLOWS = 1-(embetter or llvm_opts) Settings.CORRECT_OVERFLOWS = 1-(embetter and llvm_opts) Settings.CORRECT_SIGNS = 0 @@ -4465,7 +4487,7 @@ else: Settings.USE_TYPED_ARRAYS = 1 Settings.QUANTUM_SIZE = 1 Settings.I64_MODE = 0 - Settings.ASSERTIONS = Settings.SAFE_HEAP = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.INIT_STACK = Settings.AUTO_OPTIMIZE = Settings.RUNTIME_TYPE_INFO = 0 + Settings.ASSERTIONS = Settings.SAFE_HEAP = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.INIT_STACK = Settings.PGO = Settings.RUNTIME_TYPE_INFO = 0 Settings.INVOKE_RUN = 1 Settings.CORRECT_SIGNS = 0 Settings.CORRECT_ROUNDINGS = 0 diff --git a/tools/shared.py b/tools/shared.py index 8dc9fbea..6f80e8b0 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -186,22 +186,25 @@ def pick_llvm_opts(optimization_level, safe=True): return opts -def read_auto_optimize_data(filename): +def read_pgo_data(filename): ''' - Reads the output of AUTO_OPTIMIZE and generates proper information for CORRECT_* == 2 's *_LINES options + Reads the output of PGO and generates proper information for CORRECT_* == 2 's *_LINES options ''' signs_lines = [] overflows_lines = [] for line in open(filename, 'r'): - if line.rstrip() == '': continue - if '%0 failures' in line: continue - left, right = line.split(' : ') - signature = left.split('|')[1] - if 'Sign' in left: - signs_lines.append(signature) - elif 'Overflow' in left: - overflows_lines.append(signature) + try: + if line.rstrip() == '': continue + if '%0 failures' in line: continue + left, right = line.split(' : ') + signature = left.split('|')[1] + if 'Sign' in left: + signs_lines.append(signature) + elif 'Overflow' in left: + overflows_lines.append(signature) + except: + pass return { 'signs_lines': signs_lines, @@ -340,7 +343,7 @@ class Building: # Run Emscripten exported_settings = {} - for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTION_CATCHING', 'TOTAL_MEMORY', 'FAST_MEMORY', 'EXCEPTION_DEBUG', 'PROFILE', 'I64_MODE', 'EMULATE_UNALIGNED_ACCESSES']: + for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'PGO', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTION_CATCHING', 'TOTAL_MEMORY', 'FAST_MEMORY', 'EXCEPTION_DEBUG', 'PROFILE', 'I64_MODE', 'EMULATE_UNALIGNED_ACCESSES']: try: value = eval('Settings.' + setting) if value is not None: |