summaryrefslogtreecommitdiff
path: root/src/ir/module-splitting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/module-splitting.cpp')
-rw-r--r--src/ir/module-splitting.cpp66
1 files changed, 62 insertions, 4 deletions
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp
index 8ef0e7b8c..27b6a0902 100644
--- a/src/ir/module-splitting.cpp
+++ b/src/ir/module-splitting.cpp
@@ -282,7 +282,7 @@ struct ModuleSplitter {
// Initialization helpers
static std::unique_ptr<Module> initSecondary(const Module& primary);
static std::pair<std::set<Name>, std::set<Name>>
- classifyFunctions(const Module& primary, const Config& config);
+ classifyFunctions(Module& primary, const Config& config);
static std::map<Name, Name> initExportedPrimaryFuncs(const Module& primary);
// Other helpers
@@ -343,7 +343,64 @@ std::unique_ptr<Module> ModuleSplitter::initSecondary(const Module& primary) {
}
std::pair<std::set<Name>, std::set<Name>>
-ModuleSplitter::classifyFunctions(const Module& primary, const Config& config) {
+ModuleSplitter::classifyFunctions(Module& primary, const Config& config) {
+ // Find functions that refer to data or element segments. These functions must
+ // remain in the primary module because segments cannot be exported to be
+ // accessed from the secondary module.
+ //
+ // TODO: Investigate other options, such as moving the segments to the
+ // secondary module or replacing the segment-using instructions in the
+ // secondary module with calls to imports.
+ ModuleUtils::ParallelFunctionAnalysis<std::vector<Name>>
+ segmentReferrerCollector(
+ primary, [&](Function* func, std::vector<Name>& segmentReferrers) {
+ if (func->imported()) {
+ return;
+ }
+
+ struct SegmentReferrerCollector
+ : PostWalker<SegmentReferrerCollector,
+ UnifiedExpressionVisitor<SegmentReferrerCollector>> {
+ bool hasSegmentReference = false;
+
+ void visitExpression(Expression* curr) {
+
+#define DELEGATE_ID curr->_id
+
+#define DELEGATE_START(id) [[maybe_unused]] auto* cast = curr->cast<id>();
+#define DELEGATE_GET_FIELD(id, field) cast->field
+#define DELEGATE_FIELD_TYPE(id, field)
+#define DELEGATE_FIELD_HEAPTYPE(id, field)
+#define DELEGATE_FIELD_CHILD(id, field)
+#define DELEGATE_FIELD_OPTIONAL_CHILD(id, field)
+#define DELEGATE_FIELD_INT(id, field)
+#define DELEGATE_FIELD_LITERAL(id, field)
+#define DELEGATE_FIELD_NAME(id, field)
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, field)
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, field)
+#define DELEGATE_FIELD_ADDRESS(id, field)
+
+#define DELEGATE_FIELD_NAME_KIND(id, field, kind) \
+ if (kind == ModuleItemKind::DataSegment || \
+ kind == ModuleItemKind::ElementSegment) { \
+ hasSegmentReference = true; \
+ }
+
+#include "wasm-delegations-fields.def"
+ }
+ };
+ SegmentReferrerCollector collector;
+ collector.walkFunction(func);
+ if (collector.hasSegmentReference) {
+ segmentReferrers.push_back(func->name);
+ }
+ });
+
+ std::unordered_set<Name> segmentReferrers;
+ for (auto& [_, referrers] : segmentReferrerCollector.map) {
+ segmentReferrers.insert(referrers.begin(), referrers.end());
+ }
+
std::set<Name> primaryFuncs, secondaryFuncs;
for (auto& func : primary.functions) {
// In JSPI mode exported functions cannot be moved to the secondary
@@ -351,14 +408,15 @@ ModuleSplitter::classifyFunctions(const Module& primary, const Config& config) {
// wrapper. Exported JSPI functions can still benefit from splitting though
// since only the JSPI wrapper stub will remain in the primary module.
if (func->imported() || config.primaryFuncs.count(func->name) ||
- (config.jspi && ExportUtils::isExported(primary, *func))) {
+ (config.jspi && ExportUtils::isExported(primary, *func)) ||
+ segmentReferrers.count(func->name)) {
primaryFuncs.insert(func->name);
} else {
assert(func->name != primary.start && "The start function must be kept");
secondaryFuncs.insert(func->name);
}
}
- return std::make_pair(primaryFuncs, secondaryFuncs);
+ return std::make_pair(std::move(primaryFuncs), std::move(secondaryFuncs));
}
std::map<Name, Name>