summaryrefslogtreecommitdiff
path: root/src/passes
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes')
-rw-r--r--src/passes/DeadArgumentElimination.cpp8
-rw-r--r--src/passes/Directize.cpp2
-rw-r--r--src/passes/FuncCastEmulation.cpp20
-rw-r--r--src/passes/GenerateDynCalls.cpp16
-rw-r--r--src/passes/Inlining.cpp8
-rw-r--r--src/passes/LegalizeJSInterface.cpp10
-rw-r--r--src/passes/Metrics.cpp8
-rw-r--r--src/passes/PostEmscripten.cpp2
-rw-r--r--src/passes/Print.cpp62
-rw-r--r--src/passes/PrintCallGraph.cpp10
-rw-r--r--src/passes/RemoveImports.cpp8
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp67
-rw-r--r--src/passes/ReorderFunctions.cpp8
-rw-r--r--src/passes/opt-utils.h9
14 files changed, 138 insertions, 100 deletions
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp
index 1a404dbcf..6223c841d 100644
--- a/src/passes/DeadArgumentElimination.cpp
+++ b/src/passes/DeadArgumentElimination.cpp
@@ -284,11 +284,9 @@ struct DAE : public Pass {
infoMap[curr->value].hasUnseenCalls = true;
}
}
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- for (auto name : segment.data) {
- infoMap[name].hasUnseenCalls = true;
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto name : segment->data) {
+ infoMap[name].hasUnseenCalls = true;
}
}
// Scan all the functions.
diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp
index 6ee976b39..3a7ef1024 100644
--- a/src/passes/Directize.cpp
+++ b/src/passes/Directize.cpp
@@ -124,7 +124,7 @@ struct Directize : public Pass {
}
if (canOptimizeCallIndirect) {
- TableUtils::FlatTable flatTable(*table);
+ TableUtils::FlatTable flatTable(*module, *table);
if (flatTable.valid) {
validTables.emplace(table->name, flatTable);
}
diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp
index b91d7ba4f..753c986b8 100644
--- a/src/passes/FuncCastEmulation.cpp
+++ b/src/passes/FuncCastEmulation.cpp
@@ -173,17 +173,15 @@ struct FuncCastEmulation : public Pass {
Signature ABIType(Type(std::vector<Type>(numParams, Type::i64)), Type::i64);
// Add a thunk for each function in the table, and do the call through it.
std::unordered_map<Name, Name> funcThunks;
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- for (auto& name : segment.data) {
- auto iter = funcThunks.find(name);
- if (iter == funcThunks.end()) {
- auto thunk = makeThunk(name, module, numParams);
- funcThunks[name] = thunk;
- name = thunk;
- } else {
- name = iter->second;
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto& name : segment->data) {
+ auto iter = funcThunks.find(name);
+ if (iter == funcThunks.end()) {
+ auto thunk = makeThunk(name, module, numParams);
+ funcThunks[name] = thunk;
+ name = thunk;
+ } else {
+ name = iter->second;
}
}
}
diff --git a/src/passes/GenerateDynCalls.cpp b/src/passes/GenerateDynCalls.cpp
index 827dccea0..dad992fea 100644
--- a/src/passes/GenerateDynCalls.cpp
+++ b/src/passes/GenerateDynCalls.cpp
@@ -45,10 +45,20 @@ struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> {
void visitTable(Table* table) {
// Generate dynCalls for functions in the table
- if (table->segments.size() > 0) {
+ Module* wasm = getModule();
+ auto& segments = wasm->elementSegments;
+
+ // Find a single elem segment for the table. We only care about one, since
+ // wasm-ld emits only one table with a single segment.
+ auto it = std::find_if(segments.begin(),
+ segments.end(),
+ [&](std::unique_ptr<ElementSegment>& segment) {
+ return segment->table == table->name;
+ });
+ if (it != segments.end()) {
std::vector<Name> tableSegmentData;
- for (const auto& indirectFunc : table->segments[0].data) {
- generateDynCallThunk(getModule()->getFunction(indirectFunc)->sig);
+ for (const auto& indirectFunc : it->get()->data) {
+ generateDynCallThunk(wasm->getFunction(indirectFunc)->sig);
}
}
}
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index 727e94d72..41481b310 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -348,11 +348,9 @@ struct Inlining : public Pass {
infos[ex->value].usedGlobally = true;
}
}
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- for (auto name : segment.data) {
- infos[name].usedGlobally = true;
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto name : segment->data) {
+ infos[name].usedGlobally = true;
}
}
diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp
index e8a604326..0a991caa5 100644
--- a/src/passes/LegalizeJSInterface.cpp
+++ b/src/passes/LegalizeJSInterface.cpp
@@ -97,12 +97,10 @@ struct LegalizeJSInterface : public Pass {
// we need to use the legalized version in the tables, as the import
// from JS is legal for JS. Our stub makes it look like a native wasm
// function.
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- for (auto& name : segment.data) {
- if (name == im->name) {
- name = funcName;
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto& name : segment->data) {
+ if (name == im->name) {
+ name = funcName;
}
}
}
diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp
index 09dcc5445..231ad928c 100644
--- a/src/passes/Metrics.cpp
+++ b/src/passes/Metrics.cpp
@@ -74,11 +74,13 @@ struct Metrics
}
Index size = 0;
+ ModuleUtils::iterActiveElementSegments(
+ *module, [&](ElementSegment* segment) { size += segment->data.size(); });
for (auto& table : module->tables) {
walkTable(table.get());
- for (auto& segment : table->segments) {
- size += segment.data.size();
- }
+ }
+ for (auto& segment : module->elementSegments) {
+ walkElementSegment(segment.get());
}
if (!module->tables.empty()) {
counts["[table-data]"] = size;
diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp
index 35e2b9a8b..403fb998b 100644
--- a/src/passes/PostEmscripten.cpp
+++ b/src/passes/PostEmscripten.cpp
@@ -67,7 +67,7 @@ struct PostEmscripten : public Pass {
// Next, see if the Table is flat, which we need in order to see where
// invokes go statically. (In dynamic linking, the table is not flat,
// and we can't do this.)
- TableUtils::FlatTable flatTable(*module->tables[0]);
+ TableUtils::FlatTable flatTable(*module, *module->tables[0]);
if (!flatTable.valid) {
return;
}
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 993eddb99..05a639158 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2665,36 +2665,57 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
printTableHeader(curr);
o << maybeNewLine;
}
- for (auto& segment : curr->segments) {
- // Don't print empty segments
- if (segment.data.empty()) {
- continue;
- }
- doIndent(o, indent);
- o << '(';
- printMedium(o, "elem ");
+ ModuleUtils::iterTableSegments(
+ *currModule, curr->name, [&](ElementSegment* segment) {
+ printElementSegment(segment);
+ });
+ }
+ void visitElementSegment(ElementSegment* curr) {
+ if (curr->table.is()) {
+ return;
+ }
+ printElementSegment(curr);
+ }
+ void printElementSegment(ElementSegment* curr) {
+ // Don't print empty segments
+ if (curr->data.empty()) {
+ return;
+ }
+ doIndent(o, indent);
+ o << '(';
+ printMedium(o, "elem");
+ if (curr->hasExplicitName) {
+ o << ' ';
+ printName(curr->name, o);
+ }
+
+ if (curr->table.is()) {
// TODO(reference-types): check for old-style based on the complete spec
if (currModule->tables.size() > 1) {
// tableuse
- o << '(';
- printMedium(o, "table ");
- printName(curr->name, o);
- o << ") ";
+ o << " (table ";
+ printName(curr->table, o);
+ o << ")";
}
- visit(segment.offset);
+ o << ' ';
+ visit(curr->offset);
if (currModule->tables.size() > 1) {
- o << " func";
- }
-
- for (auto name : segment.data) {
o << ' ';
- printName(name, o);
+ TypeNamePrinter(o, currModule).print(HeapType::func);
}
- o << ')' << maybeNewLine;
+ } else {
+ o << ' ';
+ TypeNamePrinter(o, currModule).print(HeapType::func);
}
+
+ for (auto name : curr->data) {
+ o << ' ';
+ printName(name, o);
+ }
+ o << ')' << maybeNewLine;
}
void printMemoryHeader(Memory* curr) {
o << '(';
@@ -2833,6 +2854,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
*curr, [&](Memory* memory) { visitMemory(memory); });
ModuleUtils::iterDefinedTables(*curr,
[&](Table* table) { visitTable(table); });
+ for (auto& segment : curr->elementSegments) {
+ visitElementSegment(segment.get());
+ }
auto elemDeclareNames = TableUtils::getFunctionsNeedingElemDeclare(*curr);
if (!elemDeclareNames.empty()) {
doIndent(o, indent);
diff --git a/src/passes/PrintCallGraph.cpp b/src/passes/PrintCallGraph.cpp
index 49e056312..d70e0d7f2 100644
--- a/src/passes/PrintCallGraph.cpp
+++ b/src/passes/PrintCallGraph.cpp
@@ -96,12 +96,10 @@ struct PrintCallGraph : public Pass {
CallPrinter printer(module);
// Indirect Targets
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- for (auto& curr : segment.data) {
- auto* func = module->getFunction(curr);
- o << " \"" << func->name << "\" [style=\"filled, rounded\"];\n";
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto& curr : segment->data) {
+ auto* func = module->getFunction(curr);
+ o << " \"" << func->name << "\" [style=\"filled, rounded\"];\n";
}
}
diff --git a/src/passes/RemoveImports.cpp b/src/passes/RemoveImports.cpp
index 10a885586..be41717f4 100644
--- a/src/passes/RemoveImports.cpp
+++ b/src/passes/RemoveImports.cpp
@@ -49,11 +49,9 @@ struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
*curr, [&](Function* func) { names.push_back(func->name); });
// Do not remove names referenced in a table
std::set<Name> indirectNames;
- for (auto& table : curr->tables) {
- for (auto& segment : table->segments) {
- for (auto& name : segment.data) {
- indirectNames.insert(name);
- }
+ for (auto& segment : curr->elementSegments) {
+ for (auto& name : segment->data) {
+ indirectNames.insert(name);
}
}
for (auto& name : names) {
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index d12fdb487..fa295dac5 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -29,7 +29,7 @@
namespace wasm {
-enum class ModuleElementKind { Function, Global, Event, Table };
+enum class ModuleElementKind { Function, Global, Event, Table, ElementSegment };
typedef std::pair<ModuleElementKind, Name> ModuleElement;
@@ -51,9 +51,9 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
walk(segment.offset);
}
}
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- walk(segment.offset);
+ for (auto& segment : module->elementSegments) {
+ if (segment->table.is()) {
+ walk(segment->offset);
}
}
@@ -76,10 +76,10 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
walk(global->init);
}
} else if (curr.first == ModuleElementKind::Table) {
- auto* table = module->getTable(curr.second);
- for (auto& segment : table->segments) {
- walk(segment.offset);
- }
+ ModuleUtils::iterTableSegments(
+ *module, curr.second, [&](ElementSegment* segment) {
+ walk(segment->offset);
+ });
}
}
}
@@ -96,8 +96,12 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
}
void visitCallIndirect(CallIndirect* curr) {
assert(!module->tables.empty() && "call-indirect to undefined table.");
-
maybeAdd(ModuleElement(ModuleElementKind::Table, curr->table));
+ ModuleUtils::iterTableSegments(
+ *module, curr->table, [&](ElementSegment* segment) {
+ maybeAdd(
+ ModuleElement(ModuleElementKind::ElementSegment, segment->name));
+ });
}
void visitGlobalGet(GlobalGet* curr) {
@@ -157,6 +161,13 @@ struct RemoveUnusedModuleElements : public Pass {
roots.emplace_back(ModuleElementKind::Function, func->name);
});
}
+ ModuleUtils::iterActiveElementSegments(
+ *module, [&](ElementSegment* segment) {
+ auto table = module->getTable(segment->table);
+ if (table->imported() && !segment->data.empty()) {
+ roots.emplace_back(ModuleElementKind::ElementSegment, segment->name);
+ }
+ });
// Exports are roots.
bool exportsMemory = false;
for (auto& curr : module->exports) {
@@ -168,6 +179,11 @@ struct RemoveUnusedModuleElements : public Pass {
roots.emplace_back(ModuleElementKind::Event, curr->value);
} else if (curr->kind == ExternalKind::Table) {
roots.emplace_back(ModuleElementKind::Table, curr->value);
+ ModuleUtils::iterTableSegments(
+ *module, curr->value, [&](ElementSegment* segment) {
+ roots.emplace_back(ModuleElementKind::ElementSegment,
+ segment->name);
+ });
} else if (curr->kind == ExternalKind::Memory) {
exportsMemory = true;
}
@@ -178,12 +194,9 @@ struct RemoveUnusedModuleElements : public Pass {
importsMemory = true;
}
// For now, all functions that can be called indirectly are marked as roots.
- for (auto& table : module->tables) {
- // TODO(reference-types): Check whether table's datatype is funcref.
- for (auto& segment : table->segments) {
- for (auto& curr : segment.data) {
- roots.emplace_back(ModuleElementKind::Function, curr);
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto& curr : segment->data) {
+ roots.emplace_back(ModuleElementKind::Function, curr);
}
}
// Compute reachability starting from the root set.
@@ -201,20 +214,24 @@ struct RemoveUnusedModuleElements : public Pass {
return analyzer.reachable.count(
ModuleElement(ModuleElementKind::Event, curr->name)) == 0;
});
-
- for (auto& table : module->tables) {
- table->segments.erase(
- std::remove_if(table->segments.begin(),
- table->segments.end(),
- [&](auto& seg) { return seg.data.empty(); }),
- table->segments.end());
- }
+ module->removeElementSegments([&](ElementSegment* curr) {
+ return curr->data.empty() ||
+ analyzer.reachable.count(ModuleElement(
+ ModuleElementKind::ElementSegment, curr->name)) == 0;
+ });
+ // Since we've removed all empty element segments, here we mark all tables
+ // that have a segment left.
+ std::unordered_set<Name> nonemptyTables;
+ ModuleUtils::iterActiveElementSegments(
+ *module,
+ [&](ElementSegment* segment) { nonemptyTables.insert(segment->table); });
module->removeTables([&](Table* curr) {
- return (curr->segments.empty() || !curr->imported()) &&
+ return (nonemptyTables.count(curr->name) == 0 || !curr->imported()) &&
analyzer.reachable.count(
ModuleElement(ModuleElementKind::Table, curr->name)) == 0;
});
- // Handle the memory and table
+
+ // Handle the memory
if (!exportsMemory && !analyzer.usesMemory) {
if (!importsMemory) {
// The memory is unobservable to the outside, we can remove the
diff --git a/src/passes/ReorderFunctions.cpp b/src/passes/ReorderFunctions.cpp
index 4d02616f0..0c95101a5 100644
--- a/src/passes/ReorderFunctions.cpp
+++ b/src/passes/ReorderFunctions.cpp
@@ -70,11 +70,9 @@ struct ReorderFunctions : public Pass {
for (auto& curr : module->exports) {
counts[curr->value]++;
}
- for (auto& table : module->tables) {
- for (auto& segment : table->segments) {
- for (auto& curr : segment.data) {
- counts[curr]++;
- }
+ for (auto& segment : module->elementSegments) {
+ for (auto& curr : segment->data) {
+ counts[curr]++;
}
}
// sort
diff --git a/src/passes/opt-utils.h b/src/passes/opt-utils.h
index 0a67a7e1e..27a3c5c25 100644
--- a/src/passes/opt-utils.h
+++ b/src/passes/opt-utils.h
@@ -86,13 +86,12 @@ inline void replaceFunctions(PassRunner* runner,
// replace direct calls
FunctionRefReplacer(maybeReplace).run(runner, &module);
// replace in table
- for (auto& table : module.tables) {
- for (auto& segment : table->segments) {
- for (auto& name : segment.data) {
- maybeReplace(name);
- }
+ for (auto& segment : module.elementSegments) {
+ for (auto& name : segment->data) {
+ maybeReplace(name);
}
}
+
// replace in start
if (module.start.is()) {
maybeReplace(module.start);