Skip to content

Commit 0571fe3

Browse files
authored
wasm-metadce tool (#1320)
This adds a new tool for better dead code elimination. The problem this helps overcome is when the wasm module is part of something larger, like a wasm+JS combination, and therefore doing DCE in either one is not sufficient as it can't remove a cycle spanning the wasm and JS worlds. Concretely, when binaryen performs DCE by itself, it can never remove an export, because it considers those roots - but in the larger ("meta") space outside, they may actually be removable. To solve that, this tool receives a description of the outside graph (in very abstract form), including which nodes are roots. It then adds to that graph nodes from the wasm, so that we have a single graph representing the entire space (the outside + wasm + connections between them). It then performs DCE, finding what is not reachable from the roots, and cleaning it up from the wasm. It of course can't clean up things from the outside, since all it has is the abstract representation of those things in the graph, but it prints out the ids of the removable nodes, which an outside tool can use. This tool is written in as general a way as possible, hopefully it can have multiple uses. The use I have in mind is to write something in emscripten that uses this to DCE the JS+wasm combination that we emit.
1 parent b7f0a89 commit 0571fe3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1506
-4
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,16 @@ SET_PROPERTY(TARGET wasm-merge PROPERTY CXX_STANDARD 11)
232232
SET_PROPERTY(TARGET wasm-merge PROPERTY CXX_STANDARD_REQUIRED ON)
233233
INSTALL(TARGETS wasm-merge DESTINATION bin)
234234

235+
SET(wasm-metadce_SOURCES
236+
src/tools/wasm-metadce.cpp
237+
)
238+
ADD_EXECUTABLE(wasm-metadce
239+
${wasm-metadce_SOURCES})
240+
TARGET_LINK_LIBRARIES(wasm-metadce wasm asmjs emscripten-optimizer passes ir cfg support wasm)
241+
SET_PROPERTY(TARGET wasm-metadce PROPERTY CXX_STANDARD 11)
242+
SET_PROPERTY(TARGET wasm-metadce PROPERTY CXX_STANDARD_REQUIRED ON)
243+
INSTALL(TARGETS wasm-metadce DESTINATION bin)
244+
235245
SET(asm2wasm_SOURCES
236246
src/tools/asm2wasm.cpp
237247
src/wasm-emscripten.cpp

auto_update_tests.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
from scripts.test.support import run_command, split_wast
66
from scripts.test.shared import (
77
ASM2WASM, MOZJS, S2WASM, WASM_SHELL, WASM_OPT, WASM_AS, WASM_DIS,
8-
WASM_CTOR_EVAL, WASM_MERGE, WASM_REDUCE, WASM2ASM,
8+
WASM_CTOR_EVAL, WASM_MERGE, WASM_REDUCE, WASM2ASM, WASM_METADCE,
99
BINARYEN_INSTALL_DIR, has_shell_timeout)
1010
from scripts.test.wasm2asm import tests, spec_tests, extra_tests, assert_tests
1111

12-
1312
print '[ processing and updating testcases... ]\n'
1413

1514
for asm in sorted(os.listdir('test')):
@@ -293,6 +292,20 @@
293292
out = run_command(cmd)
294293
with open(traps_expected_file, 'w') as o: o.write(out)
295294

295+
print '\n[ checking wasm-metadce... ]\n'
296+
297+
for t in os.listdir(os.path.join('test', 'metadce')):
298+
if t.endswith(('.wast', '.wasm')):
299+
print '..', t
300+
t = os.path.join('test', 'metadce', t)
301+
graph = t + '.graph.txt'
302+
cmd = WASM_METADCE + [t, '--graph-file=' + graph, '-o', 'a.wast', '-S']
303+
stdout = run_command(cmd)
304+
actual = open('a.wast').read()
305+
out = t + '.dced'
306+
with open(out, 'w') as o: o.write(actual)
307+
with open(out + '.stdout', 'w') as o: o.write(stdout)
308+
296309
if has_shell_timeout():
297310
print '\n[ checking wasm-reduce ]\n'
298311

check.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from scripts.test.support import run_command, split_wast
2424
from scripts.test.shared import (
2525
BIN_DIR, EMCC, MOZJS, NATIVECC, NATIVEXX, NODEJS, S2WASM_EXE,
26-
WASM_AS, WASM_CTOR_EVAL, WASM_OPT, WASM_SHELL, WASM_MERGE, WASM_SHELL_EXE,
26+
WASM_AS, WASM_CTOR_EVAL, WASM_OPT, WASM_SHELL, WASM_MERGE, WASM_SHELL_EXE, WASM_METADCE,
2727
WASM_DIS, WASM_REDUCE, binary_format_check, delete_from_orbit, fail, fail_with_error,
2828
fail_if_not_identical, fail_if_not_contained, has_vanilla_emcc,
2929
has_vanilla_llvm, minify_check, num_failures, options, tests,
@@ -209,6 +209,23 @@ def run_ctor_eval_tests():
209209
with open(out) as f:
210210
fail_if_not_identical(f.read(), actual)
211211

212+
def run_wasm_metadce_tests():
213+
print '\n[ checking wasm-metadce ]\n'
214+
215+
for t in os.listdir(os.path.join('test', 'metadce')):
216+
if t.endswith(('.wast', '.wasm')):
217+
print '..', t
218+
t = os.path.join('test', 'metadce', t)
219+
graph = t + '.graph.txt'
220+
cmd = WASM_METADCE + [t, '--graph-file=' + graph, '-o', 'a.wast', '-S']
221+
stdout = run_command(cmd)
222+
expected = t + '.dced'
223+
with open('a.wast') as seen:
224+
with open(expected) as correct:
225+
fail_if_not_identical(seen.read(), correct.read())
226+
with open(expected + '.stdout') as correct:
227+
fail_if_not_identical(stdout, correct.read())
228+
212229
def run_wasm_reduce_tests():
213230
print '\n[ checking wasm-reduce ]\n'
214231

@@ -560,6 +577,7 @@ def main():
560577
run_wasm_dis_tests()
561578
run_wasm_merge_tests()
562579
run_ctor_eval_tests()
580+
run_wasm_metadce_tests()
563581
if has_shell_timeout():
564582
run_wasm_reduce_tests()
565583

scripts/test/shared.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def is_exe(fpath):
168168
WASM_MERGE = [os.path.join(options.binaryen_bin, 'wasm-merge')]
169169
S2WASM = [os.path.join(options.binaryen_bin, 's2wasm')]
170170
WASM_REDUCE = [os.path.join(options.binaryen_bin, 'wasm-reduce')]
171+
WASM_METADCE = [os.path.join(options.binaryen_bin, 'wasm-metadce')]
171172

172173
S2WASM_EXE = S2WASM[0]
173174
WASM_SHELL_EXE = WASM_SHELL[0]

src/support/command-line.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ void printWrap(std::ostream& os, int leftPad, const std::string& content) {
2828
std::string nextWord;
2929
std::string pad(leftPad, ' ');
3030
for (int i = 0; i <= len; ++i) {
31-
if (i != len && content[i] != ' ') {
31+
if (i != len && content[i] != ' ' && content[i] != '\n') {
3232
nextWord += content[i];
3333
} else {
3434
if (static_cast<int>(nextWord.size()) > space) {
@@ -39,6 +39,10 @@ void printWrap(std::ostream& os, int leftPad, const std::string& content) {
3939
space -= nextWord.size() + 1;
4040
if (space > 0) os << ' ';
4141
nextWord.clear();
42+
if (content[i] == '\n') {
43+
os << '\n';
44+
space = SCREEN_WIDTH - leftPad;
45+
}
4246
}
4347
}
4448
}

0 commit comments

Comments
 (0)