diff --git a/src/tools/wasm-split/wasm-split.cpp b/src/tools/wasm-split/wasm-split.cpp index fd53dd18b5e..82a3e9ab860 100644 --- a/src/tools/wasm-split/wasm-split.cpp +++ b/src/tools/wasm-split/wasm-split.cpp @@ -242,6 +242,33 @@ void setCommonSplitConfigs(ModuleSplitting::Config& config, } } +// Returns whether it is valid to split a function out from the main module. +bool canSplitFunc(Function* func, + const Module& wasm, + const WasmSplitOptions& options) { + if (!func) { + if (!options.quiet) { + std::cerr << "warning: function " << func->name << " does not exist\n"; + } + return false; + } + if (func->imported()) { + if (!options.quiet) { + std::cerr << "warning: cannot split out imported function " << func->name + << "\n"; + } + return false; + } + if (func->name == wasm.start) { + if (!options.quiet) { + std::cerr << "warning: cannot split out start function " << func->name + << "\n"; + } + return false; + } + return true; +} + void splitModule(const WasmSplitOptions& options) { Module wasm; parseInput(wasm, options); @@ -283,17 +310,7 @@ void splitModule(const WasmSplitOptions& options) { // Use the explicitly provided `splitFuncs`. for (auto& func : options.splitFuncs) { auto* function = wasm.getFunctionOrNull(func); - if (!function) { - if (!options.quiet) { - std::cerr << "warning: function " << func << " does not exist\n"; - } - continue; - } - if (function->imported()) { - if (!options.quiet) { - std::cerr << "warning: cannot split out imported function " << func - << "\n"; - } + if (!canSplitFunc(function, wasm, options)) { continue; } if (!options.quiet && options.keepFuncs.contains(func)) { @@ -435,6 +452,9 @@ void multiSplitModule(const WasmSplitOptions& options) { continue; } assert(currFuncs); + if (!canSplitFunc(wasm.getFunctionOrNull(name), wasm, options)) { + continue; + } currFuncs->insert(name); auto [it, inserted] = funcModules.insert({name, currModule}); if (!inserted && it->second != currModule) { @@ -442,9 +462,6 @@ void multiSplitModule(const WasmSplitOptions& options) { << currModule << "; it is already assigned to module " << it->second << '\n'; } - if (inserted && !options.quiet && !wasm.getFunctionOrNull(name)) { - std::cerr << "warning: Function " << name << " does not exist\n"; - } } if (options.emitModuleNames && !wasm.name) { diff --git a/test/lit/wasm-split/multi-split-start.wast b/test/lit/wasm-split/multi-split-start.wast new file mode 100644 index 00000000000..8a0bb1af728 --- /dev/null +++ b/test/lit/wasm-split/multi-split-start.wast @@ -0,0 +1,86 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: wasm-split -all -g --multi-split %s --manifest %s.manifest --out-prefix=%t -o %t.wasm +;; RUN: wasm-dis %t.wasm | filecheck %s --check-prefix=PRIMARY +;; RUN: wasm-dis %t1.wasm | filecheck %s --check-prefix=MOD1 +;; RUN: wasm-dis %t2.wasm | filecheck %s --check-prefix=MOD2 +;; RUN: wasm-dis %t3.wasm | filecheck %s --check-prefix=MOD3 + +;; The start function, $C, cannot be split it, and will remain in the primary. + +(module + ;; PRIMARY: (type $0 (func)) + + ;; PRIMARY: (import "placeholder.2" "0" (func $placeholder_0)) + + ;; PRIMARY: (table $0 1 funcref) + + ;; PRIMARY: (elem $0 (i32.const 0) $placeholder_0) + + ;; PRIMARY: (export "table" (table $0)) + + ;; PRIMARY: (export "C" (func $C)) + + ;; PRIMARY: (start $C) + (start $C) + + ;; MOD1: (type $0 (func)) + + ;; MOD1: (import "primary" "table" (table $timport$0 1 funcref)) + + ;; MOD1: (import "primary" "C" (func $C (exact))) + + ;; MOD1: (func $A + ;; MOD1-NEXT: (call $A) + ;; MOD1-NEXT: (call_indirect (type $0) + ;; MOD1-NEXT: (i32.const 0) + ;; MOD1-NEXT: ) + ;; MOD1-NEXT: (call $C) + ;; MOD1-NEXT: ) + (func $A + (call $A) + (call $B) + (call $C) + ) + + ;; MOD2: (type $0 (func)) + + ;; MOD2: (import "primary" "table" (table $timport$0 1 funcref)) + + ;; MOD2: (elem $0 (i32.const 0) $B) + + ;; MOD2: (func $B + ;; MOD2-NEXT: (drop + ;; MOD2-NEXT: (i32.const 42) + ;; MOD2-NEXT: ) + ;; MOD2-NEXT: ) + (func $B + (drop + (i32.const 42) + ) + ) + + ;; PRIMARY: (func $C + ;; PRIMARY-NEXT: (drop + ;; PRIMARY-NEXT: (i32.const 1337) + ;; PRIMARY-NEXT: ) + ;; PRIMARY-NEXT: ) + (func $C + (drop + (i32.const 1337) + ) + ) + + ;; MOD3: (type $0 (func)) + + ;; MOD3: (func $D + ;; MOD3-NEXT: (drop + ;; MOD3-NEXT: (i32.const 999999) + ;; MOD3-NEXT: ) + ;; MOD3-NEXT: ) + (func $D + (drop + (i32.const 999999) + ) + ) +) diff --git a/test/lit/wasm-split/multi-split-start.wast.manifest b/test/lit/wasm-split/multi-split-start.wast.manifest new file mode 100644 index 00000000000..ae2c2b78c5a --- /dev/null +++ b/test/lit/wasm-split/multi-split-start.wast.manifest @@ -0,0 +1,9 @@ +1: +A + +2: +B + +3: +C +D diff --git a/test/lit/wasm-split/start.wast b/test/lit/wasm-split/start.wast new file mode 100644 index 00000000000..381a1e8707a --- /dev/null +++ b/test/lit/wasm-split/start.wast @@ -0,0 +1,28 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: wasm-split %s --split-funcs=start_func,other -o1 %t.1.wasm -o2 %t.2.wasm -g 2>&1 +;; RUN: wasm-dis -all %t.1.wasm | filecheck %s --check-prefix PRIMARY +;; RUN: wasm-dis -all %t.2.wasm | filecheck %s --check-prefix SECONDARY + +;; Do not error on trying to split out the start function. It cannot be +;; split out, keep it in the primary module. + +(module + ;; PRIMARY: (type $0 (func)) + + ;; PRIMARY: (start $start_func) + + ;; PRIMARY: (func $start_func (type $0) + ;; PRIMARY-NEXT: ) + (func $start_func) + + (start $start_func) + + ;; SECONDARY: (type $0 (func)) + + ;; SECONDARY: (func $other (type $0) + ;; SECONDARY-NEXT: ) + (func $other) +) + +