summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp62
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--src/passes/passes.h1
-rw-r--r--src/tools/wasm-reduce.cpp1
-rw-r--r--test/passes/remove-unused-module-elements.txt19
-rw-r--r--test/passes/remove-unused-module-elements.wast43
-rw-r--r--test/passes/remove-unused-nonfunction-module-elements.txt331
-rw-r--r--test/passes/remove-unused-nonfunction-module-elements.wast264
8 files changed, 709 insertions, 13 deletions
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 05e80af0d..6cd050da9 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -153,6 +153,10 @@ struct FunctionTypeAnalyzer : public PostWalker<FunctionTypeAnalyzer> {
};
struct RemoveUnusedModuleElements : public Pass {
+ bool rootAllFunctions;
+
+ RemoveUnusedModuleElements(bool rootAllFunctions) : rootAllFunctions(rootAllFunctions) {}
+
void run(PassRunner* runner, Module* module) override {
optimizeGlobalsAndFunctions(module);
optimizeFunctionTypes(module);
@@ -170,6 +174,12 @@ struct RemoveUnusedModuleElements : public Pass {
roots.emplace_back(ModuleElementKind::Function, module->start);
}
}
+ // If told to, root all the functions
+ if (rootAllFunctions) {
+ for (auto& func : module->functions) {
+ roots.emplace_back(ModuleElementKind::Function, func->name);
+ }
+ }
// Exports are roots.
bool exportsMemory = false;
bool exportsTable = false;
@@ -184,6 +194,16 @@ struct RemoveUnusedModuleElements : public Pass {
exportsTable = true;
}
}
+ // Check for special imports are roots.
+ bool importsMemory = false;
+ bool importsTable = false;
+ for (auto& curr : module->imports) {
+ if (curr->kind == ExternalKind::Memory) {
+ importsMemory = true;
+ } else if (curr->kind == ExternalKind::Table) {
+ importsTable = true;
+ }
+ }
// For now, all functions that can be called indirectly are marked as roots.
for (auto& segment : module->table.segments) {
for (auto& curr : segment.data) {
@@ -218,19 +238,31 @@ struct RemoveUnusedModuleElements : public Pass {
}
module->updateMaps();
// Handle the memory and table
- if (!exportsMemory && !analyzer.usesMemory && module->memory.segments.empty()) {
- module->memory.exists = false;
- module->memory.imported = false;
- module->memory.initial = 0;
- module->memory.max = 0;
- removeImport(ExternalKind::Memory, module);
+ if (!exportsMemory && !analyzer.usesMemory) {
+ if (!importsMemory) {
+ // The memory is unobservable to the outside, we can remove the contents.
+ module->memory.segments.clear();
+ }
+ if (module->memory.segments.empty()) {
+ module->memory.exists = false;
+ module->memory.imported = false;
+ module->memory.initial = 0;
+ module->memory.max = 0;
+ removeImport(ExternalKind::Memory, module);
+ }
}
- if (!exportsTable && !analyzer.usesTable && module->table.segments.empty()) {
- module->table.exists = false;
- module->table.imported = false;
- module->table.initial = 0;
- module->table.max = 0;
- removeImport(ExternalKind::Table, module);
+ if (!exportsTable && !analyzer.usesTable) {
+ if (!importsTable) {
+ // The table is unobservable to the outside, we can remove the contents.
+ module->table.segments.clear();
+ }
+ if (module->table.segments.empty()) {
+ module->table.exists = false;
+ module->table.imported = false;
+ module->table.initial = 0;
+ module->table.max = 0;
+ removeImport(ExternalKind::Table, module);
+ }
}
}
@@ -279,7 +311,11 @@ struct RemoveUnusedModuleElements : public Pass {
};
Pass* createRemoveUnusedModuleElementsPass() {
- return new RemoveUnusedModuleElements();
+ return new RemoveUnusedModuleElements(false);
+}
+
+Pass* createRemoveUnusedNonFunctionModuleElementsPass() {
+ return new RemoveUnusedModuleElements(true);
}
} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index ae9484d29..2d93d99ae 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -103,6 +103,7 @@ void PassRegistry::registerPasses() {
registerPass("remove-memory", "removes memory segments", createRemoveMemoryPass);
registerPass("remove-unused-brs", "removes breaks from locations that are not needed", createRemoveUnusedBrsPass);
registerPass("remove-unused-module-elements", "removes unused module elements", createRemoveUnusedModuleElementsPass);
+ registerPass("remove-unused-nonfunction-module-elements", "removes unused module elements that are not functions", createRemoveUnusedNonFunctionModuleElementsPass);
registerPass("remove-unused-names", "removes names from locations that are never branched to", createRemoveUnusedNamesPass);
registerPass("reorder-functions", "sorts functions by access frequency", createReorderFunctionsPass);
registerPass("reorder-locals", "sorts locals by access frequency", createReorderLocalsPass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index 5ab03a439..cf77f9fac 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -60,6 +60,7 @@ Pass* createRemoveImportsPass();
Pass* createRemoveMemoryPass();
Pass* createRemoveUnusedBrsPass();
Pass* createRemoveUnusedModuleElementsPass();
+Pass* createRemoveUnusedNonFunctionModuleElementsPass();
Pass* createRemoveUnusedNamesPass();
Pass* createReorderFunctionsPass();
Pass* createReorderLocalsPass();
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp
index 6b8d93f97..7b7ff9da3 100644
--- a/src/tools/wasm-reduce.cpp
+++ b/src/tools/wasm-reduce.cpp
@@ -249,6 +249,7 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
"--remove-memory",
"--remove-unused-names --remove-unused-brs",
"--remove-unused-module-elements",
+ "--remove-unused-nonfunction-module-elements",
"--reorder-functions",
"--reorder-locals",
"--simplify-locals --vacuum",
diff --git a/test/passes/remove-unused-module-elements.txt b/test/passes/remove-unused-module-elements.txt
index 82ed9125e..7c85eec58 100644
--- a/test/passes/remove-unused-module-elements.txt
+++ b/test/passes/remove-unused-module-elements.txt
@@ -259,3 +259,22 @@
)
)
)
+(module
+)
+(module
+)
+(module
+ (type $0 (func (param f64) (result f64)))
+ (import "env" "table" (table 6 6 anyfunc))
+ (elem (i32.const 0) $0)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
diff --git a/test/passes/remove-unused-module-elements.wast b/test/passes/remove-unused-module-elements.wast
index 2d4b51f1b..dfefd7b91 100644
--- a/test/passes/remove-unused-module-elements.wast
+++ b/test/passes/remove-unused-module-elements.wast
@@ -218,4 +218,47 @@
(drop (i32.const 0))
)
)
+(module ;; the function and the table can be removed
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 anyfunc)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
+(module ;; the function uses the table, but all are removeable
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 anyfunc)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (call_indirect (type $0) (f64.const 1) (i32.const 0))
+ (f64.const 0)
+ )
+ )
+)
+(module ;; the table is imported - we can't remove it
+ (type $0 (func (param f64) (result f64)))
+ (import "env" "table" (table 6 6 anyfunc))
+ (elem (i32.const 0) $0)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
diff --git a/test/passes/remove-unused-nonfunction-module-elements.txt b/test/passes/remove-unused-nonfunction-module-elements.txt
new file mode 100644
index 000000000..bd4a8c7d4
--- /dev/null
+++ b/test/passes/remove-unused-nonfunction-module-elements.txt
@@ -0,0 +1,331 @@
+(module
+ (type $0 (func))
+ (type $1 (func (param i32)))
+ (type $2 (func (param i32) (result i32)))
+ (table 1 1 anyfunc)
+ (elem (i32.const 0) $called_indirect)
+ (memory $0 0)
+ (export "memory" (memory $0))
+ (export "exported" (func $exported))
+ (export "other1" (func $other1))
+ (export "other2" (func $other2))
+ (start $start)
+ (func $start (; 0 ;) (type $0)
+ (call $called0)
+ )
+ (func $called0 (; 1 ;) (type $0)
+ (call $called1)
+ )
+ (func $called1 (; 2 ;) (type $0)
+ (nop)
+ )
+ (func $called_indirect (; 3 ;) (type $0)
+ (nop)
+ )
+ (func $exported (; 4 ;) (type $0)
+ (call $called2)
+ )
+ (func $called2 (; 5 ;) (type $0)
+ (call $called2)
+ (call $called3)
+ )
+ (func $called3 (; 6 ;) (type $0)
+ (call $called4)
+ )
+ (func $called4 (; 7 ;) (type $0)
+ (call $called3)
+ )
+ (func $remove0 (; 8 ;) (type $0)
+ (call $remove1)
+ )
+ (func $remove1 (; 9 ;) (type $0)
+ (nop)
+ )
+ (func $remove2 (; 10 ;) (type $0)
+ (call $remove2)
+ )
+ (func $remove3 (; 11 ;) (type $0)
+ (call $remove4)
+ )
+ (func $remove4 (; 12 ;) (type $0)
+ (call $remove3)
+ )
+ (func $other1 (; 13 ;) (type $1) (param $0 i32)
+ (call_indirect (type $0)
+ (i32.const 0)
+ )
+ (call_indirect (type $0)
+ (i32.const 0)
+ )
+ (call_indirect (type $0)
+ (i32.const 0)
+ )
+ (call_indirect (type $0)
+ (i32.const 0)
+ )
+ (call_indirect (type $1)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ (call_indirect (type $1)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ (drop
+ (call_indirect (type $2)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (call_indirect (type $2)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (call_indirect (type $2)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+ )
+ (func $other2 (; 14 ;) (type $1) (param $0 i32)
+ (unreachable)
+ )
+)
+(module
+)
+(module
+)
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 1 anyfunc))
+ (export "mem" (memory $0))
+ (export "tab" (table $0))
+)
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 1 anyfunc))
+ (elem (i32.const 0) $waka)
+ (data (i32.const 1) "hello, world!")
+ (func $waka (; 0 ;) (type $0)
+ (nop)
+ )
+)
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0)
+ (drop
+ (i32.load
+ (i32.const 0)
+ )
+ )
+ (call_indirect (type $0)
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0)
+ (i32.store
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0) (result i32)
+ (i32.atomic.rmw.add
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0) (result i32)
+ (i32.atomic.rmw8_u.cmpxchg
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0)
+ (local $0 i32)
+ (local $1 i64)
+ (drop
+ (i32.wait
+ (get_local $0)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ )
+)
+(module
+ (type $0 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0) (result i32)
+ (wake
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (result i32)))
+ (memory $0 23 256)
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0) (result i32)
+ (grow_memory
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0) (result i32)
+ (grow_memory
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (result i32)))
+ (memory $0 23 256)
+ (export "user" (func $user))
+ (func $user (; 0 ;) (type $0) (result i32)
+ (current_memory)
+ )
+)
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (elem (get_global $tableBase) $waka)
+ (data (get_global $memoryBase) "hello, world!")
+ (func $waka (; 0 ;) (type $0)
+ (nop)
+ )
+)
+(module
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $1 (func (result i32)))
+ (type $2 (func))
+ (import "env" "imported" (global $imported i32))
+ (import "env" "_puts" (func $_puts (param i32) (result i32)))
+ (global $int (mut i32) (get_global $imported))
+ (global $set (mut i32) (i32.const 100))
+ (global $exp_glob i32 (i32.const 600))
+ (export "one" (func $one))
+ (export "three" (func $three))
+ (export "exp_glob" (global $exp_glob))
+ (func $one (; 1 ;) (type $1) (result i32)
+ (call $two)
+ )
+ (func $two (; 2 ;) (type $1) (result i32)
+ (get_global $int)
+ )
+ (func $three (; 3 ;) (type $2)
+ (call $four)
+ )
+ (func $four (; 4 ;) (type $2)
+ (set_global $set
+ (i32.const 200)
+ )
+ (drop
+ (call $_puts
+ (i32.const 300)
+ )
+ )
+ )
+ (func $forget_implemented (; 5 ;) (type $2)
+ (nop)
+ )
+ (func $starter (; 6 ;) (type $2)
+ (nop)
+ )
+)
+(module
+ (type $0 (func))
+ (func $starter (; 0 ;) (type $0)
+ (nop)
+ )
+)
+(module
+ (type $0 (func))
+ (start $starter)
+ (func $starter (; 0 ;) (type $0)
+ (drop
+ (i32.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (param f64) (result f64)))
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 anyfunc)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (call_indirect (type $0)
+ (f64.const 1)
+ (i32.const 0)
+ )
+ (f64.const 0)
+ )
+ )
+)
+(module
+ (type $0 (func (param f64) (result f64)))
+ (import "env" "table" (table 6 6 anyfunc))
+ (elem (i32.const 0) $0)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
diff --git a/test/passes/remove-unused-nonfunction-module-elements.wast b/test/passes/remove-unused-nonfunction-module-elements.wast
new file mode 100644
index 000000000..d0b49ee34
--- /dev/null
+++ b/test/passes/remove-unused-nonfunction-module-elements.wast
@@ -0,0 +1,264 @@
+(module
+ (memory 0)
+ (start $start)
+ (type $0 (func))
+ (type $0-dupe (func))
+ (type $1 (func (param i32)))
+ (type $1-dupe (func (param i32)))
+ (type $2 (func (param i32) (result i32)))
+ (type $2-dupe (func (param i32) (result i32)))
+ (type $2-thrupe (func (param i32) (result i32)))
+ (export "memory" (memory $0))
+ (export "exported" $exported)
+ (export "other1" $other1)
+ (export "other2" $other2)
+ (table 1 1 anyfunc)
+ (elem (i32.const 0) $called_indirect)
+ (func $start (type $0)
+ (call $called0)
+ )
+ (func $called0 (type $0)
+ (call $called1)
+ )
+ (func $called1 (type $0)
+ (nop)
+ )
+ (func $called_indirect (type $0)
+ (nop)
+ )
+ (func $exported (type $0-dupe)
+ (call $called2)
+ )
+ (func $called2 (type $0-dupe)
+ (call $called2)
+ (call $called3)
+ )
+ (func $called3 (type $0-dupe)
+ (call $called4)
+ )
+ (func $called4 (type $0-dupe)
+ (call $called3)
+ )
+ (func $remove0 (type $0-dupe)
+ (call $remove1)
+ )
+ (func $remove1 (type $0-dupe)
+ (nop)
+ )
+ (func $remove2 (type $0-dupe)
+ (call $remove2)
+ )
+ (func $remove3 (type $0)
+ (call $remove4)
+ )
+ (func $remove4 (type $0)
+ (call $remove3)
+ )
+ (func $other1 (param i32) (type $1)
+ (call_indirect (type $0) (i32.const 0))
+ (call_indirect (type $0) (i32.const 0))
+ (call_indirect (type $0-dupe) (i32.const 0))
+ (call_indirect (type $0-dupe) (i32.const 0))
+ (call_indirect (type $1) (i32.const 0) (i32.const 0))
+ (call_indirect (type $1-dupe) (i32.const 0) (i32.const 0))
+ (drop (call_indirect (type $2) (i32.const 0) (i32.const 0)))
+ (drop (call_indirect (type $2-dupe) (i32.const 0) (i32.const 0)))
+ (drop (call_indirect (type $2-thrupe) (i32.const 0) (i32.const 0)))
+ )
+ (func $other2 (param i32) (type $1-dupe)
+ (unreachable)
+ )
+)
+(module ;; remove the table and memory
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+)
+(module ;; also when not imported
+ (memory 256)
+ (table 1 anyfunc)
+)
+(module ;; but not when exported
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 1 anyfunc))
+ (export "mem" (memory 0))
+ (export "tab" (table 0))
+)
+(module ;; and not when there are segments
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 1 anyfunc))
+ (data (i32.const 1) "hello, world!")
+ (elem (i32.const 0) $waka)
+ (func $waka)
+)
+(module ;; and not when used
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (export "user" $user)
+ (func $user
+ (drop (i32.load (i32.const 0)))
+ (call_indirect (type $0) (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (memory $0 (shared 23 256))
+ (export "user" $user)
+ (func $user
+ (i32.store (i32.const 0) (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (memory $0 (shared 23 256))
+ (export "user" $user)
+ (func $user (result i32)
+ (i32.atomic.rmw.add (i32.const 0) (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (memory $0 (shared 23 256))
+ (export "user" $user)
+ (func $user (result i32)
+ (i32.atomic.rmw8_u.cmpxchg (i32.const 0) (i32.const 0) (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (memory $0 (shared 23 256))
+ (export "user" $user)
+ (func $user
+ (local $0 i32)
+ (local $1 i64)
+ (drop
+ (i32.wait
+ (get_local $0)
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ )
+)
+(module ;; more use checks
+ (memory $0 (shared 23 256))
+ (export "user" $user)
+ (func $user (result i32)
+ (wake (i32.const 0) (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (memory $0 23 256)
+ (export "user" $user)
+ (func $user (result i32)
+ (grow_memory (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (import "env" "memory" (memory $0 256))
+ (export "user" $user)
+ (func $user (result i32)
+ (grow_memory (i32.const 0))
+ )
+)
+(module ;; more use checks
+ (memory $0 23 256)
+ (export "user" $user)
+ (func $user (result i32)
+ (current_memory)
+ )
+)
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32)) ;; used in init
+ (import "env" "tableBase" (global $tableBase i32)) ;; used in init
+ (data (get_global $memoryBase) "hello, world!")
+ (elem (get_global $tableBase) $waka)
+ (func $waka) ;; used in table
+)
+(module ;; one is exported, and one->two->int global, whose init->imported
+ (import "env" "imported" (global $imported i32))
+ (import "env" "forgetme" (global $forgetme i32))
+ (import "env" "_puts" (func $_puts (param i32) (result i32)))
+ (import "env" "forget_puts" (func $forget_puts (param i32) (result i32)))
+ (global $int (mut i32) (get_global $imported))
+ (global $set (mut i32) (i32.const 100))
+ (global $forget_global (mut i32) (i32.const 500))
+ (global $exp_glob i32 (i32.const 600))
+ (export "one" (func $one))
+ (export "three" (func $three))
+ (export "exp_glob" (global $exp_glob))
+ (start $starter)
+ (func $one (result i32)
+ (call $two)
+ )
+ (func $two (result i32)
+ (get_global $int)
+ )
+ (func $three
+ (call $four)
+ )
+ (func $four
+ (set_global $set (i32.const 200))
+ (drop (call $_puts (i32.const 300)))
+ )
+ (func $forget_implemented
+ (nop)
+ )
+ (func $starter
+ (nop)
+ )
+)
+(module ;; empty start being removed
+ (start $starter)
+ (func $starter
+ (nop)
+ )
+)
+(module ;; non-empty start being kept
+ (start $starter)
+ (func $starter
+ (drop (i32.const 0))
+ )
+)
+(module ;; the function stays but the table can be removed
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 anyfunc)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
+(module ;; the function keeps the table alive
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 anyfunc)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (call_indirect (type $0) (f64.const 1) (i32.const 0))
+ (f64.const 0)
+ )
+ )
+)
+(module ;; the table is imported - we can't remove it
+ (type $0 (func (param f64) (result f64)))
+ (import "env" "table" (table 6 6 anyfunc))
+ (elem (i32.const 0) $0)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (f64.const 1)
+ (f64.const 1)
+ )
+ (f64.const 1)
+ (f64.const 0)
+ )
+ )
+)
+