summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h1
-rw-r--r--src/pass.h37
-rw-r--r--src/passes/RemoveUnusedBrs.cpp6
-rw-r--r--src/passes/pass.cpp8
-rw-r--r--src/tools/wasm-opt.cpp18
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") {