summaryrefslogtreecommitdiff
path: root/src/passes/RemoveUnusedModuleElements.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-01-10 11:34:53 -0800
committerGitHub <noreply@github.com>2018-01-10 11:34:53 -0800
commit623e42aa7be8aa030093b204491d94f3c297d312 (patch)
tree05158ff7c3ef2856345c1650192283ed737f91fd /src/passes/RemoveUnusedModuleElements.cpp
parent8f90b655201e4cd77196a0b90ea4f398ecfe2c56 (diff)
downloadbinaryen-623e42aa7be8aa030093b204491d94f3c297d312.tar.gz
binaryen-623e42aa7be8aa030093b204491d94f3c297d312.tar.bz2
binaryen-623e42aa7be8aa030093b204491d94f3c297d312.zip
Optimize out memory and table when possible (#1352)
We can remove the memory/table (itself, or an import if imported) if they are not used. This is pretty minor on a large wasm file, but when reading small wasts it's very noticeable to have an unused memory and table all the time.
Diffstat (limited to 'src/passes/RemoveUnusedModuleElements.cpp')
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 8bf2f9c9a..13caaccc9 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -43,6 +43,8 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
Module* module;
std::vector<ModuleElement> queue;
std::set<ModuleElement> reachable;
+ bool usesMemory = false;
+ bool usesTable = false;
ReachabilityAnalyzer(Module* module, const std::vector<ModuleElement>& roots) : module(module) {
queue = roots;
@@ -86,6 +88,9 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
queue.emplace_back(ModuleElementKind::Function, curr->target);
}
}
+ void visitCallIndirect(CallIndirect* curr) {
+ usesTable = true;
+ }
void visitGetGlobal(GetGlobal* curr) {
if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) == 0) {
@@ -97,6 +102,30 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
queue.emplace_back(ModuleElementKind::Global, curr->name);
}
}
+
+ void visitLoad(Load* curr) {
+ usesMemory = true;
+ }
+ void visitStore(Store* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicRMW(AtomicRMW* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicWait(AtomicWait* curr) {
+ usesMemory = true;
+ }
+ void visitAtomicWake(AtomicWake* curr) {
+ usesMemory = true;
+ }
+ void visitHost(Host* curr) {
+ if (curr->op == CurrentMemory || curr->op == GrowMemory) {
+ usesMemory = true;
+ }
+ }
};
// Finds function type usage
@@ -136,11 +165,17 @@ struct RemoveUnusedModuleElements : public Pass {
roots.emplace_back(ModuleElementKind::Function, module->start);
}
// Exports are roots.
+ bool exportsMemory = false;
+ bool exportsTable = false;
for (auto& curr : module->exports) {
if (curr->kind == ExternalKind::Function) {
roots.emplace_back(ModuleElementKind::Function, curr->value);
} else if (curr->kind == ExternalKind::Global) {
roots.emplace_back(ModuleElementKind::Global, curr->value);
+ } else if (curr->kind == ExternalKind::Memory) {
+ exportsMemory = true;
+ } else if (curr->kind == ExternalKind::Table) {
+ exportsTable = true;
}
}
// For now, all functions that can be called indirectly are marked as roots.
@@ -176,6 +211,28 @@ struct RemoveUnusedModuleElements : public Pass {
}), v.end());
}
module->updateMaps();
+ // Handle the memory and table
+ if (!exportsMemory && !analyzer.usesMemory && module->memory.segments.empty()) {
+ module->memory.exists = false;
+ module->memory.imported = false;
+ module->memory.initial = 0;
+ module->memory.max = 0;
+ removeImport(ExternalKind::Memory, module);
+ }
+ if (!exportsTable && !analyzer.usesTable && module->table.segments.empty()) {
+ module->table.exists = false;
+ module->table.imported = false;
+ module->table.initial = 0;
+ module->table.max = 0;
+ removeImport(ExternalKind::Table, module);
+ }
+ }
+
+ void removeImport(ExternalKind kind, Module* module) {
+ auto& v = module->imports;
+ v.erase(std::remove_if(v.begin(), v.end(), [&](const std::unique_ptr<Import>& curr) {
+ return curr->kind == kind;
+ }), v.end());
}
void optimizeFunctionTypes(Module* module) {