Skip to content
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8939ccd
[wasm-split] Precompute ownership info (NFC)
aheejin Aug 6, 2026
4e9ea51
[wasm-split] Remove module elements in bulk (NFC)
aheejin Aug 8, 2026
752739b
[wasm-split] Deduplicate loops in shareImportableItems (NFC)
aheejin Aug 12, 2026
cbe6fc3
Update src/ir/module-splitting.cpp
aheejin Aug 14, 2026
c083f06
Merge branch 'main' into wasm_split_owning_modules
aheejin Aug 14, 2026
ba70880
Remove usedToSecondary map
aheejin Aug 14, 2026
8a3cd6c
FIELD->field, VAL->val
aheejin Aug 14, 2026
491367c
Rename a few variables
aheejin Aug 14, 2026
e39e906
More comments
aheejin Aug 14, 2026
3731f28
Apply suggestions from code review
aheejin Aug 14, 2026
529b130
[wasm-split] Don't use ParallelFunctionAnalysis in scanModule (NFC)
aheejin Aug 15, 2026
0261532
Merge branch 'wasm_split_no_parallel' into wasm_split_owning_modules
aheejin Aug 15, 2026
f03574f
Eliminate two-phase approach in computeUsedNames
aheejin Aug 15, 2026
8912e36
Use template instead of ADD_ITEM macro
aheejin Aug 15, 2026
0355b59
Merge branch 'wasm_split_owning_modules' into wasm_split_remove_opt
aheejin Aug 15, 2026
e802ede
Update src/ir/module-splitting.cpp
aheejin Aug 15, 2026
93813d2
Merge branch 'wasm_split_remove_opt' into wasm_split_dedup_loops
aheejin Aug 15, 2026
0e2c9ff
[wasm-split] Precompute ownership info (NFC)
aheejin Aug 6, 2026
7d0d87d
Update src/ir/module-splitting.cpp
aheejin Aug 14, 2026
8d9455b
Remove usedToSecondary map
aheejin Aug 14, 2026
86f57f4
FIELD->field, VAL->val
aheejin Aug 14, 2026
89b8e08
Rename a few variables
aheejin Aug 14, 2026
620886f
More comments
aheejin Aug 14, 2026
47b0a61
Apply suggestions from code review
aheejin Aug 14, 2026
f3b6900
Eliminate two-phase approach in computeUsedNames
aheejin Aug 15, 2026
d117127
Use template instead of ADD_ITEM macro
aheejin Aug 15, 2026
009571b
[wasm-split] Remove module elements in bulk (NFC)
aheejin Aug 8, 2026
485abf9
Update src/ir/module-splitting.cpp
aheejin Aug 15, 2026
716760a
Use macros in insert()
aheejin Aug 18, 2026
3fbc940
clang-format
aheejin Aug 18, 2026
4ca31cf
Merge branch 'wasm_split_owning_modules' into wasm_split_remove_opt
aheejin Aug 18, 2026
8591385
Merge branch 'main' into wasm_split_dedup_loops
aheejin Aug 18, 2026
8b222ce
Merge branch 'wasm_split_remove_opt' into wasm_split_dedup_loops
aheejin Aug 18, 2026
ec8c860
Fix reverted function
aheejin Aug 18, 2026
9db6057
Merge branch 'main' into wasm_split_remove_opt
aheejin Aug 18, 2026
d925538
Remove stray change from previous PR
aheejin Aug 18, 2026
e2ca90e
Merge branch 'wasm_split_remove_opt' into wasm_split_dedup_loops
aheejin Aug 18, 2026
d998497
Merge branch 'main' into wasm_split_dedup_loops
aheejin Aug 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 65 additions & 108 deletions src/ir/module-splitting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1065,129 +1065,86 @@ void ModuleSplitter::shareImportableItems() {
// the primary and secondary modules), export the item from the primary and
// import it from the using secondary modules.

std::unordered_set<Name> memoriesToRemove;
for (auto& memory : primary.memories) {
if (tracker.isUnused(memory->name, tracker.memories)) {
memoriesToRemove.insert(memory->name);
} else if (tracker.usedBySingleSecondary(memory->name, tracker.memories)) {
auto* secondary =
tracker.getUsingSecondaries(memory->name, tracker.memories)[0];
ModuleUtils::copyMemory(memory.get(), *secondary);
memoriesToRemove.insert(memory->name);
} else {
for (auto* secondary :
tracker.getUsingSecondaries(memory->name, tracker.memories)) {
auto* secondaryMemory =
ModuleUtils::copyMemory(memory.get(), *secondary);
makeImportExport(
*memory, *secondaryMemory, "memory", ExternalKind::Memory);
}
}
}
primary.removeMemories(
[&](Memory* memory) { return memoriesToRemove.contains(memory->name); });

std::unordered_set<Name> tablesToRemove;
for (auto& table : primary.tables) {
if (tracker.isUnused(table->name, tracker.tables)) {
tablesToRemove.insert(table->name);
} else if (tracker.usedBySingleSecondary(table->name, tracker.tables)) {
auto* secondary =
tracker.getUsingSecondaries(table->name, tracker.tables)[0];
assert(!secondary->getTableOrNull(table->name));
ModuleUtils::copyTable(table.get(), *secondary);
tablesToRemove.insert(table->name);
} else {
for (auto* secondary :
tracker.getUsingSecondaries(table->name, tracker.tables)) {
auto* secondaryTable = ModuleUtils::copyTable(table.get(), *secondary);
makeImportExport(*table, *secondaryTable, "table", ExternalKind::Table);
auto shareElements = [&](auto& elements,
auto& trackerElements,
auto copyElement,
auto removeElements,
const char* exportName = nullptr,
ExternalKind kind = ExternalKind::Invalid) {
std::unordered_set<Name> elementsToRemove;
for (auto& element : elements) {
if (tracker.isUnused(element->name, trackerElements)) {
elementsToRemove.insert(element->name);
} else if (tracker.usedBySingleSecondary(element->name,
trackerElements)) {
auto* secondary =
tracker.getUsingSecondaries(element->name, trackerElements)[0];
copyElement(element.get(), *secondary);
elementsToRemove.insert(element->name);
} else {
// We only import and export Importables, i.e., we don't do this for
// segments.
using T = std::remove_pointer_t<decltype(element.get())>;
if constexpr (std::is_base_of_v<Importable, T>) {
for (auto* secondary :
tracker.getUsingSecondaries(element->name, trackerElements)) {
auto* secondaryElement = copyElement(element.get(), *secondary);
makeImportExport(*element, *secondaryElement, exportName, kind);
}
}
}
}
}
primary.removeTables(
[&](Table* table) { return tablesToRemove.count(table->name); });
(primary.*removeElements)(
[&](auto* element) { return elementsToRemove.count(element->name); });
};

shareElements(primary.memories,
tracker.memories,
ModuleUtils::copyMemory,
&Module::removeMemories,
"memory",
ExternalKind::Memory);

shareElements(primary.tables,
tracker.tables,
ModuleUtils::copyTable,
&Module::removeTables,
"table",
ExternalKind::Table);

std::unordered_set<Name> globalsToRemove;
for (auto& global : primary.globals) {
if (global->mutable_) {
assert(primary.features.hasMutableGlobals() &&
"TODO: add wrapper functions for disallowed mutable globals");
}

if (tracker.isUnused(global->name, tracker.globals)) {
globalsToRemove.insert(global->name);
} else if (tracker.usedBySingleSecondary(global->name, tracker.globals)) {
auto* secondary =
tracker.getUsingSecondaries(global->name, tracker.globals)[0];
ModuleUtils::copyGlobal(global.get(), *secondary);
globalsToRemove.insert(global->name);
} else {
for (auto* secondary :
tracker.getUsingSecondaries(global->name, tracker.globals)) {
auto* secondaryGlobal =
ModuleUtils::copyGlobal(global.get(), *secondary);
makeImportExport(
*global, *secondaryGlobal, "global", ExternalKind::Global);
}
}
}
primary.removeGlobals(
[&](Global* global) { return globalsToRemove.count(global->name); });

std::unordered_set<Name> tagsToRemove;
for (auto& tag : primary.tags) {
if (tracker.isUnused(tag->name, tracker.tags)) {
tagsToRemove.insert(tag->name);
} else if (tracker.usedBySingleSecondary(tag->name, tracker.tags)) {
auto* secondary = tracker.getUsingSecondaries(tag->name, tracker.tags)[0];
ModuleUtils::copyTag(tag.get(), *secondary);
tagsToRemove.insert(tag->name);
} else {
for (auto* secondary :
tracker.getUsingSecondaries(tag->name, tracker.tags)) {
auto* secondaryTag = ModuleUtils::copyTag(tag.get(), *secondary);
makeImportExport(*tag, *secondaryTag, "tag", ExternalKind::Tag);
}
}
}
primary.removeTags([&](Tag* tag) { return tagsToRemove.count(tag->name); });
shareElements(primary.globals,
tracker.globals,
ModuleUtils::copyGlobal,
&Module::removeGlobals,
"global",
ExternalKind::Global);

shareElements(primary.tags,
tracker.tags,
ModuleUtils::copyTag,
&Module::removeTags,
"tag",
ExternalKind::Tag);

// Move segments that are exclusively used in a secondary module. If not, do
// nothing. (Segments cannot be imported / exported. They will be handled in
// indirectReferencesToSecondaryFunctions.)

std::unordered_set<Name> dataSegmentsToRemove;
for (auto& dataSegment : primary.dataSegments) {
if (tracker.isUnused(dataSegment->name, tracker.dataSegments)) {
dataSegmentsToRemove.insert(dataSegment->name);
} else if (tracker.usedBySingleSecondary(dataSegment->name,
tracker.dataSegments)) {
auto* secondary =
tracker.getUsingSecondaries(dataSegment->name, tracker.dataSegments)[0];
ModuleUtils::copyDataSegment(dataSegment.get(), *secondary);
dataSegmentsToRemove.insert(dataSegment->name);
}
}
primary.removeDataSegments([&](DataSegment* dataSegment) {
return dataSegmentsToRemove.count(dataSegment->name);
});
shareElements(primary.dataSegments,
tracker.dataSegments,
ModuleUtils::copyDataSegment,
&Module::removeDataSegments);

std::unordered_set<Name> elementSegmentsToRemove;
for (auto& elementSegment : primary.elementSegments) {
if (tracker.isUnused(elementSegment->name, tracker.elementSegments)) {
elementSegmentsToRemove.insert(elementSegment->name);
} else if (tracker.usedBySingleSecondary(elementSegment->name,
tracker.elementSegments)) {
auto* secondary = tracker.getUsingSecondaries(elementSegment->name,
tracker.elementSegments)[0];
ModuleUtils::copyElementSegment(elementSegment.get(), *secondary);
elementSegmentsToRemove.insert(elementSegment->name);
}
}
primary.removeElementSegments([&](ElementSegment* elementSegment) {
return elementSegmentsToRemove.count(elementSegment->name);
});
shareElements(primary.elementSegments,
tracker.elementSegments,
ModuleUtils::copyElementSegment,
&Module::removeElementSegments);
}

void ModuleSplitter::indirectReferencesToSecondaryFunctions() {
Expand Down
Loading