From c977ef7266b13a16d6abe26a38bd9098a02360ac Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 24 May 2017 13:10:53 -0700 Subject: [PATCH] Refactor optimization opts (#1023) * refactor optimization opts helper code to a class --- src/tools/asm2wasm.cpp | 22 ++-- src/tools/optimization-options.h | 175 ++++++++++++++++++++----------- src/tools/wasm-opt.cpp | 30 +----- 3 files changed, 129 insertions(+), 98 deletions(-) diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp index 24cff6f0916..cf0715198ad 100644 --- a/src/tools/asm2wasm.cpp +++ b/src/tools/asm2wasm.cpp @@ -25,6 +25,7 @@ #include "wasm-printing.h" #include "wasm-io.h" #include "wasm-validator.h" +#include "optimization-options.h" #include "asm2wasm.h" @@ -32,15 +33,13 @@ using namespace cashew; using namespace wasm; int main(int argc, const char *argv[]) { - PassOptions passOptions; bool legalizeJavaScriptFFI = true; - bool runOptimizationPasses = false; Asm2WasmBuilder::TrapMode trapMode = Asm2WasmBuilder::TrapMode::JS; bool wasmOnly = false; std::string symbolMap; bool emitBinary = true; - Options options("asm2wasm", "Translate asm.js files to .wast files"); + OptimizationOptions options("asm2wasm", "Translate asm.js files to .wast files"); options .add("--output", "-o", "Output file (stdout if not specified)", Options::Arguments::One, @@ -72,7 +71,6 @@ int main(int argc, const char *argv[]) { [](Options *o, const std::string &argument) { o->extra["table max"] = argument; }) - #include "optimization-options.h" .add("--no-opts", "-n", "Disable optimization passes (deprecated)", Options::Arguments::Zero, [](Options *o, const std::string &) { std::cerr << "--no-opts is deprecated (use -O0, etc.)\n"; @@ -103,7 +101,7 @@ int main(int argc, const char *argv[]) { }) .add("--debuginfo", "-g", "Emit names section and debug info (for debug info you must emit text, -S, for this to work)", Options::Arguments::Zero, - [&](Options *o, const std::string &arguments) { passOptions.debugInfo = true; }) + [&](Options *o, const std::string &arguments) { options.passOptions.debugInfo = true; }) .add("--symbolmap", "-s", "Emit a symbol map (indexes => names)", Options::Arguments::One, [&](Options *o, const std::string &argument) { symbolMap = argument; }) @@ -122,6 +120,12 @@ int main(int argc, const char *argv[]) { emitBinary = false; } + if (options.runningDefaultOptimizationPasses()) { + if (options.passes.size() > 1) { + Fatal() << "asm2wasm can only run default optimization passes (-O, -Ox, etc.), and not specific additional passes"; + } + } + const auto &tm_it = options.extra.find("total memory"); size_t totalMemory = tm_it == options.extra.end() ? 16 * 1024 * 1024 : atoi(tm_it->second.c_str()); @@ -133,7 +137,7 @@ int main(int argc, const char *argv[]) { Asm2WasmPreProcessor pre; // wasm binaries can contain a names section, but not full debug info - pre.debugInfo = passOptions.debugInfo && !emitBinary; + pre.debugInfo = options.passOptions.debugInfo && !emitBinary; auto input( read_file>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); char *start = pre.process(input.data()); @@ -145,7 +149,7 @@ int main(int argc, const char *argv[]) { if (options.debug) std::cerr << "wasming..." << std::endl; Module wasm; wasm.memory.initial = wasm.memory.max = totalMemory / Memory::kPageSize; - Asm2WasmBuilder asm2wasm(wasm, pre, options.debug, trapMode, passOptions, legalizeJavaScriptFFI, runOptimizationPasses, wasmOnly); + Asm2WasmBuilder asm2wasm(wasm, pre, options.debug, trapMode, options.passOptions, legalizeJavaScriptFFI, options.runningDefaultOptimizationPasses(), wasmOnly); asm2wasm.processAsm(asmjs); // import mem init file, if provided @@ -162,7 +166,7 @@ int main(int argc, const char *argv[]) { init = Builder(wasm).makeConst(Literal(int32_t(atoi(memBase->second.c_str())))); } wasm.memory.segments.emplace_back(init, data); - if (runOptimizationPasses) { + if (options.runningDefaultOptimizationPasses()) { PassRunner runner(&wasm); runner.add("memory-packing"); runner.run(); @@ -197,7 +201,7 @@ int main(int argc, const char *argv[]) { if (options.debug) std::cerr << "emitting..." << std::endl; ModuleWriter writer; writer.setDebug(options.debug); - writer.setDebugInfo(passOptions.debugInfo); + writer.setDebugInfo(options.passOptions.debugInfo); writer.setSymbolMap(symbolMap); writer.setBinary(emitBinary); writer.write(wasm, options.extra["output"]); diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 2af43072386..b094f96ce41 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -18,67 +18,116 @@ // Shared optimization options for commandline tools // - .add("", "-O", "execute default optimization passes", - Options::Arguments::Zero, - [&runOptimizationPasses, &passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 2; - passOptions.shrinkLevel = 1; - runOptimizationPasses = true; - }) - .add("", "-O0", "execute no optimization passes", - Options::Arguments::Zero, - [&passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 0; - passOptions.shrinkLevel = 0; - }) - .add("", "-O1", "execute -O1 optimization passes", - Options::Arguments::Zero, - [&runOptimizationPasses, &passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 1; - passOptions.shrinkLevel = 0; - runOptimizationPasses = true; - }) - .add("", "-O2", "execute -O2 optimization passes", - Options::Arguments::Zero, - [&runOptimizationPasses, &passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 2; - passOptions.shrinkLevel = 0; - runOptimizationPasses = true; - }) - .add("", "-O3", "execute -O3 optimization passes", - Options::Arguments::Zero, - [&runOptimizationPasses, &passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 3; - passOptions.shrinkLevel = 0; - runOptimizationPasses = true; - }) - .add("", "-Os", "execute default optimization passes, focusing on code size", - Options::Arguments::Zero, - [&runOptimizationPasses, &passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 2; - passOptions.shrinkLevel = 1; - runOptimizationPasses = true; - }) - .add("", "-Oz", "execute default optimization passes, super-focusing on code size", - Options::Arguments::Zero, - [&runOptimizationPasses, &passOptions](Options*, const std::string&) { - passOptions.optimizeLevel = 2; - passOptions.shrinkLevel = 2; - runOptimizationPasses = true; - }) - .add("--optimize-level", "-ol", "How much to focus on optimizing code", - Options::Arguments::One, - [&passOptions](Options* o, const std::string& argument) { - passOptions.optimizeLevel = atoi(argument.c_str()); - }) - .add("--shrink-level", "-s", "How much to focus on shrinking code size", - Options::Arguments::One, - [&passOptions](Options* o, const std::string& argument) { - passOptions.shrinkLevel = atoi(argument.c_str()); - }) - .add("--ignore-implicit-traps", "-iit", "Optimize under the helpful assumption that no surprising traps occur (from load, div/mod, etc.)", - Options::Arguments::Zero, - [&passOptions](Options*, const std::string&) { - passOptions.ignoreImplicitTraps = true; - }) +namespace wasm { + +struct OptimizationOptions : public Options { + static constexpr const char* DEFAULT_OPT_PASSES = "O"; + + std::vector passes; + PassOptions passOptions; + + OptimizationOptions(const std::string &command, const std::string &description) : Options(command, description) { + (*this).add("", "-O", "execute default optimization passes", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 2; + passOptions.shrinkLevel = 1; + passes.push_back(DEFAULT_OPT_PASSES); + }) + .add("", "-O0", "execute no optimization passes", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 0; + passOptions.shrinkLevel = 0; + }) + .add("", "-O1", "execute -O1 optimization passes", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 1; + passOptions.shrinkLevel = 0; + passes.push_back(DEFAULT_OPT_PASSES); + }) + .add("", "-O2", "execute -O2 optimization passes", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 2; + passOptions.shrinkLevel = 0; + passes.push_back(DEFAULT_OPT_PASSES); + }) + .add("", "-O3", "execute -O3 optimization passes", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 3; + passOptions.shrinkLevel = 0; + passes.push_back(DEFAULT_OPT_PASSES); + }) + .add("", "-Os", "execute default optimization passes, focusing on code size", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 2; + passOptions.shrinkLevel = 1; + passes.push_back(DEFAULT_OPT_PASSES); + }) + .add("", "-Oz", "execute default optimization passes, super-focusing on code size", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.optimizeLevel = 2; + passOptions.shrinkLevel = 2; + passes.push_back(DEFAULT_OPT_PASSES); + }) + .add("--optimize-level", "-ol", "How much to focus on optimizing code", + Options::Arguments::One, + [this](Options* o, const std::string& argument) { + passOptions.optimizeLevel = atoi(argument.c_str()); + }) + .add("--shrink-level", "-s", "How much to focus on shrinking code size", + Options::Arguments::One, + [this](Options* o, const std::string& argument) { + passOptions.shrinkLevel = atoi(argument.c_str()); + }) + .add("--ignore-implicit-traps", "-iit", "Optimize under the helpful assumption that no surprising traps occur (from load, div/mod, etc.)", + Options::Arguments::Zero, + [this](Options*, const std::string&) { + passOptions.ignoreImplicitTraps = true; + }); + // add passes in registry + for (const auto& p : PassRegistry::get()->getRegisteredNames()) { + (*this).add( + std::string("--") + p, "", PassRegistry::get()->getPassDescription(p), + Options::Arguments::Zero, + [this, p](Options*, const std::string&) { + passes.push_back(p); + } + ); + } + } + + bool runningDefaultOptimizationPasses() { + for (auto& pass : passes) { + if (pass == DEFAULT_OPT_PASSES) { + return true; + } + } + return false; + } + + bool runningPasses() { + return passes.size() > 0; + } + + PassRunner getPassRunner(Module& wasm) { + PassRunner passRunner(&wasm, passOptions); + if (debug) passRunner.setDebug(true); + for (auto& pass : passes) { + if (pass == DEFAULT_OPT_PASSES) { + passRunner.addDefaultOptimizationPasses(); + } else { + passRunner.add(pass); + } + } + return passRunner; + } +}; + +} // namespace wasm diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 468f3ce9323..0603ae93c1c 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -30,6 +30,7 @@ #include "wasm-io.h" #include "wasm-interpreter.h" #include "shell-interface.h" +#include "optimization-options.h" using namespace wasm; @@ -93,13 +94,11 @@ struct ExecutionResults { int main(int argc, const char* argv[]) { Name entry; std::vector passes; - bool runOptimizationPasses = false; - PassOptions passOptions; bool emitBinary = true; bool debugInfo = false; bool fuzzExec = false; - Options options("wasm-opt", "Optimize .wast files"); + OptimizationOptions options("wasm-opt", "Optimize .wast files"); options .add("--output", "-o", "Output file (stdout if not specified)", Options::Arguments::One, @@ -107,7 +106,6 @@ int main(int argc, const char* argv[]) { o->extra["output"] = argument; Colors::disable(); }) - #include "optimization-options.h" .add("--emit-text", "-S", "Emit text instead of binary for the output file", Options::Arguments::Zero, [&](Options *o, const std::string &argument) { emitBinary = false; }) @@ -121,20 +119,8 @@ int main(int argc, const char* argv[]) { [](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 (runOptimizationPasses) { - passes.resize(passes.size() + 1); - std::move_backward(passes.begin(), passes.begin() + passes.size() - 1, passes.end()); - passes[0] = "O"; - } - auto input(read_file(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); Module wasm; @@ -163,17 +149,9 @@ int main(int argc, const char* argv[]) { results.get(wasm); } - if (passes.size() > 0) { + if (options.runningPasses()) { if (options.debug) std::cerr << "running passes...\n"; - PassRunner passRunner(&wasm, passOptions); - if (options.debug) passRunner.setDebug(true); - for (auto& passName : passes) { - if (passName == "O") { - passRunner.addDefaultOptimizationPasses(); - } else { - passRunner.add(passName); - } - } + PassRunner passRunner = options.getPassRunner(wasm); passRunner.run(); assert(WasmValidator().validate(wasm)); }