Skip to content

Commit

Permalink
Remove fastcomp-only ELIMINATE_DUPLICATE_FUNCTIONS* options (#11876)
Browse files Browse the repository at this point in the history
This has been a no-op on wasm, and this PR keeps it that way (we do
duplicate function elimination in binaryen automatically).

See #11860
  • Loading branch information
kripken authored Aug 12, 2020
1 parent 40dbef9 commit 574f381
Show file tree
Hide file tree
Showing 9 changed files with 4 additions and 1,147 deletions.
9 changes: 0 additions & 9 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1869,9 +1869,6 @@ def include_and_export(name):
shared.Settings.WASM_BINARY_FILE = shared.JS.escape_for_js_string(os.path.basename(wasm_binary_target))
shared.Settings.ASMJS_CODE_FILE = shared.JS.escape_for_js_string(os.path.basename(asm_target))
shared.Settings.ASM_JS = 2 # when targeting wasm, we use a wasm Memory, but that is not compatible with asm.js opts
if shared.Settings.ELIMINATE_DUPLICATE_FUNCTIONS:
diagnostics.warning('emcc', 'for wasm there is no need to set ELIMINATE_DUPLICATE_FUNCTIONS, the binaryen optimizer does it automatically')
shared.Settings.ELIMINATE_DUPLICATE_FUNCTIONS = 0
if options.js_opts and not options.force_js_opts:
options.js_opts = None
logger.debug('asm.js opts not forced by user or an option that depends them, and we do not intend to run the asm.js, so disabling and leaving opts to the binaryen optimizer')
Expand Down Expand Up @@ -2695,12 +2692,6 @@ def get_eliminate():
else:
optimizer.queue += ['registerize']

# NOTE: Important that this comes after registerize/registerizeHarder
if shared.Settings.ELIMINATE_DUPLICATE_FUNCTIONS and shared.Settings.OPT_LEVEL >= 2:
optimizer.flush()
building.eliminate_duplicate_funcs(final)
save_intermediate('dfe')

if shared.Settings.EVAL_CTORS and options.memory_init_file and not use_source_map(options) and not shared.Settings.WASM:
optimizer.flush()
building.eval_ctors(final, memfile)
Expand Down
1 change: 0 additions & 1 deletion site/source/docs/optimizing/Optimizing-Code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ The following compiler settings can help (see ``src/settings.js`` for more detai
- Disable inlining when possible, using ``-s INLINING_LIMIT=1``. Compiling with -Os or -Oz generally avoids inlining too. (Inlining can make code faster, though, so use this carefully.)
- You can use the ``-s FILESYSTEM=0`` option to disable bundling of filesystem support code (the compiler should optimize it out if not used, but may not always succeed). This can be useful if you are building a pure computational library, for example.
- The ``ENVIRONMENT`` flag lets you specify that the output will only run on the web, or only run in node.js, etc. This prevents the compiler from emitting code to support all possible runtime environments, saving ~2KB.
- You can use ``ELIMINATE_DUPLICATE_FUNCTIONS`` to remove duplicate functions, which C++ templates often create. (This is already done by default for wasm, in ``-O1`` and above.)

LTO
===
Expand Down
16 changes: 3 additions & 13 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1412,19 +1412,6 @@ var PTHREADS_DEBUG = 0;
// If true, building against Emscripten's asm.js/wasm heap memory profiler.
var MEMORYPROFILER = 0;

// Duplicate function elimination. This coalesces function bodies that are
// identical, which can happen e.g. if two methods have different C/C++ or LLVM
// types, but end up identical at the asm.js level (all pointers are the same as
// int32_t in asm.js, for example).
//
// This option is quite slow to run, as it processes and hashes all methods in
// the codebase in multiple passes.
//
// [fastcomp-only]
var ELIMINATE_DUPLICATE_FUNCTIONS = 0; // disabled by default
var ELIMINATE_DUPLICATE_FUNCTIONS_DUMP_EQUIVALENT_FUNCTIONS = 0;
var ELIMINATE_DUPLICATE_FUNCTIONS_PASSES = 5;

// This tries to evaluate global ctors at compile-time, applying their effects
// into the mem init file. This saves running code during startup, and also
// allows removing the global ctor functions and other code that only they used,
Expand Down Expand Up @@ -1766,6 +1753,9 @@ var LEGACY_SETTINGS = [
['SKIP_STACK_IN_SMALL', [0, 1], 'SKIP_STACK_IN_SMALL is no longer needed as the backend can optimize it directly'],
['SAFE_STACK', [0], 'Replace SAFE_STACK=1 with STACK_OVERFLOW_CHECK=2'],
['MEMORY_GROWTH_STEP', 'MEMORY_GROWTH_LINEAR_STEP'],
['ELIMINATE_DUPLICATE_FUNCTIONS', [0, 1], 'Duplicate function elimination for wasm is handled automatically by binaryen'],
['ELIMINATE_DUPLICATE_FUNCTIONS_DUMP_EQUIVALENT_FUNCTIONS', [0], 'Duplicate function elimination for wasm is handled automatically by binaryen'],
['ELIMINATE_DUPLICATE_FUNCTIONS_PASSES', [5], 'Duplicate function elimination for wasm is handled automatically by binaryen'],
// WASM_OBJECT_FILES is handled in emcc.py, supporting both 0 and 1 for now.
['WASM_OBJECT_FILES', [0, 1], 'For LTO, use -flto or -fto=thin instead; to disable LTO, just do not pass WASM_OBJECT_FILES=1 as 1 is the default anyhow'],
['TOTAL_MEMORY', 'INITIAL_MEMORY'],
Expand Down
5 changes: 0 additions & 5 deletions tests/fuzz/25.c
Original file line number Diff line number Diff line change
Expand Up @@ -1785,8 +1785,3 @@ XXX max block depth: 5
XXX percentage a fresh-made variable is used: 17.8
XXX percentage an existing variable is used: 82.2
********************* end of statistics **********************/


// /usr/bin/python /Users/achoudhury/Code/emscripten/emscripten/emcc -Oz --llvm-opts 1 /Users/achoudhury/Code/emscripten/emscripten/tests/fuzz/temp_fuzzcode28225_.cpp -o /Users/achoudhury/Code/emscripten/emscripten/tests/fuzz/fuzz.cpp -I /usr/local/Cellar/csmith/2.2.0/include/csmith-2.2.0/runtime -s ELIMINATE_DUPLICATE_FUNCTIONS=1 --emit-symbol-map -w -s MAIN_MODULE=1 -s EMTERPRETIFY=1 -s EMTERPRETIFY_WHITELIST=["_main"]


28 changes: 0 additions & 28 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,6 @@ class TestCoreBase(RunnerCore):
def is_wasm2js(self):
return self.is_wasm_backend() and not self.get_setting('WASM')

# whether the test mode supports duplicate function elimination in js
def supports_js_dfe(self):
# wasm does this when optimizing anyhow, and the wasm backend always
# optimizes the wasm even if it does wasm2js later
if self.is_wasm() or self.is_wasm_backend():
return False
supported_opt_levels = ['-O2', '-O3', '-Oz', '-Os']
for opt_level in supported_opt_levels:
if opt_level in self.emcc_args:
return True
return False

# Use closure in some tests for some additional coverage
def maybe_closure(self):
if '-g' not in self.emcc_args and ('-O2' in self.emcc_args or '-Os' in self.emcc_args):
Expand Down Expand Up @@ -6258,14 +6246,6 @@ def test():

test()

if self.supports_js_dfe():
print("Testing poppler with ELIMINATE_DUPLICATE_FUNCTIONS set to 1", file=sys.stderr)
num_original_funcs = self.count_funcs('src.cpp.o.js')
self.set_setting('ELIMINATE_DUPLICATE_FUNCTIONS', 1)
test()
# Make sure that DFE ends up eliminating more than 200 functions (if we can view source)
assert (num_original_funcs - self.count_funcs('src.cpp.o.js')) > 200

@needs_make('make')
@is_slow_test
def test_openjpeg(self):
Expand Down Expand Up @@ -8290,14 +8270,6 @@ def test(assert_returncode=0):
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
test()

def test_dfe(self):
if not self.supports_js_dfe():
self.skipTest('dfe-only')
self.set_setting('ELIMINATE_DUPLICATE_FUNCTIONS', 1)
self.do_run_in_out_file_test('tests', 'core', 'test_hello_world')
self.emcc_args += ['-g2'] # test for issue #6331
self.do_run_in_out_file_test('tests', 'core', 'test_hello_world')

def test_postrun_exception(self):
# verify that an exception thrown in postRun() will not trigger the
# compilation failed handler, and will be printed to stderr.
Expand Down
127 changes: 1 addition & 126 deletions tests/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import tools.line_endings
import tools.js_optimizer
import tools.tempfiles
import tools.duplicate_function_eliminator

scons_path = shared.which('scons')
emmake = shared.bat_suffix(path_from_root('emmake'))
Expand Down Expand Up @@ -6999,130 +6998,6 @@ def test_warn_unexported_main(self):
proc = self.run_process([EMCC, path_from_root('tests', 'hello_world.c'), '-s', 'EXPORTED_FUNCTIONS=[]'], stderr=PIPE)
self.assertContained(WARNING, proc.stderr)

############################################################
# Function eliminator tests
############################################################
def normalize_line_endings(self, input):
return input.replace('\r\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')

def get_file_contents(self, file):
file_contents = ""
with open(file) as fout:
file_contents = "".join(fout.readlines())

file_contents = self.normalize_line_endings(file_contents)

return file_contents

def function_eliminator_test_helper(self, input_file, expected_output_file, use_hash_info=False):
input_file = path_from_root('tests', 'optimizer', input_file)
expected_output_file = path_from_root('tests', 'optimizer', expected_output_file)
command = [path_from_root('tools', 'eliminate-duplicate-functions.js'), input_file, '--no-minimize-whitespace', '--use-asm-ast']

if use_hash_info:
command.append('--use-hash-info')

proc = self.run_process(NODE_JS + command, stdin=PIPE, stderr=PIPE, stdout=PIPE)
assert proc.stderr == '', proc.stderr
expected_output = self.get_file_contents(expected_output_file)
output = self.normalize_line_endings(proc.stdout)

self.assertIdentical(expected_output, output)

def test_function_eliminator_simple(self):
self.function_eliminator_test_helper('test-function-eliminator-simple.js',
'test-function-eliminator-simple-output.js')

def test_function_eliminator_replace_function_call(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-function-call.js',
'test-function-eliminator-replace-function-call-output.js')

def test_function_eliminator_replace_function_call_two_passes(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-function-call-output.js',
'test-function-eliminator-replace-function-call-two-passes-output.js')

def test_function_eliminator_replace_array_value(self):
output_file = 'output.js'

try:
shared.safe_copy(path_from_root('tests', 'optimizer', 'test-function-eliminator-replace-array-value.js'), output_file)

tools.duplicate_function_eliminator.run(output_file)

output_file_contents = self.get_file_contents(output_file)

expected_file_contents = self.get_file_contents(path_from_root('tests', 'optimizer', 'test-function-eliminator-replace-array-value-output.js'))

self.assertIdentical(expected_file_contents, output_file_contents)
finally:
tools.tempfiles.try_delete(output_file)

def test_function_eliminator_replace_object_value_assignment(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-object-value-assignment.js',
'test-function-eliminator-replace-object-value-assignment-output.js')

def test_function_eliminator_variable_clash(self):
self.function_eliminator_test_helper('test-function-eliminator-variable-clash.js',
'test-function-eliminator-variable-clash-output.js')

def test_function_eliminator_replace_variable_value(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-variable-value.js',
'test-function-eliminator-replace-variable-value-output.js')

@no_wasm_backend('tests native asm.js optimizer, which is never build for wasm backend')
def test_function_eliminator_double_parsed_correctly(self):
# This is a test that makes sure that when we perform final optimization on
# the JS file, doubles are preserved (and not converted to ints).
output_file = 'output.js'

try:
shared.safe_copy(path_from_root('tests', 'optimizer', 'test-function-eliminator-double-parsed-correctly.js'), output_file)

# Run duplicate function elimination
tools.duplicate_function_eliminator.run(output_file)

# Run last opts
shutil.move(tools.js_optimizer.run(output_file, ['last', 'asm']), output_file)
output_file_contents = self.get_file_contents(output_file)

# Compare
expected_file_contents = self.get_file_contents(path_from_root('tests', 'optimizer', 'test-function-eliminator-double-parsed-correctly-output.js'))
self.assertIdentical(expected_file_contents, output_file_contents)
finally:
tools.tempfiles.try_delete(output_file)

# Now do the same, but using a pre-generated equivalent function hash info that
# comes in handy for parallel processing
def test_function_eliminator_simple_with_hash_info(self):
self.function_eliminator_test_helper('test-function-eliminator-simple-with-hash-info.js',
'test-function-eliminator-simple-output.js',
use_hash_info=True)

def test_function_eliminator_replace_function_call_with_hash_info(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-function-call-with-hash-info.js',
'test-function-eliminator-replace-function-call-output.js',
use_hash_info=True)

def test_function_eliminator_replace_function_call_two_passes_with_hash_info(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-function-call-output-with-hash-info.js',
'test-function-eliminator-replace-function-call-two-passes-output.js',
use_hash_info=True)

def test_function_eliminator_replace_object_value_assignment_with_hash_info(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-object-value-assignment-with-hash-info.js',
'test-function-eliminator-replace-object-value-assignment-output.js',
use_hash_info=True)

def test_function_eliminator_variable_clash_with_hash_info(self):
self.function_eliminator_test_helper('test-function-eliminator-variable-clash-with-hash-info.js',
'test-function-eliminator-variable-clash-output.js',
use_hash_info=True)

def test_function_eliminator_replace_variable_value_with_hash_info(self):
self.function_eliminator_test_helper('test-function-eliminator-replace-variable-value-with-hash-info.js',
'test-function-eliminator-replace-variable-value-output.js',
use_hash_info=True)

def test_source_file_with_fixed_language_mode(self):
create_test_file('src_tmp_fixed_lang', '''
#include <string>
Expand Down Expand Up @@ -9035,7 +8910,7 @@ def test_minimal_runtime_code_size(self):
'-DNDEBUG',
'-ffast-math']

asmjs = ['-s', 'WASM=0', '--separate-asm', '-s', 'ELIMINATE_DUPLICATE_FUNCTIONS=1', '--memory-init-file', '1']
asmjs = ['-s', 'WASM=0', '--separate-asm', '-s', '--memory-init-file', '1']
wasm2js = ['-s', 'WASM=0', '--memory-init-file', '1']

hello_world_sources = [path_from_root('tests', 'small_hello_world.c'),
Expand Down
5 changes: 0 additions & 5 deletions tools/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,11 +986,6 @@ def eval_ctors(js_file, binary_file, binaryen_bin='', debug_info=False):
check_call(cmd)


def eliminate_duplicate_funcs(filename):
from . import duplicate_function_eliminator
duplicate_function_eliminator.eliminate_duplicate_funcs(filename)


def calculate_reachable_functions(infile, initial_list, can_reach=True):
with ToolchainProfiler.profile_block('calculate_reachable_functions'):
from . import asm_module
Expand Down
Loading

0 comments on commit 574f381

Please sign in to comment.