summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rwxr-xr-xcheck.py46
-rw-r--r--src/binaryen-shell.cpp144
-rw-r--r--test/s2wasm_known_binaryen_shell_test_failures.txt71
m---------test/waterfall0
5 files changed, 70 insertions, 195 deletions
diff --git a/README.md b/README.md
index 2b17e54de..e26ac846c 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/check.py b/check.py
index 72f9bd46c..fe68e124b 100755
--- a/check.py
+++ b/check.py
@@ -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