diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-10-18 10:50:54 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-18 10:50:54 -0700 |
commit | b9698cc7076390ae2bb937537850395ae7bad056 (patch) | |
tree | a7048c7c9b01e57b6c64d1b0e8a06ad103c674da /src | |
parent | c3d2775402d74a920577ed317930f3693305354f (diff) | |
download | binaryen-b9698cc7076390ae2bb937537850395ae7bad056.tar.gz binaryen-b9698cc7076390ae2bb937537850395ae7bad056.tar.bz2 binaryen-b9698cc7076390ae2bb937537850395ae7bad056.zip |
Pass options (#788)
* add PassOptions structure, and use it for new -Os param to wasm-opt
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 1 | ||||
-rw-r--r-- | src/pass.h | 37 | ||||
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 6 | ||||
-rw-r--r-- | src/passes/pass.cpp | 8 | ||||
-rw-r--r-- | src/tools/wasm-opt.cpp | 18 |
5 files changed, 59 insertions, 11 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 836b8044a..5df5af271 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -653,6 +653,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { if (body[i][0] == DEFUN) numFunctions++; } optimizingBuilder = make_unique<OptimizingIncrementalModuleBuilder>(&wasm, numFunctions, [&](PassRunner& passRunner) { + passRunner.options.setDefaultOptimizationOptions(); if (debug) { passRunner.setDebug(true); passRunner.setValidateGlobally(false); diff --git a/src/pass.h b/src/pass.h index 35065b0a3..334f46ac8 100644 --- a/src/pass.h +++ b/src/pass.h @@ -55,6 +55,20 @@ private: std::map<std::string, PassInfo> passInfos; }; +struct PassOptions { + bool debug = false; // run passes in debug mode, doing extra validation and timing checks + bool validateGlobally = false; // when validating validate globally and not just locally + int optimizeLevel = 0; // 0, 1, 2 correspond to -O0, -O1, -O2, etc. + int shrinkLevel = 0; // 0, 1, 2 correspond to -O0, -Os, -Oz + bool ignoreImplicitTraps = false; // optimize assuming things like div by 0, bad load/store, will not trap + + void setDefaultOptimizationOptions() { + optimizeLevel = 2; + shrinkLevel = 1; + ignoreImplicitTraps = true; + } +}; + // // Runs a set of passes, in order // @@ -62,17 +76,17 @@ struct PassRunner { Module* wasm; MixedArena* allocator; std::vector<Pass*> passes; - bool debug = false; - bool validateGlobally = false; + PassOptions options; PassRunner(Module* wasm) : wasm(wasm), allocator(&wasm->allocator) {} + PassRunner(Module* wasm, PassOptions options) : wasm(wasm), allocator(&wasm->allocator), options(options) {} void setDebug(bool debug_) { - debug = debug_; - validateGlobally = debug; // validate everything by default if debugging + options.debug = debug_; + options.validateGlobally = debug_; // validate everything by default if debugging } void setValidateGlobally(bool validate) { - validateGlobally = validate; + options.validateGlobally = validate; } void add(std::string passName) { @@ -173,15 +187,28 @@ protected: // template <typename WalkerType> class WalkerPass : public Pass, public WalkerType { + PassRunner *runner; + public: void run(PassRunner* runner, Module* module) override { + setPassRunner(runner); + WalkerType::setModule(module); WalkerType::walkModule(module); } void runFunction(PassRunner* runner, Module* module, Function* func) override { + setPassRunner(runner); WalkerType::setModule(module); WalkerType::walkFunction(func); } + + PassRunner* getPassRunner() { + return runner; + } + + void setPassRunner(PassRunner* runner_) { + runner = runner_; + } }; // Standard passes. All passes in /passes/ are runnable from the shell, diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index d1de0086a..328ca275b 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -423,8 +423,13 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R } } } + + bool selectify; + void visitIf(If* curr) { // we may have simplified ifs enough to turn them into selects + // this is helpful for code size, but can be a tradeoff with performance as we run both code paths + if (!selectify) return; if (curr->ifFalse && isConcreteWasmType(curr->ifTrue->type) && isConcreteWasmType(curr->ifFalse->type)) { // if with else, consider turning it into a select if there is no control flow // TODO: estimate cost @@ -448,6 +453,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R }; FinalOptimizer finalOptimizer; finalOptimizer.setModule(getModule()); + finalOptimizer.selectify = getPassRunner()->options.shrinkLevel > 0; finalOptimizer.walkFunction(func); } }; diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 284bb1642..3ae0819ea 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -124,7 +124,7 @@ void PassRunner::addDefaultGlobalOptimizationPasses() { } void PassRunner::run() { - if (debug) { + if (options.debug) { // for debug logging purposes, run each pass in full before running the other auto totalTime = std::chrono::duration<double>(0); size_t padding = 0; @@ -159,7 +159,7 @@ void PassRunner::run() { totalTime += diff; // validate, ignoring the time std::cerr << "[PassRunner] (validating)\n"; - if (!WasmValidator().validate(*wasm, false, validateGlobally)) { + if (!WasmValidator().validate(*wasm, false, options.validateGlobally)) { if (passDebug) { std::cerr << "Last pass (" << pass->name << ") broke validation. Here is the module before: \n" << moduleBefore.str() << "\n"; } else { @@ -171,7 +171,7 @@ void PassRunner::run() { std::cerr << "[PassRunner] passes took " << totalTime.count() << " seconds." << std::endl; // validate std::cerr << "[PassRunner] (final validation)\n"; - if (!WasmValidator().validate(*wasm, false, validateGlobally)) { + if (!WasmValidator().validate(*wasm, false, options.validateGlobally)) { std::cerr << "final module does not validate\n"; abort(); } @@ -222,7 +222,7 @@ void PassRunner::run() { } void PassRunner::runFunction(Function* func) { - if (debug) { + if (options.debug) { std::cerr << "[PassRunner] running passes on function " << func->name << std::endl; } for (auto* pass : passes) { diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index d6e7d3bd6..aad87726b 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -37,6 +37,7 @@ using namespace wasm; int main(int argc, const char* argv[]) { Name entry; std::vector<std::string> passes; + PassOptions passOptions; Options options("wasm-opt", "Optimize .wast files"); options @@ -48,9 +49,22 @@ int main(int argc, const char* argv[]) { }) .add("", "-O", "execute default optimization passes", Options::Arguments::Zero, - [&passes](Options*, const std::string&) { + [&passes, &passOptions](Options*, const std::string&) { + passOptions.setDefaultOptimizationOptions(); passes.push_back("O"); }) + .add("", "-Os", "execute default optimization passes, focusing on code size", + Options::Arguments::Zero, + [&passes, &passOptions](Options*, const std::string&) { + passOptions.setDefaultOptimizationOptions(); + passOptions.shrinkLevel = 1; + passes.push_back("O"); + }) + .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_positional("INFILE", Options::Arguments::One, [](Options* o, const std::string& argument) { o->extra["infile"] = argument; @@ -84,7 +98,7 @@ int main(int argc, const char* argv[]) { if (passes.size() > 0) { if (options.debug) std::cerr << "running passes...\n"; - PassRunner passRunner(&wasm); + PassRunner passRunner(&wasm, passOptions); if (options.debug) passRunner.setDebug(true); for (auto& passName : passes) { if (passName == "O") { |