diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-01-20 17:04:25 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2016-01-20 17:04:25 -0800 |
commit | 4e7c814b4d37cbb1bffcb205f19ab2167ce6815d (patch) | |
tree | 7a757dcd31456586f0853ef52f109cc6840f6f06 | |
parent | cda8084b61a1d9f67c4cdd201bad3e4138b942f2 (diff) | |
parent | ccea1fb53442cccaa80945dc8f7a97264af673a5 (diff) | |
download | binaryen-4e7c814b4d37cbb1bffcb205f19ab2167ce6815d.tar.gz binaryen-4e7c814b4d37cbb1bffcb205f19ab2167ce6815d.tar.bz2 binaryen-4e7c814b4d37cbb1bffcb205f19ab2167ce6815d.zip |
Merge pull request #129 from WebAssembly/binaryen-shell-command-lines
Use command-line & waterfall for binaryen-shell
-rw-r--r-- | README.md | 4 | ||||
-rwxr-xr-x | check.py | 46 | ||||
-rw-r--r-- | src/binaryen-shell.cpp | 144 | ||||
-rw-r--r-- | test/s2wasm_known_binaryen_shell_test_failures.txt | 71 | ||||
m--------- | test/waterfall | 0 |
5 files changed, 70 insertions, 195 deletions
@@ -55,13 +55,13 @@ bin/binaryen-shell [.wast file] [options] [passes, see --help] [--help] The binaryen shell receives a .wast file as input, and can run transformation passes on it, as well as print it (before and/or after the transformations). For example, try ```` -bin/binaryen-shell test/if_else.wast -print-before +bin/binaryen-shell test/if_else.wast --print-before ```` That will pretty-print out one of the testcases in the test suite. To run a transformation pass on it, try ```` -bin/binaryen-shell test/if_else.wast -print-before -print-after -lower-if-else +bin/binaryen-shell test/if_else.wast --print-before --print-after --lower-if-else ```` The `lower-if-else` pass lowers if-else into a block and a break. You can see the change the transformation causes by comparing the print before versus after. @@ -175,7 +175,7 @@ for asm in tests: # verify in wasm if interpreter: # remove imports, spec interpreter doesn't know what to do with them - subprocess.check_call([os.path.join('bin', 'binaryen-shell'), '-remove-imports', '-print-after', os.path.join('test', wasm)], stdout=open('ztemp.wast', 'w'), stderr=subprocess.PIPE) + subprocess.check_call([os.path.join('bin', 'binaryen-shell'), '--remove-imports', '--print-after', os.path.join('test', wasm)], stdout=open('ztemp.wast', 'w'), stderr=subprocess.PIPE) proc = subprocess.Popen([interpreter, 'ztemp.wast'], stderr=subprocess.PIPE) out, err = proc.communicate() if proc.returncode != 0: @@ -195,21 +195,14 @@ for asm in tests: raise Exception('wasm interpreter error: ' + err) # failed to pretty-print raise Exception('wasm interpreter error') -print '\n[ checking binaryen-shell... ]\n' - -actual, err = subprocess.Popen([os.path.join('bin', 'binaryen-shell'), '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() -fail_if_not_contained(actual, 'binaryen shell') -fail_if_not_contained(actual, 'options:') -fail_if_not_contained(actual, 'passes:') -fail_if_not_contained(actual, ' -lower-if-else') - print '\n[ checking binaryen-shell passes... ]\n' for t in sorted(os.listdir(os.path.join('test', 'passes'))): if t.endswith('.wast'): print '..', t passname = os.path.basename(t).replace('.wast', '') - cmd = [os.path.join('bin', 'binaryen-shell'), '-print-after', '-' + passname, os.path.join('test', 'passes', t)] + opt = '-O' if passname == 'O' else '--' + passname + cmd = [os.path.join('bin', 'binaryen-shell'), '--print-after', opt, os.path.join('test', 'passes', t)] print ' ', ' '.join(cmd) actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() fail_if_not_identical(actual, open(os.path.join('test', 'passes', passname + '.txt')).read()) @@ -220,7 +213,7 @@ for t in tests: if t.endswith('.wast') and not t.startswith('spec'): print '..', t t = os.path.join('test', t) - cmd = [os.path.join('bin', 'binaryen-shell'), t, '-print-before'] + cmd = [os.path.join('bin', 'binaryen-shell'), t, '--print-before'] print ' ', ' '.join(cmd) actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() assert err.replace('printing before:', '').strip() == '', 'bad err:' + err @@ -334,37 +327,30 @@ if torture: print '\n[ checking torture testcases... ]\n' + unexpected_result_count = 0 + import test.waterfall.src.link_assembly_files as link_assembly_files s2wasm_torture_out = os.path.abspath(os.path.join('test', 's2wasm-torture-out')) if os.path.isdir(s2wasm_torture_out): shutil.rmtree(s2wasm_torture_out) os.mkdir(s2wasm_torture_out) - unexpected_result_count = link_assembly_files.run( + unexpected_result_count += link_assembly_files.run( linker=os.path.abspath(os.path.join('bin', 's2wasm')), files=os.path.abspath(os.path.join('test', 'torture-s', '*.s')), fails=os.path.abspath(os.path.join('test', 's2wasm_known_gcc_test_failures.txt')), out=s2wasm_torture_out) assert os.path.isdir(s2wasm_torture_out), 'Expected output directory %s' % s2wasm_torture_out - # execute it TODO: parallelize, use waterfall - known_failures = set(open(os.path.join('test', 's2wasm_known_binaryen_shell_test_failures.txt')).read().split('\n')) - total = 0 - bad_failures = [] - for wast in sorted(os.listdir(s2wasm_torture_out)): - total += 1 - cmd = [os.path.join('bin', 'binaryen-shell'), os.path.join(s2wasm_torture_out, wast), '--entry=main'] - print ' '.join(cmd) - try: - subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except: - if wast not in known_failures: - bad_failures.append(wast) - if len(bad_failures) > 0: - print '\nbad failures:\n' - print '\n'.join(bad_failures) - raise Exception('bad failures :( %d out of %d' % (len(bad_failures), total)) + + import test.waterfall.src.execute_files as execute_files + unexpected_result_count += execute_files.run( + runner=os.path.abspath(os.path.join('bin', 'binaryen-shell')), + files=os.path.abspath(os.path.join(s2wasm_torture_out, '*.wast')), + fails=os.path.abspath(os.path.join('test', 's2wasm_known_binaryen_shell_test_failures.txt')), + out='') + shutil.rmtree(s2wasm_torture_out) if unexpected_result_count: - fail(unexpected_result_count, 0) + fail('%s failures' % unexpected_result_count, '0 failures') print '\n[ checking binary format testcases... ]\n' diff --git a/src/binaryen-shell.cpp b/src/binaryen-shell.cpp index b0965344c..96f76fa95 100644 --- a/src/binaryen-shell.cpp +++ b/src/binaryen-shell.cpp @@ -23,18 +23,16 @@ #include <setjmp.h> #include <memory> -#include "wasm-s-parser.h" +#include "pass.h" +#include "support/command-line.h" +#include "support/file.h" #include "wasm-interpreter.h" +#include "wasm-s-parser.h" #include "wasm-validator.h" -#include "pass.h" using namespace cashew; using namespace wasm; -namespace wasm { -int debug = 0; -} - // Globals MixedArena globalAllocator; @@ -262,106 +260,68 @@ static void run_asserts(size_t* i, bool* checked, AllocatingModule* wasm, // main // -int main(int argc, char **argv) { - debug = getenv("BINARYEN_DEBUG") ? getenv("BINARYEN_DEBUG")[0] - '0' : 0; - - char *infile = nullptr; +int main(int argc, const char* argv[]) { bool print_before = false; bool print_after = false; - std::vector<std::string> passes; Name entry; + std::vector<std::string> passes; - assert(argc > 0 && "expect at least program name as an argument"); - for (size_t i = 1, e = argc; i != e; i++) { - char* curr = argv[i]; - if (curr[0] == '-') { - std::string arg = curr; - if (arg == "-print-before") { - print_before = true; - } else if (arg == "-print-after") { - print_after = true; - } else if (arg == "--help") { - std::cout << "\n"; - std::cout << "binaryen shell\n"; - std::cout << "--------------\n\n"; - std::cout << "printing options:\n"; - std::cout << " -print-before : print modules before processing them\n"; - std::cout << " -print-after : print modules after processing them\n"; - std::cout << "\n"; - std::cout << "execution options:\n"; - std::cout << " --entry=[ENTRY] : call ENTRY() after parsing the module\n"; - std::cout << "\n"; - std::cout << "passes:\n"; - std::cout << " -O : execute default optimization passes\n"; - auto allPasses = PassRegistry::get()->getRegisteredNames(); - for (auto& name : allPasses) { - std::cout << " -" << name << " : " << PassRegistry::get()->getPassDescription(name) << "\n"; - } - std::cout << "\n"; - exit(0); - } else if (arg == "-O") { - passes.push_back("remove-unused-brs"); - passes.push_back("remove-unused-names"); - passes.push_back("merge-blocks"); - passes.push_back("simplify-locals"); - } else if (arg.substr(0, 7) == "--entry") { - entry = Name(strchr(curr, '=') + 1); - } else { - // otherwise, assumed to be a pass - const char* name = curr + 1; - auto check = PassRegistry::get()->createPass(name); - if (!check) { - printf("error: invalid option %s\n", curr); - exit(1); - } - delete check; - passes.push_back(name); - } - } else { - if (infile) { - printf("error: too many input files provided.\n"); - exit(1); - } - infile = curr; - } + static const char* default_passes[] = {"remove-unused-brs", + "remove-unused-names", "merge-blocks", + "simplify-locals"}; + + Options options("binaryen-shell", "Execute .wast files"); + options + .add("--output", "-o", "Output file (stdout if not specified)", + Options::Arguments::One, + [](Options* o, const std::string& argument) { + o->extra["output"] = argument; + Colors::disable(); + }) + .add( + "--entry", "-e", "call the entry point after parsing the module", + Options::Arguments::One, + [&entry](Options*, const std::string& argument) { entry = argument; }) + .add("", "-O", "execute default optimization passes", + Options::Arguments::Zero, + [&passes](Options*, const std::string&) { + for (const auto* p : default_passes) passes.push_back(p); + }) + .add("--print-before", "", "Print modules before processing them", + Options::Arguments::Zero, + [&print_before](Options*, const std::string&) { + print_before = true; + }) + .add("--print-after", "", "Print modules after processing them", + Options::Arguments::Zero, + [&print_after](Options*, const std::string&) { print_after = true; }) + .add_positional("INFILE", Options::Arguments::One, + [](Options* o, const std::string& argument) { + o->extra["infile"] = argument; + }); + for (const auto& p : PassRegistry::get()->getRegisteredNames()) { + options.add( + std::string("--") + p, "", PassRegistry::get()->getPassDescription(p), + Options::Arguments::Zero, + [&passes, p](Options*, const std::string&) { passes.push_back(p); }); } + options.parse(argc, argv); - if (!infile) { - printf("error: no input file provided.\n"); - exit(1); - } + auto input(read_file<std::vector<char>>(options.extra["infile"], options.debug)); - if (debug) std::cerr << "loading '" << infile << "'...\n"; - FILE *f = fopen(infile, "r"); - if (!f) { - printf("error: could not open input file: %s\n", infile); - exit(1); - } - fseek(f, 0, SEEK_END); - int size = ftell(f); - char *input = new char[size+1]; - rewind(f); - int num = fread(input, 1, size, f); - // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when - // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one), - // so return value of fread can be less than size reported by ftell, and that is normal. - assert((num > 0 || size == 0) && num <= size); - fclose(f); - input[num] = 0; - - if (debug) std::cerr << "parsing text to s-expressions...\n"; - SExpressionParser parser(input); + if (options.debug) std::cerr << "parsing text to s-expressions...\n"; + SExpressionParser parser(input.data()); Element& root = *parser.root; - if (debug) std::cout << root << '\n'; + if (options.debug) std::cout << root << '\n'; // A .wast may have multiple modules, with some asserts after them bool checked = false; size_t i = 0; while (i < root.size()) { - if (debug) std::cerr << "parsing s-expressions to wasm...\n"; + if (options.debug) std::cerr << "parsing s-expressions to wasm...\n"; AllocatingModule wasm; std::unique_ptr<SExpressionWasmBuilder> builder( - new SExpressionWasmBuilder(wasm, *root[i], [&]() { abort(); }, debug)); + new SExpressionWasmBuilder(wasm, *root[i], [&]() { abort(); }, options.debug)); i++; if (print_before) { @@ -374,7 +334,7 @@ int main(int argc, char **argv) { MixedArena moreModuleAllocations; if (passes.size() > 0) { - if (debug) std::cerr << "running passes...\n"; + if (options.debug) std::cerr << "running passes...\n"; PassRunner passRunner(&moreModuleAllocations); for (auto& passName : passes) { passRunner.add(passName); diff --git a/test/s2wasm_known_binaryen_shell_test_failures.txt b/test/s2wasm_known_binaryen_shell_test_failures.txt index 54739a8f4..abc1aff2b 100644 --- a/test/s2wasm_known_binaryen_shell_test_failures.txt +++ b/test/s2wasm_known_binaryen_shell_test_failures.txt @@ -72,7 +72,6 @@ 920501-9.c.s.wast 920612-1.c.s.wast 920711-1.c.s.wast -920909-1.c.s.wast 930513-1.c.s.wast 930930-2.c.s.wast 931110-1.c.s.wast @@ -89,7 +88,6 @@ 981206-1.c.s.wast 990106-2.c.s.wast 990222-1.c.s.wast -990404-1.c.s.wast 990513-1.c.s.wast 990628-1.c.s.wast 991112-1.c.s.wast @@ -104,7 +102,6 @@ builtin-constant.c.s.wast builtin-prefetch-2.c.s.wast const-addr-expr-1.c.s.wast eeprof-1.c.s.wast -index-1.c.s.wast ipa-sra-1.c.s.wast ipa-sra-2.c.s.wast loop-2f.c.s.wast @@ -197,13 +194,11 @@ pr58365.c.s.wast pr58419.c.s.wast pr59229.c.s.wast pr59358.c.s.wast -pr60017.c.s.wast pr60960.c.s.wast pr61375.c.s.wast pr63659.c.s.wast printf-1.c.s.wast regstack-1.c.s.wast -simd-1.c.s.wast simd-2.c.s.wast simd-5.c.s.wast strcmp-1.c.s.wast @@ -215,7 +210,6 @@ strlen-1.c.s.wast strncmp-1.c.s.wast struct-aliasing-1.c.s.wast struct-cpy-1.c.s.wast -struct-ini-1.c.s.wast switch-1.c.s.wast vrp-1.c.s.wast vrp-2.c.s.wast @@ -223,68 +217,3 @@ vrp-3.c.s.wast vrp-5.c.s.wast vrp-6.c.s.wast zerolen-1.c.s.wast -pr57144.c.s.wast -pr57281.c.s.wast -pr57321.c.s.wast -pr57344-1.c.s.wast -pr57344-2.c.s.wast -pr57829.c.s.wast -pr57861.c.s.wast -pr57875.c.s.wast -pr58209.c.s.wast -pr58277-2.c.s.wast -pr58364.c.s.wast -pr58385.c.s.wast -pr58387.c.s.wast -pr58431.c.s.wast -pr58564.c.s.wast -pr58570.c.s.wast -pr58574.c.s.wast -pr58640-2.c.s.wast -pr58662.c.s.wast -pr58726.c.s.wast -pr58831.c.s.wast -pr58943.c.s.wast -pr58984.c.s.wast -pr59014-2.c.s.wast -pr59014.c.s.wast -pr59101.c.s.wast -pr59221.c.s.wast -pr59387.c.s.wast -pr59388.c.s.wast -pr59413.c.s.wast -pr59747.c.s.wast -pr60062.c.s.wast -pr60072.c.s.wast -pr60454.c.s.wast -pr61306-1.c.s.wast -pr61306-2.c.s.wast -pr61306-3.c.s.wast -pr61725.c.s.wast -pr63302.c.s.wast -pr7284-1.c.s.wast -ptr-arith-1.c.s.wast -pure-1.c.s.wast -pushpop_macro.c.s.wast -restrict-1.c.s.wast -scope-1.c.s.wast -shiftdi.c.s.wast -shiftopt-1.c.s.wast -simd-4.c.s.wast -strct-pack-1.c.s.wast -strct-pack-2.c.s.wast -strct-pack-3.c.s.wast -struct-ini-2.c.s.wast -struct-ini-3.c.s.wast -struct-ini-4.c.s.wast -struct-ret-2.c.s.wast -tstdi-1.c.s.wast -unroll-1.c.s.wast -usmul.c.s.wast -vrp-7.c.s.wast -wchar_t-1.c.s.wast -widechar-1.c.s.wast -widechar-2.c.s.wast -zero-struct-1.c.s.wast -zero-struct-2.c.s.wast -zerolen-2.c.s.wast diff --git a/test/waterfall b/test/waterfall -Subproject 3bb7ac46970b9d16dc8bfb62318483b21061d70 +Subproject b2c744bf233f92b34c237757aa0373abe44f936 |