diff options
Diffstat (limited to 'src/passes')
-rw-r--r-- | src/passes/DeadArgumentElimination.cpp | 8 | ||||
-rw-r--r-- | src/passes/Directize.cpp | 2 | ||||
-rw-r--r-- | src/passes/FuncCastEmulation.cpp | 20 | ||||
-rw-r--r-- | src/passes/GenerateDynCalls.cpp | 16 | ||||
-rw-r--r-- | src/passes/Inlining.cpp | 8 | ||||
-rw-r--r-- | src/passes/LegalizeJSInterface.cpp | 10 | ||||
-rw-r--r-- | src/passes/Metrics.cpp | 8 | ||||
-rw-r--r-- | src/passes/PostEmscripten.cpp | 2 | ||||
-rw-r--r-- | src/passes/Print.cpp | 62 | ||||
-rw-r--r-- | src/passes/PrintCallGraph.cpp | 10 | ||||
-rw-r--r-- | src/passes/RemoveImports.cpp | 8 | ||||
-rw-r--r-- | src/passes/RemoveUnusedModuleElements.cpp | 67 | ||||
-rw-r--r-- | src/passes/ReorderFunctions.cpp | 8 | ||||
-rw-r--r-- | src/passes/opt-utils.h | 9 |
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); |