diff options
-rwxr-xr-x | scripts/fuzz_opt.py | 6 | ||||
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/EncloseWorld.cpp | 155 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 37 | ||||
-rw-r--r-- | src/tools/wasm-reduce.cpp | 1 | ||||
-rw-r--r-- | test/lit/help/wasm-metadce.test | 3 | ||||
-rw-r--r-- | test/lit/help/wasm-opt.test | 3 | ||||
-rw-r--r-- | test/lit/help/wasm2js.test | 3 | ||||
-rw-r--r-- | test/lit/passes/enclose-world.wast | 237 | ||||
-rw-r--r-- | test/passes/fuzz_metrics_passes_noprint.bin.txt | 58 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 72 |
13 files changed, 497 insertions, 83 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index cd583e026..4fc92f367 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -225,6 +225,11 @@ def randomize_fuzz_settings(): # optimizations we use to create any other wasm file. FUZZ_OPTS += ['--dce'] + # Enclose the world much of the time when fuzzing closed-world, so that many + # types are private and hence optimizable. + if CLOSED_WORLD and random.random() < 0.5: + GEN_ARGS += ['--enclose-world'] + print('randomized settings (NaNs, OOB, legalize):', NANS, OOB, LEGALIZE) @@ -1790,6 +1795,7 @@ opt_choices = [ ("--dce",), ("--directize",), ("--discard-global-effects",), + ("--enclose-world",), ("--flatten", "--dfo",), ("--duplicate-function-elimination",), ("--flatten",), diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index e46163406..6b78e487d 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -35,6 +35,7 @@ set(passes_SOURCES DuplicateImportElimination.cpp DuplicateFunctionElimination.cpp DWARF.cpp + EncloseWorld.cpp ExtractFunction.cpp Flatten.cpp FuncCastEmulation.cpp diff --git a/src/passes/EncloseWorld.cpp b/src/passes/EncloseWorld.cpp new file mode 100644 index 000000000..5c6b70546 --- /dev/null +++ b/src/passes/EncloseWorld.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// "Closes" the world, in the sense of making it more compatible with the +// --closed-world flag, in a potentially destructive manner. This is mainly +// useful for fuzzing (in that a random module is usually very incomptable with +// closed world, with most types being public and hence unoptimizable, but +// running this pass makes as many as we can fully private). +// +// The fixup we do is to find references sent out/received in, and to +// externalize / internalize them. For example, this export: +// +// (func $refs (export "refs") (param $x (ref $X)) (result (ref $Y)) +// +// would have the following function exported in its place: +// +// (func $refs-closed (export "refs") (param $x externref) (result externref) +// (extern.convert_any +// (call $refs +// (ref.cast (ref $X) +// (any.convert_extern +// (local.get $x)))))) +// + +#include "ir/names.h" +#include "pass.h" +#include "wasm-builder.h" +#include "wasm.h" + +namespace wasm { + +namespace { + +struct EncloseWorld : public Pass { + void run(Module* module) override { + // Handle exports. + // TODO: Non-function exports. + std::vector<std::unique_ptr<Export>> newExports; + for (auto& ex : module->exports) { + if (ex->kind == ExternalKind::Function) { + auto* func = module->getFunction(ex->value); + // If this opens up types, replace it with an enclosed stub. + if (opensTypes(func)) { + auto stubName = makeStubStubForExport(func, module); + ex->value = stubName; + } + } + } + for (auto& ex : newExports) { + module->addExport(std::move(ex)); + } + + // TODO: Handle imports. + } + +private: + // Whether a type is an "open" ref, that is, a type that closed-world would + // consider to keep things public and prevent some amount of closed-world + // optimizations. + bool isOpenRef(Type t) { + // Only externref keeps things closed, and we must ignore things that + // cannot be converted to/from it (like funcrefs), so we can just check for + // the top type being any. + return t.isRef() && t.getHeapType().getTop() == HeapType::any; + } + + // Whether a function causes types to be open. + bool opensTypes(Function* func) { + for (const auto& param : func->getParams()) { + if (isOpenRef(param)) { + return true; + } + } + // TODO: Handle tuple results. + return isOpenRef(func->getResults()); + } + + // Make an enclosed stub function for an exported function, and return its + // name. + Name makeStubStubForExport(Function* func, Module* module) { + // Pick a valid name for the stub we are about to create. + auto stubName = Names::getValidFunctionName( + *module, std::string("stub$") + func->name.toString()); + + // Create the stub. + Builder builder(*module); + + // The stub's body is just a call to the original function, but with some + // conversions to/from externref. + std::vector<Expression*> params; + + auto externref = Type(HeapType::ext, Nullable); + + // Handle params. + std::vector<Type> stubParams; + for (const auto& param : func->getParams()) { + if (!isOpenRef(param)) { + // A normal parameter. Just pass it to the original function. + auto* get = builder.makeLocalGet(stubParams.size(), param); + params.push_back(get); + stubParams.push_back(param); + } else { + // A type we must fix up: receive as an externref and then internalize + // and cast before sending to the original function. + auto* get = builder.makeLocalGet(stubParams.size(), externref); + auto* interned = builder.makeRefAs(AnyConvertExtern, get); + // This cast may be trivial, but we leave it to the optimizer to remove. + auto* cast = builder.makeRefCast(interned, param); + params.push_back(cast); + stubParams.push_back(externref); + } + } + + auto* call = builder.makeCall(func->name, params, func->getResults()); + + // Generate the stub's type. + auto oldResults = func->getResults(); + Type resultsType = isOpenRef(oldResults) ? externref : oldResults; + auto type = Signature(Type(stubParams), resultsType); + + // Handle the results and make the body. + Expression* body; + if (!isOpenRef(oldResults)) { + // Just use the call. + body = call; + } else { + // Fix up the call's result. + body = builder.makeRefAs(ExternConvertAny, call); + } + + module->addFunction(builder.makeFunction(stubName, type, {}, body)); + + return stubName; + } +}; + +} // anonymous namespace + +Pass* createEncloseWorldPass() { return new EncloseWorld(); } + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 4be24cebf..7f6985e0f 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -159,6 +159,9 @@ void PassRegistry::registerPasses() { registerPass("emit-target-features", "emit the target features section in the output", createEmitTargetFeaturesPass); + registerPass("enclose-world", + "modify the wasm (destructively) for closed-world", + createEncloseWorldPass); registerPass("extract-function", "leaves just one function (useful for debugging)", createExtractFunctionPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index aadd26d41..b313b3431 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -46,6 +46,7 @@ Pass* createDWARFDumpPass(); Pass* createDuplicateImportEliminationPass(); Pass* createDuplicateFunctionEliminationPass(); Pass* createEmitTargetFeaturesPass(); +Pass* createEncloseWorldPass(); Pass* createExtractFunctionPass(); Pass* createExtractFunctionIndexPass(); Pass* createFlattenPass(); diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index ed653ef6b..135e50393 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -62,6 +62,17 @@ void TranslateToFuzzReader::pickPasses(OptimizationOptions& options) { // things like ClusterFuzz, where we are using Binaryen to fuzz other things // than itself). As a result, the list of passes here is different from // fuzz_opt.py. + + // Enclose the world, some of the time. We do this before picking any other + // passes so that we make the initial fuzz contents more optimizable by + // closed-world passes later. Note that we do this regardless of whether we + // are in closed-world mode or not, as it is good to get this variety + // regardless. + if (oneIn(2)) { + options.passes.push_back("enclose-world"); + } + + // Main selection of passes. while (options.passes.size() < 20 && !random.finished() && !oneIn(3)) { switch (upTo(42)) { case 0: @@ -1075,30 +1086,14 @@ Function* TranslateToFuzzReader::addFunction() { // Add hang limit checks after all other operations on the function body. wasm.addFunction(std::move(allocation)); // Export some functions, but not all (to allow inlining etc.). Try to export - // at least one, though, to keep each testcase interesting. Only functions - // with valid params and returns can be exported because the trap fuzzer - // depends on that (TODO: fix this). - auto validExportType = [](Type t) { - if (!t.isRef()) { - return true; - } - auto heapType = t.getHeapType(); - return heapType == HeapType::ext || heapType == HeapType::func || - heapType == HeapType::string; - }; + // at least one, though, to keep each testcase interesting. Avoid non- + // nullable params, as those cannot be constructed by the fuzzer on the + // outside. bool validExportParams = std::all_of(paramType.begin(), paramType.end(), [&](Type t) { - return validExportType(t) && t.isDefaultable(); + return t.isDefaultable(); }); - // Note: spec discussions around JS API integration are still ongoing, and it - // is not clear if we should allow nondefaultable types in exports or not - // (in imports, we cannot allow them in the fuzzer anyhow, since it can't - // construct such values in JS to send over to the wasm from the fuzzer - // harness). - bool validExportResults = - std::all_of(resultType.begin(), resultType.end(), validExportType); - if (validExportParams && validExportResults && - (numAddedFunctions == 0 || oneIn(2)) && + if (validExportParams && (numAddedFunctions == 0 || oneIn(2)) && !wasm.getExportOrNull(func->name)) { auto* export_ = new Export; export_->name = func->name; diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 8d9858b78..026825118 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -275,6 +275,7 @@ struct Reducer "--dae-optimizing", "--dce", "--duplicate-function-elimination", + "--enclose-world", "--gto", "--inlining", "--inlining-optimizing", diff --git a/test/lit/help/wasm-metadce.test b/test/lit/help/wasm-metadce.test index 4dc03883a..e44e51a16 100644 --- a/test/lit/help/wasm-metadce.test +++ b/test/lit/help/wasm-metadce.test @@ -143,6 +143,9 @@ ;; CHECK-NEXT: --emit-target-features emit the target features section ;; CHECK-NEXT: in the output ;; CHECK-NEXT: +;; CHECK-NEXT: --enclose-world modify the wasm (destructively) +;; CHECK-NEXT: for closed-world +;; CHECK-NEXT: ;; CHECK-NEXT: --extract-function leaves just one function (useful ;; CHECK-NEXT: for debugging) ;; CHECK-NEXT: diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index 62a30a770..5c978ee81 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -152,6 +152,9 @@ ;; CHECK-NEXT: --emit-target-features emit the target features section ;; CHECK-NEXT: in the output ;; CHECK-NEXT: +;; CHECK-NEXT: --enclose-world modify the wasm (destructively) +;; CHECK-NEXT: for closed-world +;; CHECK-NEXT: ;; CHECK-NEXT: --extract-function leaves just one function (useful ;; CHECK-NEXT: for debugging) ;; CHECK-NEXT: diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index e2a450bc8..c1dd0401d 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -106,6 +106,9 @@ ;; CHECK-NEXT: --emit-target-features emit the target features section ;; CHECK-NEXT: in the output ;; CHECK-NEXT: +;; CHECK-NEXT: --enclose-world modify the wasm (destructively) +;; CHECK-NEXT: for closed-world +;; CHECK-NEXT: ;; CHECK-NEXT: --extract-function leaves just one function (useful ;; CHECK-NEXT: for debugging) ;; CHECK-NEXT: diff --git a/test/lit/passes/enclose-world.wast b/test/lit/passes/enclose-world.wast new file mode 100644 index 000000000..0077c27be --- /dev/null +++ b/test/lit/passes/enclose-world.wast @@ -0,0 +1,237 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: foreach %s %t wasm-opt --enclose-world -all -S -o - | filecheck %s + +(module + ;; CHECK: (type $A (struct)) + (type $A (struct)) + ;; CHECK: (type $B (struct (field i32))) + (type $B (struct (field i32))) + ;; CHECK: (type $2 (func (param externref))) + + ;; CHECK: (type $3 (func (result externref))) + + ;; CHECK: (type $4 (func (param anyref) (result anyref))) + + ;; CHECK: (type $5 (func (param externref) (result externref))) + + ;; CHECK: (type $C (struct (field i32) (field f64))) + (type $C (struct (field i32 f64))) + + ;; CHECK: (type $7 (func (param i32) (result f64))) + + ;; CHECK: (type $8 (func (param anyref))) + + ;; CHECK: (type $9 (func (result anyref))) + + ;; CHECK: (type $10 (func (param (ref $A) (ref null $B)) (result (ref $C)))) + + ;; CHECK: (type $11 (func (param i32 (ref $A) funcref))) + + ;; CHECK: (type $12 (func (param externref externref) (result externref))) + + ;; CHECK: (type $13 (func (param i32 externref funcref))) + + ;; CHECK: (export "normal" (func $normal)) + + ;; CHECK: (export "externref-param" (func $externref-param)) + + ;; CHECK: (export "externref-result" (func $externref-result)) + + ;; CHECK: (export "anyref-param" (func $stub$anyref-param)) + + ;; CHECK: (export "anyref-result" (func $stub$anyref-result)) + + ;; CHECK: (export "anyref-both" (func $stub$anyref-both)) + + ;; CHECK: (export "anyref-both-dupe" (func $stub$anyref-both-dupe)) + + ;; CHECK: (export "many" (func $stub$many)) + + ;; CHECK: (export "mixed" (func $stub$mixed)) + + ;; CHECK: (func $normal (type $7) (param $x i32) (result f64) + ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: ) + (func $normal (export "normal") (param $x i32) (result f64) + ;; A normal function which we do not need to do anything with. + (f64.const 3.14159) + ) + + ;; CHECK: (func $externref-param (type $2) (param $x externref) + ;; CHECK-NEXT: ) + (func $externref-param (export "externref-param") (param $x externref) + ;; An externref param is fine, we don't need to do anything. + ) + + ;; CHECK: (func $externref-result (type $3) (result externref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $externref-result (export "externref-result") (result externref) + ;; An externref result is also fine. + (unreachable) + ) + + ;; CHECK: (func $anyref-param (type $8) (param $x anyref) + ;; CHECK-NEXT: ) + (func $anyref-param (export "anyref-param") (param $x anyref) + ;; An anyref requires a fixup. We will call this from a stub that has an + ;; externref param, which calls this. + ) + + ;; CHECK: (func $anyref-result (type $9) (result anyref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $anyref-result (export "anyref-result") (result anyref) + ;; An anyref result also requires a fixup. + (unreachable) + ) + + ;; CHECK: (func $anyref-both (type $4) (param $x anyref) (result anyref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $anyref-both (export "anyref-both") (param $x anyref) (result anyref) + ;; Here we must fix up both the param and the result. + (unreachable) + ) + + ;; CHECK: (func $anyref-both-dupe (type $4) (param $x anyref) (result anyref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $anyref-both-dupe (export "anyref-both-dupe") (param $x anyref) (result anyref) + ;; Identical to the above function, and should be fixed up in the same + ;; manner. In theory we could use the same stub for both, but we leave that + ;; for the optimizer. + (unreachable) + ) + + ;; CHECK: (func $many (type $10) (param $a (ref $A)) (param $b (ref null $B)) (result (ref $C)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $many (export "many") (param $a (ref $A)) (param $b (ref null $B)) (result (ref $C)) + ;; Various declared types are used, and must be fixed up. + (unreachable) + ) + + ;; CHECK: (func $mixed (type $11) (param $a i32) (param $b (ref $A)) (param $c funcref) + ;; CHECK-NEXT: ) + (func $mixed (export "mixed") (param $a i32) (param $b (ref $A)) (param $c funcref) + ;; One param needs to be fixed, two others do not: we can ignore i32 and + ;; funcref. + ) +) + +;; CHECK: (func $stub$anyref-param (type $2) (param $0 externref) +;; CHECK-NEXT: (call $anyref-param +;; CHECK-NEXT: (ref.cast anyref +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $stub$anyref-result (type $3) (result externref) +;; CHECK-NEXT: (extern.convert_any +;; CHECK-NEXT: (call $anyref-result) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $stub$anyref-both (type $5) (param $0 externref) (result externref) +;; CHECK-NEXT: (extern.convert_any +;; CHECK-NEXT: (call $anyref-both +;; CHECK-NEXT: (ref.cast anyref +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $stub$anyref-both-dupe (type $5) (param $0 externref) (result externref) +;; CHECK-NEXT: (extern.convert_any +;; CHECK-NEXT: (call $anyref-both-dupe +;; CHECK-NEXT: (ref.cast anyref +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $stub$many (type $12) (param $0 externref) (param $1 externref) (result externref) +;; CHECK-NEXT: (extern.convert_any +;; CHECK-NEXT: (call $many +;; CHECK-NEXT: (ref.cast (ref $A) +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (ref.cast (ref null $B) +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $1) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $stub$mixed (type $13) (param $0 i32) (param $1 externref) (param $2 funcref) +;; CHECK-NEXT: (call $mixed +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: (ref.cast (ref $A) +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $1) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (local.get $2) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +(module + ;; Two exports of a single function that needs fixups. We could reuse a + ;; single stub, but we leave that for the optimizer. + + (export "a" (func $anyref-both)) + + (export "b" (func $anyref-both)) + + ;; CHECK: (type $0 (func (param externref) (result externref))) + + ;; CHECK: (type $1 (func (param anyref) (result anyref))) + + ;; CHECK: (export "a" (func $stub$anyref-both)) + + ;; CHECK: (export "b" (func $stub$anyref-both_2)) + + ;; CHECK: (func $anyref-both (type $1) (param $x anyref) (result anyref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $anyref-both (param $x anyref) (result anyref) + (unreachable) + ) +) +;; CHECK: (func $stub$anyref-both (type $0) (param $0 externref) (result externref) +;; CHECK-NEXT: (extern.convert_any +;; CHECK-NEXT: (call $anyref-both +;; CHECK-NEXT: (ref.cast anyref +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $stub$anyref-both_2 (type $0) (param $0 externref) (result externref) +;; CHECK-NEXT: (extern.convert_any +;; CHECK-NEXT: (call $anyref-both +;; CHECK-NEXT: (ref.cast anyref +;; CHECK-NEXT: (any.convert_extern +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) diff --git a/test/passes/fuzz_metrics_passes_noprint.bin.txt b/test/passes/fuzz_metrics_passes_noprint.bin.txt index b4d67bab0..5e0dbfe07 100644 --- a/test/passes/fuzz_metrics_passes_noprint.bin.txt +++ b/test/passes/fuzz_metrics_passes_noprint.bin.txt @@ -1,35 +1,35 @@ Metrics total - [exports] : 23 - [funcs] : 34 - [globals] : 30 + [exports] : 50 + [funcs] : 64 + [globals] : 24 [imports] : 5 [memories] : 1 - [memory-data] : 17 - [table-data] : 6 + [memory-data] : 15 + [table-data] : 16 [tables] : 1 [tags] : 0 - [total] : 9415 - [vars] : 105 - Binary : 726 - Block : 1537 - Break : 331 - Call : 306 - CallIndirect : 10 - Const : 1479 - Drop : 83 - GlobalGet : 778 - GlobalSet : 584 - If : 531 - Load : 164 - LocalGet : 774 - LocalSet : 570 - Loop : 244 - Nop : 105 - RefFunc : 6 - Return : 94 - Select : 70 - Store : 86 - Switch : 2 - Unary : 654 - Unreachable : 281 + [total] : 6973 + [vars] : 223 + Binary : 534 + Block : 1168 + Break : 228 + Call : 282 + CallIndirect : 38 + Const : 1083 + Drop : 115 + GlobalGet : 580 + GlobalSet : 444 + If : 354 + Load : 113 + LocalGet : 501 + LocalSet : 367 + Loop : 148 + Nop : 99 + RefFunc : 16 + Return : 91 + Select : 53 + Store : 70 + Switch : 1 + Unary : 466 + Unreachable : 222 diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt index a77708b2e..8df9d033c 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,48 +1,54 @@ Metrics total - [exports] : 6 - [funcs] : 12 + [exports] : 9 + [funcs] : 10 [globals] : 4 [imports] : 8 [memories] : 1 [memory-data] : 112 - [table-data] : 3 + [table-data] : 2 [tables] : 1 - [tags] : 0 - [total] : 608 - [vars] : 48 - ArrayNew : 5 + [tags] : 1 + [total] : 682 + [vars] : 37 + ArrayLen : 1 + ArrayNew : 7 ArrayNewFixed : 5 - Binary : 75 - Block : 80 - BrOn : 5 - Break : 4 - Call : 21 - CallRef : 1 - Const : 113 + ArraySet : 1 + AtomicNotify : 1 + Binary : 79 + Block : 72 + BrOn : 4 + Break : 7 + Call : 19 + Const : 149 Drop : 15 - GlobalGet : 39 - GlobalSet : 36 - If : 21 - Load : 17 - LocalGet : 45 - LocalSet : 20 + GlobalGet : 35 + GlobalSet : 32 + If : 20 + Load : 20 + LocalGet : 55 + LocalSet : 26 Loop : 7 - Nop : 7 - RefAs : 2 + MemoryFill : 1 + Nop : 9 + Pop : 1 + RefAs : 1 + RefCast : 1 RefEq : 1 - RefFunc : 9 - RefI31 : 1 - RefIsNull : 1 + RefFunc : 17 + RefI31 : 2 + RefIsNull : 2 RefNull : 8 Return : 5 - Select : 2 + SIMDExtract : 3 Store : 1 - StringConst : 4 - StringEq : 1 - StringMeasure : 2 - StructNew : 13 - TupleExtract : 1 + StringConst : 3 + StringMeasure : 1 + StringWTF16Get : 1 + StructNew : 23 + Try : 1 + TupleExtract : 3 TupleMake : 4 - Unary : 19 - Unreachable : 18 + Unary : 23 + Unreachable : 16 |