summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/example/module-splitting.cpp289
-rw-r--r--test/example/module-splitting.txt641
2 files changed, 930 insertions, 0 deletions
diff --git a/test/example/module-splitting.cpp b/test/example/module-splitting.cpp
new file mode 100644
index 000000000..50fb0f4c5
--- /dev/null
+++ b/test/example/module-splitting.cpp
@@ -0,0 +1,289 @@
+#include <cassert>
+#include <iostream>
+
+#include "ir/module-splitting.h"
+#include "ir/stack-utils.h"
+#include "wasm-features.h"
+#include "wasm-printing.h"
+#include "wasm-s-parser.h"
+#include "wasm-validator.h"
+#include "wasm.h"
+
+using namespace wasm;
+
+std::unique_ptr<Module> parse(char* module) {
+ auto wasm = std::make_unique<Module>();
+ wasm->features = FeatureSet::All;
+ try {
+ SExpressionParser parser(module);
+ Element& root = *parser.root;
+ SExpressionWasmBuilder builder(*wasm, *root[0], IRProfile::Normal);
+ } catch (ParseException& p) {
+ p.dump(std::cerr);
+ Fatal() << "error in parsing wasm text";
+ }
+ return wasm;
+}
+
+void do_test(const std::set<Name>& keptFuncs, std::string&& module) {
+ WasmValidator validator;
+ bool valid;
+
+ auto primary = parse(&module.front());
+ valid = validator.validate(*primary);
+ assert(valid && "before invalid!");
+
+ std::cout << "Before:\n";
+ WasmPrinter::printModule(primary.get());
+
+ std::cout << "Keeping: ";
+ if (keptFuncs.size()) {
+ auto it = keptFuncs.begin();
+ std::cout << *it++;
+ while (it != keptFuncs.end()) {
+ std::cout << ", " << *it++;
+ }
+ } else {
+ std::cout << "<none>";
+ }
+ std::cout << "\n";
+
+ ModuleSplitting::Config config;
+ config.primaryFuncs = keptFuncs;
+ config.newExportPrefix = "%";
+ auto secondary = splitFunctions(*primary, config);
+
+ std::cout << "After:\n";
+ WasmPrinter::printModule(primary.get());
+ std::cout << "Secondary:\n";
+ WasmPrinter::printModule(secondary.get());
+ std::cout << "\n\n";
+
+ valid = validator.validate(*primary);
+ assert(valid && "after invalid!");
+ valid = validator.validate(*secondary);
+ assert(valid && "secondary invalid!");
+}
+
+int main() {
+ // Trivial module
+ do_test({}, "(module)");
+
+ // Global stuff
+ do_test({}, R"(
+ (module
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ ))");
+
+ // Imported global stuff
+ do_test({}, R"(
+ (module
+ (import "env" "mem" (memory $mem (shared 3 42)))
+ (import "env" "tab" (table $tab 3 42 funcref))
+ (import "env" "glob" (global $glob (mut i32)))
+ (import "env" "e" (event $e (attr 0) (param i32)))
+ ))");
+
+ // Exported global stuff
+ do_test({}, R"(
+ (module
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "mem" (memory $mem))
+ (export "tab" (table $tab))
+ (export "glob" (global $glob))
+ (export "e" (event $e))
+ ))");
+
+ // Non-deferred function
+ do_test({"foo"}, R"(
+ (module
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Non-deferred exported function
+ do_test({"foo"}, R"(
+ (module
+ (export "foo" (func $foo))
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Non-deferred function in table
+ do_test({"foo"}, R"(
+ (module
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Non-deferred imported function
+ do_test({"foo"}, R"(
+ (module
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ ))");
+
+ // Non-deferred exported imported function in table at a weird offset
+ do_test({"foo"}, R"(
+ (module
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+ ))");
+
+ // Deferred function
+ do_test({}, R"(
+ (module
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Deferred exported function
+ do_test({}, R"(
+ (module
+ (export "foo" (func $foo))
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Deferred function in table
+ do_test({}, R"(
+ (module
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Deferred exported function in table at a weird offset
+ do_test({}, R"(
+ (module
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+ (func $foo (param i32) (result i32)
+ (local.get 0)
+ )
+ ))");
+
+ // Non-deferred function calling non-deferred function
+ do_test({"foo", "bar"}, R"(
+ (module
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+ ))");
+
+ // Deferred function calling non-deferred function
+ do_test({"bar"}, R"(
+ (module
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+ ))");
+
+ // Non-deferred function calling deferred function
+ do_test({"foo"}, R"(
+ (module
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+ ))");
+
+ // Deferred function calling deferred function
+ do_test({}, R"(
+ (module
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+ ))");
+
+ // Deferred function calling non-deferred function with clashing export name
+ do_test({"foo"}, R"(
+ (module
+ (export "%foo" (func $bar))
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (call $foo)
+ )
+ ))");
+
+ // Mixed table 1
+ do_test({"bar", "quux"}, R"(
+ (module
+ (table $table 4 funcref)
+ (elem (i32.const 0) $foo $bar $baz $quux)
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (nop)
+ )
+ (func $baz
+ (nop)
+ )
+ (func $quux
+ (nop)
+ )
+ ))");
+
+ // Mixed table 2
+ do_test({"baz"}, R"(
+ (module
+ (table $table 4 funcref)
+ (elem (i32.const 0) $foo $bar $baz $quux)
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (nop)
+ )
+ (func $baz
+ (nop)
+ )
+ (func $quux
+ (nop)
+ )
+ ))");
+
+ // Mutual recursion with table growth
+ do_test({"foo"}, R"(
+ (module
+ (table $table 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param i32) (result i32)
+ (call $bar (i32.const 0))
+ )
+ (func $bar (param i32) (result i32)
+ (call $foo (i32.const 1))
+ )
+ ))");
+}
diff --git a/test/example/module-splitting.txt b/test/example/module-splitting.txt
new file mode 100644
index 000000000..4d79688f7
--- /dev/null
+++ b/test/example/module-splitting.txt
@@ -0,0 +1,641 @@
+Before:
+(module
+)
+Keeping: <none>
+After:
+(module
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "%memory" (memory $mem))
+ (export "%table" (table $tab))
+ (export "%global" (global $glob))
+ (export "%event" (event $e))
+)
+Secondary:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "primary" "%memory" (memory $mem (shared 3 42)))
+ (import "primary" "%table" (table $tab 3 42 funcref))
+ (import "primary" "%global" (global $glob (mut i32)))
+ (import "primary" "%event" (event $e (attr 0) (param i32)))
+)
+
+
+Before:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "mem" (memory $mem (shared 3 42)))
+ (import "env" "tab" (table $tab 3 42 funcref))
+ (import "env" "glob" (global $glob (mut i32)))
+ (import "env" "e" (event $e (attr 0) (param i32)))
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "mem" (memory $mem (shared 3 42)))
+ (import "env" "tab" (table $tab 3 42 funcref))
+ (import "env" "glob" (global $glob (mut i32)))
+ (import "env" "e" (event $e (attr 0) (param i32)))
+ (export "%memory" (memory $mem))
+ (export "%table" (table $tab))
+ (export "%global" (global $glob))
+ (export "%event" (event $e))
+)
+Secondary:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "primary" "%memory" (memory $mem (shared 3 42)))
+ (import "primary" "%table" (table $tab 3 42 funcref))
+ (import "primary" "%global" (global $glob (mut i32)))
+ (import "primary" "%event" (event $e (attr 0) (param i32)))
+)
+
+
+Before:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "mem" (memory $mem))
+ (export "tab" (table $tab))
+ (export "glob" (global $glob))
+ (export "e" (event $e))
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "mem" (memory $mem))
+ (export "tab" (table $tab))
+ (export "glob" (global $glob))
+ (export "e" (event $e))
+)
+Secondary:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "primary" "mem" (memory $mem (shared 3 42)))
+ (import "primary" "tab" (table $tab 3 42 funcref))
+ (import "primary" "glob" (global $glob (mut i32)))
+ (import "primary" "e" (event $e (attr 0) (param i32)))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (export "%table" (table $table))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Secondary:
+(module
+ (import "primary" "%table" (table $table 1 funcref))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+ (export "%table" (table $table))
+)
+Secondary:
+(module
+ (import "primary" "%table" (table $table 1000 funcref))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32)))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "foo" (func $foo))
+ (export "%table" (table $0))
+ (func $foo (param $0 i32) (result i32)
+ (call_indirect (type $i32_=>_i32)
+ (local.get $0)
+ (i32.const 0)
+ )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "%table" (table $table))
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 1 funcref))
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "42" (func $placeholder_42 (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $placeholder_42)
+ (export "foo" (func $foo))
+ (export "%table" (table $table))
+ (func $foo (param $0 i32) (result i32)
+ (call_indirect (type $i32_=>_i32)
+ (local.get $0)
+ (i32.const 42)
+ )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 1000 funcref))
+ (elem (i32.const 42) $foo)
+ (func $foo (param $0 i32) (result i32)
+ (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+)
+Keeping: bar, foo
+After:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+)
+Keeping: bar
+After:
+(module
+ (type $none_=>_none (func))
+ (export "%bar" (func $bar))
+ (func $bar
+ (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%bar" (func $bar))
+ (func $foo
+ (call $bar)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "%table" (table $0))
+ (func $foo
+ (call_indirect (type $none_=>_none)
+ (i32.const 0)
+ )
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $bar)
+ (func $bar
+ (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+ (call $bar)
+ )
+ (func $bar
+ (nop)
+ )
+)
+Keeping: <none>
+After:
+(module
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (func $bar
+ (nop)
+ )
+ (func $foo
+ (call $bar)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (export "%foo" (func $bar))
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (call $foo)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "%foo" (func $bar))
+ (export "%foo_0" (func $foo))
+ (export "%table" (table $0))
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (call_indirect (type $none_=>_none)
+ (i32.const 0)
+ )
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $bar)
+ (import "primary" "%foo_0" (func $foo))
+ (func $bar
+ (call $foo)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $foo $bar $baz $quux)
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (nop)
+ )
+ (func $baz
+ (nop)
+ )
+ (func $quux
+ (nop)
+ )
+)
+Keeping: bar, quux
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (import "placeholder" "2" (func $placeholder_2))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $placeholder_0 $bar $placeholder_2 $quux)
+ (export "%table" (table $table))
+ (func $bar
+ (nop)
+ )
+ (func $quux
+ (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 4 funcref))
+ (elem (i32.const 0) $foo)
+ (elem (i32.const 2) $baz)
+ (func $baz
+ (nop)
+ )
+ (func $foo
+ (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $foo $bar $baz $quux)
+ (func $foo
+ (nop)
+ )
+ (func $bar
+ (nop)
+ )
+ (func $baz
+ (nop)
+ )
+ (func $quux
+ (nop)
+ )
+)
+Keeping: baz
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (import "placeholder" "1" (func $placeholder_1))
+ (import "placeholder" "3" (func $placeholder_3))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $placeholder_0 $placeholder_1 $baz $placeholder_3)
+ (export "%table" (table $table))
+ (func $baz
+ (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 4 funcref))
+ (elem (i32.const 0) $foo $bar)
+ (elem (i32.const 3) $quux)
+ (func $bar
+ (nop)
+ )
+ (func $foo
+ (nop)
+ )
+ (func $quux
+ (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+ (call $bar
+ (i32.const 0)
+ )
+ )
+ (func $bar (param $0 i32) (result i32)
+ (call $foo
+ (i32.const 1)
+ )
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "1" (func $placeholder_1 (param i32) (result i32)))
+ (table $table 2 2 funcref)
+ (elem (i32.const 0) $foo $placeholder_1)
+ (export "%foo" (func $foo))
+ (export "%table" (table $table))
+ (func $foo (param $0 i32) (result i32)
+ (call_indirect (type $i32_=>_i32)
+ (i32.const 0)
+ (i32.const 1)
+ )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 2 2 funcref))
+ (elem (i32.const 1) $bar)
+ (import "primary" "%foo" (func $foo (param i32) (result i32)))
+ (func $bar (param $0 i32) (result i32)
+ (call $foo
+ (i32.const 1)
+ )
+ )
+)
+
+