Skip to content

Commit

Permalink
Refactor optimization opts (#1023)
Browse files Browse the repository at this point in the history
* refactor optimization opts helper code to a class
  • Loading branch information
kripken authored May 24, 2017
1 parent dd621a6 commit c977ef7
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 98 deletions.
22 changes: 13 additions & 9 deletions src/tools/asm2wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,21 @@
#include "wasm-printing.h"
#include "wasm-io.h"
#include "wasm-validator.h"
#include "optimization-options.h"

#include "asm2wasm.h"

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,
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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; })
Expand All @@ -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());
Expand All @@ -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<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
char *start = pre.process(input.data());
Expand All @@ -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
Expand All @@ -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();
Expand Down Expand Up @@ -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"]);
Expand Down
175 changes: 112 additions & 63 deletions src/tools/optimization-options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> 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

30 changes: 4 additions & 26 deletions src/tools/wasm-opt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "wasm-io.h"
#include "wasm-interpreter.h"
#include "shell-interface.h"
#include "optimization-options.h"

using namespace wasm;

Expand Down Expand Up @@ -93,21 +94,18 @@ struct ExecutionResults {
int main(int argc, const char* argv[]) {
Name entry;
std::vector<std::string> 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,
[](Options* o, const std::string& argument) {
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; })
Expand All @@ -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<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));

Module wasm;
Expand Down Expand Up @@ -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));
}
Expand Down

0 comments on commit c977ef7

Please sign in to comment.