diff options
-rw-r--r-- | src/passes/ExtractFunction.cpp | 79 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | test/lit/passes/extract-function.wast | 72 | ||||
-rw-r--r-- | test/passes/extract-function=foo.txt | 28 | ||||
-rw-r--r-- | test/passes/extract-function=foo.wast | 36 | ||||
-rw-r--r-- | test/passes/extract-function_pass-arg=extract-function@foo.txt | 28 | ||||
-rw-r--r-- | test/passes/extract-function_pass-arg=extract-function@foo.wast | 36 |
8 files changed, 127 insertions, 156 deletions
diff --git a/src/passes/ExtractFunction.cpp b/src/passes/ExtractFunction.cpp index ac3be9366..a219000c8 100644 --- a/src/passes/ExtractFunction.cpp +++ b/src/passes/ExtractFunction.cpp @@ -21,50 +21,73 @@ // order to remove as many things as possible. #include "pass.h" +#include "wasm-builder.h" #include "wasm.h" namespace wasm { +static void extract(PassRunner* runner, Module* module, Name name) { + std::cerr << "extracting " << name << "\n"; + bool found = false; + for (auto& func : module->functions) { + if (func->name != name) { + // Turn it into an import. + func->module = "env"; + func->base = func->name; + func->vars.clear(); + func->body = nullptr; + } else { + found = true; + } + } + if (!found) { + Fatal() << "could not find the function to extract\n"; + } + + // Leave just one export, for the thing we want. + module->exports.clear(); + module->addExport(Builder::makeExport(name, name, ExternalKind::Function)); + + // Remove unneeded things. + PassRunner postRunner(runner); + postRunner.add("remove-unused-module-elements"); + postRunner.setIsNested(true); + postRunner.run(); +} + struct ExtractFunction : public Pass { void run(PassRunner* runner, Module* module) override { Name name = runner->options.getArgument( "extract-function", "ExtractFunction usage: wasm-opt --extract-function=FUNCTION_NAME"); - std::cerr << "extracting " << name << "\n"; - bool found = false; - for (auto& func : module->functions) { - if (func->name != name) { - // Turn it into an import. - func->module = "env"; - func->base = func->name; - func->vars.clear(); - func->body = nullptr; - } else { - found = true; + extract(runner, module, name); + } +}; + +struct ExtractFunctionIndex : public Pass { + void run(PassRunner* runner, Module* module) override { + std::string index = + runner->options.getArgument("extract-function-index", + "ExtractFunctionIndex usage: wasm-opt " + "--extract-function-index=FUNCTION_INDEX"); + for (char c : index) { + if (!std::isdigit(c)) { + Fatal() << "Expected numeric function index"; } } - if (!found) { - Fatal() << "could not find the function to extract\n"; + Index i = std::stoi(index); + if (i >= module->functions.size()) { + Fatal() << "Invalid function index"; } - - // Leave just one export, for the thing we want. - module->exports.clear(); - auto* export_ = new Export; - export_->name = name; - export_->value = name; - export_->kind = ExternalKind::Function; - module->addExport(export_); - - // Remove unneeded things. - PassRunner postRunner(runner); - postRunner.add("remove-unused-module-elements"); - postRunner.setIsNested(true); - postRunner.run(); + // Assumes imports are at the beginning + Name name = module->functions[std::stoi(index)]->name; + extract(runner, module, name); } }; -// declare pass +// declare passes Pass* createExtractFunctionPass() { return new ExtractFunction(); } +Pass* createExtractFunctionIndexPass() { return new ExtractFunctionIndex(); } } // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 89b367272..10a688313 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -129,6 +129,9 @@ void PassRegistry::registerPasses() { registerPass("extract-function", "leaves just one function (useful for debugging)", createExtractFunctionPass); + registerPass("extract-function-index", + "leaves just one function selected by index", + createExtractFunctionIndexPass); registerPass( "flatten", "flattens out code, removing nesting", createFlattenPass); registerPass("fpcast-emu", diff --git a/src/passes/passes.h b/src/passes/passes.h index 4cc8040a4..5f265470d 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -42,6 +42,7 @@ Pass* createDuplicateImportEliminationPass(); Pass* createDuplicateFunctionEliminationPass(); Pass* createEmitTargetFeaturesPass(); Pass* createExtractFunctionPass(); +Pass* createExtractFunctionIndexPass(); Pass* createFlattenPass(); Pass* createFuncCastEmulationPass(); Pass* createFullPrinterPass(); diff --git a/test/lit/passes/extract-function.wast b/test/lit/passes/extract-function.wast new file mode 100644 index 000000000..1a8970598 --- /dev/null +++ b/test/lit/passes/extract-function.wast @@ -0,0 +1,72 @@ +;; RUN: foreach %s %t wasm-opt --extract-function=foo -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --extract-function --pass-arg=extract-function@foo -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --extract-function-index=0 -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --extract-function-index --pass-arg=extract-function-index@0 -S -o - | filecheck %s + +;; CHECK: (module +;; CHECK-NEXT: (type $none_=>_none (func)) +;; CHECK-NEXT: (import "env" "bar" (func $bar)) +;; CHECK-NEXT: (export "foo" (func $foo)) +;; CHECK-NEXT: (func $foo +;; CHECK-NEXT: (call $bar) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +(module + (func $foo + (call $bar) + ) + (func $bar + (call $foo) + ) + (func $other + (drop (i32.const 1)) + ) +) + +;; CHECK: (module +;; CHECK-NEXT: (type $none_=>_none (func)) +;; CHECK-NEXT: (import "env" "other" (func $other)) +;; CHECK-NEXT: (export "foo" (func $foo)) +;; CHECK-NEXT: (func $foo +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +(module + ;; Use another function in the table, but the table is not used in the + ;; extracted function + (table $t 10 funcref) + (elem $0 (table $t) (i32.const 0) func $other) + (func $foo + (nop) + ) + (func $other + (drop (i32.const 1)) + ) +) + +;; CHECK: (module +;; CHECK-NEXT: (type $none (func)) +;; CHECK-NEXT: (import "env" "other" (func $other)) +;; CHECK-NEXT: (table $t 10 funcref) +;; CHECK-NEXT: (elem $0 (i32.const 0) $other) +;; CHECK-NEXT: (export "foo" (func $foo)) +;; CHECK-NEXT: (func $foo +;; CHECK-NEXT: (call_indirect (type $none) +;; CHECK-NEXT: (i32.const 10) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +(module + ;; Use another function in the table, and the table *is* used. As a result, + ;; the table and its elements will remain. The called function, $other, will + ;; remain as an import that is placed in the table. + (type $none (func)) + (table $t 10 funcref) + (elem $0 (table $t) (i32.const 0) func $other) + (func $foo + (call_indirect (type $none) (i32.const 10)) + ) + (func $other + (drop (i32.const 1)) + ) +) diff --git a/test/passes/extract-function=foo.txt b/test/passes/extract-function=foo.txt deleted file mode 100644 index 3caf274c3..000000000 --- a/test/passes/extract-function=foo.txt +++ /dev/null @@ -1,28 +0,0 @@ -(module - (type $none_=>_none (func)) - (import "env" "bar" (func $bar)) - (export "foo" (func $foo)) - (func $foo - (call $bar) - ) -) -(module - (type $none_=>_none (func)) - (import "env" "other" (func $other)) - (export "foo" (func $foo)) - (func $foo - (nop) - ) -) -(module - (type $none (func)) - (import "env" "other" (func $other)) - (table $t 10 funcref) - (elem $0 (i32.const 0) $other) - (export "foo" (func $foo)) - (func $foo - (call_indirect (type $none) - (i32.const 10) - ) - ) -) diff --git a/test/passes/extract-function=foo.wast b/test/passes/extract-function=foo.wast deleted file mode 100644 index ab1d8b269..000000000 --- a/test/passes/extract-function=foo.wast +++ /dev/null @@ -1,36 +0,0 @@ -(module - (func $foo - (call $bar) - ) - (func $bar - (call $foo) - ) - (func $other - (drop (i32.const 1)) - ) -) -(module - ;; Use another function in the table, but the table is not used in the - ;; extracted function - (table $t 10 funcref) - (elem $0 (table $t) (i32.const 0) func $other) - (func $foo - ) - (func $other - (drop (i32.const 1)) - ) -) -(module - ;; Use another function in the table, and the table *is* used. As a result, - ;; the table and its elements will remain. The called function, $other, will - ;; remain as an import that is placed in the table. - (type $none (func)) - (table $t 10 funcref) - (elem $0 (table $t) (i32.const 0) func $other) - (func $foo - (call_indirect (type $none) (i32.const 10)) - ) - (func $other - (drop (i32.const 1)) - ) -) diff --git a/test/passes/extract-function_pass-arg=extract-function@foo.txt b/test/passes/extract-function_pass-arg=extract-function@foo.txt deleted file mode 100644 index 3caf274c3..000000000 --- a/test/passes/extract-function_pass-arg=extract-function@foo.txt +++ /dev/null @@ -1,28 +0,0 @@ -(module - (type $none_=>_none (func)) - (import "env" "bar" (func $bar)) - (export "foo" (func $foo)) - (func $foo - (call $bar) - ) -) -(module - (type $none_=>_none (func)) - (import "env" "other" (func $other)) - (export "foo" (func $foo)) - (func $foo - (nop) - ) -) -(module - (type $none (func)) - (import "env" "other" (func $other)) - (table $t 10 funcref) - (elem $0 (i32.const 0) $other) - (export "foo" (func $foo)) - (func $foo - (call_indirect (type $none) - (i32.const 10) - ) - ) -) diff --git a/test/passes/extract-function_pass-arg=extract-function@foo.wast b/test/passes/extract-function_pass-arg=extract-function@foo.wast deleted file mode 100644 index ab1d8b269..000000000 --- a/test/passes/extract-function_pass-arg=extract-function@foo.wast +++ /dev/null @@ -1,36 +0,0 @@ -(module - (func $foo - (call $bar) - ) - (func $bar - (call $foo) - ) - (func $other - (drop (i32.const 1)) - ) -) -(module - ;; Use another function in the table, but the table is not used in the - ;; extracted function - (table $t 10 funcref) - (elem $0 (table $t) (i32.const 0) func $other) - (func $foo - ) - (func $other - (drop (i32.const 1)) - ) -) -(module - ;; Use another function in the table, and the table *is* used. As a result, - ;; the table and its elements will remain. The called function, $other, will - ;; remain as an import that is placed in the table. - (type $none (func)) - (table $t 10 funcref) - (elem $0 (table $t) (i32.const 0) func $other) - (func $foo - (call_indirect (type $none) (i32.const 10)) - ) - (func $other - (drop (i32.const 1)) - ) -) |