From 5db98f48ba75f817ac7464e445186b52c9af9be2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 15:57:33 -0700 Subject: [PATCH 01/24] start --- src/pass.h | 22 ++++++++++++++++------ src/passes/pass.cpp | 30 +++++++++++++++++++++++------- src/wasm-features.h | 7 ++++++- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/pass.h b/src/pass.h index 0ebd7e6d6bd..9e9d837805a 100644 --- a/src/pass.h +++ b/src/pass.h @@ -324,18 +324,28 @@ struct PassRunner { // warning. void addIfNoDWARFIssues(std::string passName); - // Adds the default set of optimization passes; this is - // what -O does. - void addDefaultOptimizationPasses(); + // By default, we do not know if we are running first in the ordering of + // optimization passes, or last - we could be anywhere. + struct Ordering { + bool first = false; + bool last = false; + }; + static const UnknownOrdering; + + // Adds the default set of optimization passes; this is what -O does. + // + // The ordering indicates our position relative to other default + // optimizations, that is, if ordering.first then we are first. + void addDefaultOptimizationPasses(Ordering ordering = UnknownOrdering); // Adds the default optimization passes that work on // individual functions. - void addDefaultFunctionOptimizationPasses(); + void addDefaultFunctionOptimizationPasses(Ordering ordering = UnknownOrdering); // Adds the default optimization passes that work on // entire modules as a whole, and make sense to // run before function passes. - void addDefaultGlobalOptimizationPrePasses(); + void addDefaultGlobalOptimizationPrePasses(Ordering ordering = UnknownOrdering); // Adds the default optimization passes that work on // entire modules as a whole, and make sense to @@ -343,7 +353,7 @@ struct PassRunner { // This is run at the very end of the optimization // process - you can assume no other opts will be run // afterwards. - void addDefaultGlobalOptimizationPostPasses(); + void addDefaultGlobalOptimizationPostPasses(Ordering ordering = UnknownOrdering); // Run the passes on the module void run(); diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 2042bc71d3a..9324fe2b22f 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -605,13 +605,13 @@ void PassRunner::addIfNoDWARFIssues(std::string passName) { } } -void PassRunner::addDefaultOptimizationPasses() { - addDefaultGlobalOptimizationPrePasses(); - addDefaultFunctionOptimizationPasses(); - addDefaultGlobalOptimizationPostPasses(); +void PassRunner::addDefaultOptimizationPasses(Ordering ordering) { + addDefaultGlobalOptimizationPrePasses(ordering); + addDefaultFunctionOptimizationPasses(ordering); + addDefaultGlobalOptimizationPostPasses(ordering); } -void PassRunner::addDefaultFunctionOptimizationPasses() { +void PassRunner::addDefaultFunctionOptimizationPasses(Ordering ordering) { // All the additions here are optional if DWARF must be preserved. That is, // when DWARF is relevant we run fewer optimizations. // FIXME: support DWARF in all of them. @@ -723,7 +723,14 @@ void PassRunner::addDefaultFunctionOptimizationPasses() { addIfNoDWARFIssues("vacuum"); // just to be safe } -void PassRunner::addDefaultGlobalOptimizationPrePasses() { +void PassRunner::addDefaultGlobalOptimizationPrePasses(Ordering ordering) { + // If we are optimizing string builtins then we lift at the very start of the + // optimization pipeline, not just at the beginning here, but only when we are + // ordered before other bundles of passes. + if (wasm->features.hasStringBuiltins() && options.optimizeLevel >= 2 && + ordering.first) { + addIfNoDWARFIssues("string-lifting"); + } // Removing duplicate functions is fast and saves work later. addIfNoDWARFIssues("duplicate-function-elimination"); // Do a global cleanup before anything heavy, as it is fairly fast and can @@ -772,7 +779,7 @@ void PassRunner::add(std::string passName, std::optional passArg) { doAdd(std::move(pass)); } -void PassRunner::addDefaultGlobalOptimizationPostPasses() { +void PassRunner::addDefaultGlobalOptimizationPostPasses(Ordering ordering) { if (options.optimizeLevel >= 2 || options.shrinkLevel >= 1) { addIfNoDWARFIssues("dae-optimizing"); } @@ -794,6 +801,15 @@ void PassRunner::addDefaultGlobalOptimizationPostPasses() { } else { addIfNoDWARFIssues("simplify-globals"); } + + // Lower away strings at the very very end. We do this before + // remove-unused-module-elements so we don't add unused imports, and also + // before reorder-globals, which will sort the new globals. + if (wasm->features.hasStringBuiltins() && options.optimizeLevel >= 2 && + ordering.last) { + addIfNoDWARFIssues("string-lowering"); + } + addIfNoDWARFIssues("remove-unused-module-elements"); if (options.optimizeLevel >= 2 && wasm->features.hasStrings()) { // Gather strings to globals right before reorder-globals, which will then diff --git a/src/wasm-features.h b/src/wasm-features.h index a7c3ce0c4f5..f928f78445e 100644 --- a/src/wasm-features.h +++ b/src/wasm-features.h @@ -55,11 +55,12 @@ struct FeatureSet { // it does nothing. Binaryen always accepts LEB call-indirect encodings. CallIndirectOverlong = 1 << 20, CustomDescriptors = 1 << 21, + StringBuiltins = 1 << 22, MVP = None, // Keep in sync with llvm default features: // https://github.com/llvm/llvm-project/blob/c7576cb89d6c95f03968076e902d3adfd1996577/clang/lib/Basic/Targets/WebAssembly.cpp#L150-L153 Default = SignExt | MutableGlobals, - All = (1 << 22) - 1, + All = (1 << 23) - 1, }; static std::string toString(Feature f) { @@ -108,6 +109,8 @@ struct FeatureSet { return "call-indirect-overlong"; case CustomDescriptors: return "custom-descriptors"; + case StringBuiltins: + return "string-builtins"; case MVP: case Default: case All: @@ -168,6 +171,7 @@ struct FeatureSet { bool hasCustomDescriptors() const { return (features & CustomDescriptors) != 0; } + bool hasStringBuiltins() const { return (features & StringBuiltins) != 0; } bool hasAll() const { return (features & All) != 0; } void set(FeatureSet f, bool v = true) { @@ -194,6 +198,7 @@ struct FeatureSet { void setFP16(bool v = true) { set(FP16, v); } void setBulkMemoryOpt(bool v = true) { set(BulkMemoryOpt, v); } void setCustomDescriptors(bool v = true) { set(CustomDescriptors, v); } + void setStringBuiltins(bool v = true) { set(StringBuiltins, v); } void setMVP() { features = MVP; } void setAll() { features = All; } From 36d89d5c53fd4903076ba6c08b5aac9ed8e5f8e5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:01:01 -0700 Subject: [PATCH 02/24] work --- src/tools/optimization-options.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 333380d0490..cdd859a75d7 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -398,7 +398,21 @@ struct OptimizationOptions : public ToolOptions { passRunner.clear(); }; - for (auto& pass : passes) { + // Find the first and last default opt passes, so we can tell them they are + // first/last. + Index firstDefault = -1; + Index lastDefault = -1; + for (Index i = 0; i < passes.size(); i++) { + if (passes[i].name == DEFAULT_OPT_PASSES) { + if (firstDefault == -1) { + firstDefault = i; + } + lastDefault = i; + } + } + + for (Index i = 0; i < passes.size(); i++) { + auto& pass = passes[i]; if (pass.name == DEFAULT_OPT_PASSES) { // This is something like -O3 or -Oz. We must run this now, in order to // set the proper opt and shrink levels. To do that, first reset the @@ -416,8 +430,13 @@ struct OptimizationOptions : public ToolOptions { passRunner.options.optimizeLevel = *pass.optimizeLevel; passRunner.options.shrinkLevel = *pass.shrinkLevel; + // Note the ordering of these default passes. + PassRunner::Ordering ordering; + ordering.first = (i == firstDefault); + ordering.last = (i == lastDefault); + // Run our optimizations now with the custom levels. - passRunner.addDefaultOptimizationPasses(); + passRunner.addDefaultOptimizationPasses(ordering); flush(); // Restore the default optimize/shrinkLevels. From 956d45a0a02c096afe643c5322377139f58a88e4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:05:47 -0700 Subject: [PATCH 03/24] docs --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 19334a96662..8b20601788b 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,12 @@ There are a few differences between Binaryen IR and the WebAssembly language: extra size in rare cases (we avoid this overhead in the common case where the `br_if` value is unused). * Strings + * When the string builtins feature is enabled (`--enable-string=builtins`), + string operations are optimized. First, string imports are lifted into + stringref operations, before any default optimization passes. Those + stringref operations can then be optimized (e.g., a concat of constants + turns into a concatenated constant). When we are about to finish running + default optimizations, we lower stringref back into string builtins. * Binaryen allows string views (`stringview_wtf16` etc.) to be cast using `ref.cast`. This simplifies the IR, as it allows `ref.cast` to always be used in all places (and it is lowered to `ref.as_non_null` where possible From b72d7535574ac42a61fbc1a4ca903e87fb1953ab Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:10:33 -0700 Subject: [PATCH 04/24] p --- scripts/test/fuzzing.py | 6 +++++- test/lit/string-builtins.wast | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 test/lit/string-builtins.wast diff --git a/scripts/test/fuzzing.py b/scripts/test/fuzzing.py index 580bbb012b4..49c57e7ddd2 100644 --- a/scripts/test/fuzzing.py +++ b/scripts/test/fuzzing.py @@ -19,10 +19,14 @@ unfuzzable = [ # Float16 is still experimental. 'f16.wast', - # TODO: fuzzer and interpreter support for strings + # TODO: fuzzer and interpreter support for strings, including limitations + # like the fuzzer not handling (ref extern) imports (there is no way + # to create a replacement value) 'strings.wast', 'simplify-locals-strings.wast', 'string-lowering-instructions.wast', + 'O2_strings.wast', + 'O2_O3_strings.wast', # TODO: fuzzer and interpreter support for extern conversions 'extern-conversions.wast', # ignore DWARF because it is incompatible with multivalue atm diff --git a/test/lit/string-builtins.wast b/test/lit/string-builtins.wast new file mode 100644 index 00000000000..db7677109b4 --- /dev/null +++ b/test/lit/string-builtins.wast @@ -0,0 +1,28 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. + +;; Run normal -O2, which should lift, optimize, and lower strings, if the +;; string builtins feature is enabled. We optimize in the last two here. + +;; RUN: foreach %s %t wasm-opt -O2 -S -o - | filecheck %s --check-prefix=MVP +;; RUN: foreach %s %t wasm-opt -O2 -all -S -o - | filecheck %s --check-prefix=ALL +;; RUN: foreach %s %t wasm-opt -O2 --enable-string-builtins -S -o - | filecheck %s --check-prefix=ESB + +(module + (type $array16 (array (mut i16))) + + (import "\'" "foo" (global $foo (ref extern))) + + (import "\'" "bar" (global $bar (ref extern))) + + (import "wasm:js-string" "concat" (func $concat (param externref externref) (result (ref extern)))) + + (func $string.concat (export "string.concat") (result (ref extern)) + ;; When we optimize, we concatenate "foo" and "bar" here to "foobar". A new + ;; imported global will appear for that, and we will get it here. + (call $concat + (global.get $foo) + (global.get $bar) + ) + ) +) From 3b21cf2b34b4ed534e9d159b2e29322e38577f98 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:10:44 -0700 Subject: [PATCH 05/24] format --- src/pass.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pass.h b/src/pass.h index 9e9d837805a..73aef8c9baf 100644 --- a/src/pass.h +++ b/src/pass.h @@ -340,12 +340,14 @@ struct PassRunner { // Adds the default optimization passes that work on // individual functions. - void addDefaultFunctionOptimizationPasses(Ordering ordering = UnknownOrdering); + void + addDefaultFunctionOptimizationPasses(Ordering ordering = UnknownOrdering); // Adds the default optimization passes that work on // entire modules as a whole, and make sense to // run before function passes. - void addDefaultGlobalOptimizationPrePasses(Ordering ordering = UnknownOrdering); + void + addDefaultGlobalOptimizationPrePasses(Ordering ordering = UnknownOrdering); // Adds the default optimization passes that work on // entire modules as a whole, and make sense to @@ -353,7 +355,8 @@ struct PassRunner { // This is run at the very end of the optimization // process - you can assume no other opts will be run // afterwards. - void addDefaultGlobalOptimizationPostPasses(Ordering ordering = UnknownOrdering); + void + addDefaultGlobalOptimizationPostPasses(Ordering ordering = UnknownOrdering); // Run the passes on the module void run(); From adad0dc0091fe2cd67c9f78ed1d65fa8e51dbe85 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:20:06 -0700 Subject: [PATCH 06/24] work --- src/pass.h | 2 +- src/wasm-binary.h | 1 + src/wasm/wasm-binary.cpp | 2 ++ src/wasm/wasm.cpp | 1 + test/unit/test_features.py | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pass.h b/src/pass.h index 73aef8c9baf..9fb214df482 100644 --- a/src/pass.h +++ b/src/pass.h @@ -330,7 +330,7 @@ struct PassRunner { bool first = false; bool last = false; }; - static const UnknownOrdering; + static const Ordering UnknownOrdering; // Adds the default set of optimization passes; this is what -O does. // diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 5ee7452060a..c21590bd278 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -454,6 +454,7 @@ extern const char* FP16Feature; extern const char* BulkMemoryOptFeature; extern const char* CallIndirectOverlongFeature; extern const char* CustomDescriptorsFeature; +extern const char* StringBuiltinsFeature; enum Subsection { NameModule = 0, diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 4421a4f471c..7f76231ccb9 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1395,6 +1395,8 @@ void WasmBinaryWriter::writeFeaturesSection() { return BinaryConsts::CustomSections::CallIndirectOverlongFeature; case FeatureSet::CustomDescriptors: return BinaryConsts::CustomSections::CustomDescriptorsFeature; + case FeatureSet::StringBuiltins: + return BinaryConsts::CustomSections::StringBuiltinsFeature; case FeatureSet::None: case FeatureSet::Default: case FeatureSet::All: diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 655a3156382..6a96db33850 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -61,6 +61,7 @@ const char* FP16Feature = "fp16"; const char* BulkMemoryOptFeature = "bulk-memory-opt"; const char* CallIndirectOverlongFeature = "call-indirect-overlong"; const char* CustomDescriptorsFeature = "custom-descriptors"; +const char* StringBuiltinsFeature = "string-builtins"; } // namespace BinaryConsts::CustomSections diff --git a/test/unit/test_features.py b/test/unit/test_features.py index 2647ff84717..aede708dc67 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -453,4 +453,5 @@ def test_emit_all_features(self): '--enable-bulk-memory-opt', '--enable-call-indirect-overlong', '--enable-custom-descriptors', + '--enable-string-builtins', ], p2.stdout.splitlines()) From c6366855530b3b540b2bdbedf17e776208c3738f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:23:36 -0700 Subject: [PATCH 07/24] work --- src/pass.h | 6 +++--- src/tools/optimization-options.h | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/pass.h b/src/pass.h index 9fb214df482..5b255e6a6ad 100644 --- a/src/pass.h +++ b/src/pass.h @@ -327,10 +327,10 @@ struct PassRunner { // By default, we do not know if we are running first in the ordering of // optimization passes, or last - we could be anywhere. struct Ordering { - bool first = false; - bool last = false; + bool first; + bool last; }; - static const Ordering UnknownOrdering; + static constexpr Ordering UnknownOrdering = {false, false}; // Adds the default set of optimization passes; this is what -O does. // diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index cdd859a75d7..03ccc0fd53e 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -400,13 +400,11 @@ struct OptimizationOptions : public ToolOptions { // Find the first and last default opt passes, so we can tell them they are // first/last. - Index firstDefault = -1; - Index lastDefault = -1; + Index firstDefault = passes.size(); + Index lastDefault = passes.size(); for (Index i = 0; i < passes.size(); i++) { if (passes[i].name == DEFAULT_OPT_PASSES) { - if (firstDefault == -1) { - firstDefault = i; - } + firstDefault = std::min(firstDefault, i); lastDefault = i; } } From 7bf1cf721d0b3d9d96b6446bd8f517a859a412a5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:44:09 -0700 Subject: [PATCH 08/24] finish --- src/tools/tool-options.h | 2 ++ test/lit/help/wasm-as.test | 6 ++++ test/lit/help/wasm-ctor-eval.test | 6 ++++ test/lit/help/wasm-dis.test | 6 ++++ test/lit/help/wasm-emscripten-finalize.test | 6 ++++ test/lit/help/wasm-merge.test | 6 ++++ test/lit/help/wasm-metadce.test | 6 ++++ test/lit/help/wasm-opt.test | 6 ++++ test/lit/help/wasm-reduce.test | 6 ++++ test/lit/help/wasm-split.test | 6 ++++ test/lit/help/wasm2js.test | 6 ++++ test/lit/string-builtins.wast | 39 +++++++++++++++++++-- 12 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index 3c42b6b1f13..eec2dd30a50 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -108,6 +108,8 @@ struct ToolOptions : public Options { .addFeature(FeatureSet::FP16, "float 16 operations") .addFeature(FeatureSet::CustomDescriptors, "custom descriptors (RTTs) and exact references") + .addFeature(FeatureSet::StringBuiltins, + "string builtins (imported JS strings)") .add("--enable-typed-function-references", "", "Deprecated compatibility flag", diff --git a/test/lit/help/wasm-as.test b/test/lit/help/wasm-as.test index 77ae850e4df..f5d57fc46bb 100644 --- a/test/lit/help/wasm-as.test +++ b/test/lit/help/wasm-as.test @@ -134,6 +134,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-ctor-eval.test b/test/lit/help/wasm-ctor-eval.test index 9a5fbdcda26..60b1c175598 100644 --- a/test/lit/help/wasm-ctor-eval.test +++ b/test/lit/help/wasm-ctor-eval.test @@ -141,6 +141,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-dis.test b/test/lit/help/wasm-dis.test index a10b41a4f3c..b2ca9cfbc15 100644 --- a/test/lit/help/wasm-dis.test +++ b/test/lit/help/wasm-dis.test @@ -127,6 +127,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-emscripten-finalize.test b/test/lit/help/wasm-emscripten-finalize.test index 4cb9ef940a0..06f5bc556b2 100644 --- a/test/lit/help/wasm-emscripten-finalize.test +++ b/test/lit/help/wasm-emscripten-finalize.test @@ -169,6 +169,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-merge.test b/test/lit/help/wasm-merge.test index a8b95194950..25dbc0723ba 100644 --- a/test/lit/help/wasm-merge.test +++ b/test/lit/help/wasm-merge.test @@ -157,6 +157,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-metadce.test b/test/lit/help/wasm-metadce.test index 5870b5c9d45..c4ba77e67a6 100644 --- a/test/lit/help/wasm-metadce.test +++ b/test/lit/help/wasm-metadce.test @@ -787,6 +787,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors ;; CHECK-NEXT: (RTTs) and exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported +;; CHECK-NEXT: JS strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins +;; CHECK-NEXT: (imported JS strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index ac98198d2dd..cdc91c15333 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -799,6 +799,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors ;; CHECK-NEXT: (RTTs) and exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported +;; CHECK-NEXT: JS strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins +;; CHECK-NEXT: (imported JS strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-reduce.test b/test/lit/help/wasm-reduce.test index 2739394e3ed..739388333c8 100644 --- a/test/lit/help/wasm-reduce.test +++ b/test/lit/help/wasm-reduce.test @@ -217,6 +217,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm-split.test b/test/lit/help/wasm-split.test index 095c66047ac..abcc9607482 100644 --- a/test/lit/help/wasm-split.test +++ b/test/lit/help/wasm-split.test @@ -266,6 +266,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors (RTTs) and ;; CHECK-NEXT: exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins (imported JS +;; CHECK-NEXT: strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index ac68667554b..ec69865fa22 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -751,6 +751,12 @@ ;; CHECK-NEXT: --disable-custom-descriptors Disable custom descriptors ;; CHECK-NEXT: (RTTs) and exact references ;; CHECK-NEXT: +;; CHECK-NEXT: --enable-string-builtins Enable string builtins (imported +;; CHECK-NEXT: JS strings) +;; CHECK-NEXT: +;; CHECK-NEXT: --disable-string-builtins Disable string builtins +;; CHECK-NEXT: (imported JS strings) +;; CHECK-NEXT: ;; CHECK-NEXT: --enable-typed-function-references Deprecated compatibility flag ;; CHECK-NEXT: ;; CHECK-NEXT: --disable-typed-function-references Deprecated compatibility flag diff --git a/test/lit/string-builtins.wast b/test/lit/string-builtins.wast index db7677109b4..b30d56e8d1e 100644 --- a/test/lit/string-builtins.wast +++ b/test/lit/string-builtins.wast @@ -4,19 +4,52 @@ ;; Run normal -O2, which should lift, optimize, and lower strings, if the ;; string builtins feature is enabled. We optimize in the last two here. -;; RUN: foreach %s %t wasm-opt -O2 -S -o - | filecheck %s --check-prefix=MVP -;; RUN: foreach %s %t wasm-opt -O2 -all -S -o - | filecheck %s --check-prefix=ALL -;; RUN: foreach %s %t wasm-opt -O2 --enable-string-builtins -S -o - | filecheck %s --check-prefix=ESB +;; RUN: foreach %s %t wasm-opt -O2 --enable-reference-types -S -o - | filecheck %s --check-prefix=MVP +;; RUN: foreach %s %t wasm-opt -O2 -all -S -o - | filecheck %s --check-prefix=ALL +;; RUN: foreach %s %t wasm-opt -O2 --enable-reference-types --enable-string-builtins -S -o - | filecheck %s --check-prefix=ESB (module (type $array16 (array (mut i16))) + ;; MVP: (type $0 (func (param externref externref) (result (ref extern)))) + + ;; MVP: (type $1 (func (result (ref extern)))) + + ;; MVP: (import "\'" "foo" (global $foo (ref extern))) (import "\'" "foo" (global $foo (ref extern))) + ;; MVP: (import "\'" "bar" (global $bar (ref extern))) (import "\'" "bar" (global $bar (ref extern))) + ;; MVP: (import "wasm:js-string" "concat" (func $concat (param externref externref) (result (ref extern)))) (import "wasm:js-string" "concat" (func $concat (param externref externref) (result (ref extern)))) + ;; MVP: (export "string.concat" (func $string.concat)) + + ;; MVP: (func $string.concat (result (ref extern)) + ;; MVP-NEXT: (call $concat + ;; MVP-NEXT: (global.get $foo) + ;; MVP-NEXT: (global.get $bar) + ;; MVP-NEXT: ) + ;; MVP-NEXT: ) + ;; ALL: (type $0 (func (result (ref extern)))) + + ;; ALL: (import "string.const" "0" (global $"string.const_\"foobar\"" (ref extern))) + + ;; ALL: (export "string.concat" (func $string.concat)) + + ;; ALL: (func $string.concat (type $0) (result (ref extern)) + ;; ALL-NEXT: (global.get $"string.const_\"foobar\"") + ;; ALL-NEXT: ) + ;; ESB: (type $0 (func (result (ref extern)))) + + ;; ESB: (import "string.const" "0" (global $"string.const_\"foobar\"" (ref extern))) + + ;; ESB: (export "string.concat" (func $string.concat)) + + ;; ESB: (func $string.concat (result (ref extern)) + ;; ESB-NEXT: (global.get $"string.const_\"foobar\"") + ;; ESB-NEXT: ) (func $string.concat (export "string.concat") (result (ref extern)) ;; When we optimize, we concatenate "foo" and "bar" here to "foobar". A new ;; imported global will appear for that, and we will get it here. From 48f05f79c3ecd4c2b4db58e2d67569e9e5ddfbb0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:54:12 -0700 Subject: [PATCH 09/24] test --- test/unit/test_passes.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unit/test_passes.py b/test/unit/test_passes.py index 838f1d2f73f..d9753fbaae4 100644 --- a/test/unit/test_passes.py +++ b/test/unit/test_passes.py @@ -61,3 +61,18 @@ def test_O3_O1(self): self.assertNotIn(PASS_IN_O3_ONLY, self.get_passes_run(['-O1'])) self.assertNotIn(PASS_IN_O3_ONLY, self.get_passes_run(['-O1', '-O1'])) + + def test_string_builtins(self): + # When we enable string builtins, we lift early and lower late, and + # only do each once even if there are multiple -O2 operations. + passes = self.get_passes_run(['-O2', '-O2', '-all']) + self.assertEqual(passes.count('string-lifting'), 1) + self.assertEqual(passes.count('string-lowering'), 1) + + # Other passes appear twice or more. + self.assertGreater(passes.count('precompute'), 1) + + # Without the feature, we do not lift or lower. + passes = self.get_passes_run(['-O2', '-O2', '-all', '--disable-string-builtins']) + self.assertEqual(passes.count('string-lifting'), 0) + self.assertEqual(passes.count('string-lowering'), 0) From 60637f9a0348348094860468614b668bfc095870 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:57:04 -0700 Subject: [PATCH 10/24] test --- scripts/test/fuzzing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/test/fuzzing.py b/scripts/test/fuzzing.py index 9b6492a8d29..8f84ae3fc00 100644 --- a/scripts/test/fuzzing.py +++ b/scripts/test/fuzzing.py @@ -25,8 +25,7 @@ 'strings.wast', 'simplify-locals-strings.wast', 'string-lowering-instructions.wast', - 'O2_strings.wast', - 'O2_O3_strings.wast', + 'string-builtins.wast', # TODO: fuzzer and interpreter support for extern conversions 'extern-conversions.wast', # ignore DWARF because it is incompatible with multivalue atm From 3195ac24fcaff951582e9ebe7affb654175cdc53 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 16:59:02 -0700 Subject: [PATCH 11/24] test --- test/lit/string-builtins.wast | 1 - 1 file changed, 1 deletion(-) diff --git a/test/lit/string-builtins.wast b/test/lit/string-builtins.wast index b30d56e8d1e..0ce0f4b234d 100644 --- a/test/lit/string-builtins.wast +++ b/test/lit/string-builtins.wast @@ -1,5 +1,4 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. -;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. ;; Run normal -O2, which should lift, optimize, and lower strings, if the ;; string builtins feature is enabled. We optimize in the last two here. From 4dd6747e860b40281209787647a5a12bd376e7c9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 May 2025 17:00:30 -0700 Subject: [PATCH 12/24] test --- test/unit/test_passes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/test_passes.py b/test/unit/test_passes.py index d9753fbaae4..446ed377ab7 100644 --- a/test/unit/test_passes.py +++ b/test/unit/test_passes.py @@ -69,8 +69,8 @@ def test_string_builtins(self): self.assertEqual(passes.count('string-lifting'), 1) self.assertEqual(passes.count('string-lowering'), 1) - # Other passes appear twice or more. - self.assertGreater(passes.count('precompute'), 1) + # Other passes appear twice, when -O2 is repeated + self.assertEqual(passes.count('directize'), 2) # Without the feature, we do not lift or lower. passes = self.get_passes_run(['-O2', '-O2', '-all', '--disable-string-builtins']) From 3c29e7bbf8ca9739af7a4b68b5c7b882b42996e3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 May 2025 07:51:17 -0700 Subject: [PATCH 13/24] use magic imports [ci skip] --- src/passes/pass.cpp | 2 +- test/lit/string-builtins.wast | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 9324fe2b22f..d335590c76b 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -807,7 +807,7 @@ void PassRunner::addDefaultGlobalOptimizationPostPasses(Ordering ordering) { // before reorder-globals, which will sort the new globals. if (wasm->features.hasStringBuiltins() && options.optimizeLevel >= 2 && ordering.last) { - addIfNoDWARFIssues("string-lowering"); + addIfNoDWARFIssues("string-lowering-magic-imports"); } addIfNoDWARFIssues("remove-unused-module-elements"); diff --git a/test/lit/string-builtins.wast b/test/lit/string-builtins.wast index 0ce0f4b234d..68a82f48d08 100644 --- a/test/lit/string-builtins.wast +++ b/test/lit/string-builtins.wast @@ -33,7 +33,7 @@ ;; MVP-NEXT: ) ;; ALL: (type $0 (func (result (ref extern)))) - ;; ALL: (import "string.const" "0" (global $"string.const_\"foobar\"" (ref extern))) + ;; ALL: (import "\'" "foobar" (global $"string.const_\"foobar\"" (ref extern))) ;; ALL: (export "string.concat" (func $string.concat)) @@ -42,7 +42,7 @@ ;; ALL-NEXT: ) ;; ESB: (type $0 (func (result (ref extern)))) - ;; ESB: (import "string.const" "0" (global $"string.const_\"foobar\"" (ref extern))) + ;; ESB: (import "\'" "foobar" (global $"string.const_\"foobar\"" (ref extern))) ;; ESB: (export "string.concat" (func $string.concat)) From bbd680434c14e592e56fc3b9b4cd2dead2eca8f3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 May 2025 12:49:36 -0700 Subject: [PATCH 14/24] gate the pass behind GC --- src/passes/pass.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index d335590c76b..4a8b87f6484 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -727,8 +727,11 @@ void PassRunner::addDefaultGlobalOptimizationPrePasses(Ordering ordering) { // If we are optimizing string builtins then we lift at the very start of the // optimization pipeline, not just at the beginning here, but only when we are // ordered before other bundles of passes. - if (wasm->features.hasStringBuiltins() && options.optimizeLevel >= 2 && - ordering.first) { + // + // We check for GC for symmetry with the lowering pass, see comment in + // addDefaultGlobalOptimizationPostPasses() below. + if (wasm->features.hasStringBuiltins() && wasm->features.hasGC() && + options.optimizeLevel >= 2 && ordering.first) { addIfNoDWARFIssues("string-lifting"); } // Removing duplicate functions is fast and saves work later. @@ -805,8 +808,13 @@ void PassRunner::addDefaultGlobalOptimizationPostPasses(Ordering ordering) { // Lower away strings at the very very end. We do this before // remove-unused-module-elements so we don't add unused imports, and also // before reorder-globals, which will sort the new globals. - if (wasm->features.hasStringBuiltins() && options.optimizeLevel >= 2 && - ordering.last) { + // + // Note we also test for GC here, as the pass adds imports that use GC arrays + // (and externref). Those imports may be unused, but they exist until + // remove-unused-module-elements cleans them up, which would cause an error in + // between. + if (wasm->features.hasStringBuiltins() && wasm->features.hasGC() && + options.optimizeLevel >= 2 && ordering.last) { addIfNoDWARFIssues("string-lowering-magic-imports"); } From 2e82f9a1e95bc96950572aac836b96791c3f534e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 May 2025 12:50:13 -0700 Subject: [PATCH 15/24] update test --- ...rip-target-features_roundtrip_print-features_all-features.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/passes/strip-target-features_roundtrip_print-features_all-features.txt b/test/passes/strip-target-features_roundtrip_print-features_all-features.txt index 34976434e9d..2f012471e1e 100644 --- a/test/passes/strip-target-features_roundtrip_print-features_all-features.txt +++ b/test/passes/strip-target-features_roundtrip_print-features_all-features.txt @@ -20,6 +20,7 @@ --enable-bulk-memory-opt --enable-call-indirect-overlong --enable-custom-descriptors +--enable-string-builtins (module (type $0 (func (result v128 externref))) (func $foo (type $0) (result v128 externref) From 0feeeae31a59b198a6bb544c806505233c223853 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 May 2025 12:51:20 -0700 Subject: [PATCH 16/24] work --- test/binaryen.js/kitchen-sink.js.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 45c7417dcda..b9fdf381739 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -33,7 +33,7 @@ Features.RelaxedSIMD: 4096 Features.ExtendedConst: 8192 Features.Strings: 16384 Features.MultiMemory: 32768 -Features.All: 4194303 +Features.All: 8388607 InvalidId: 0 BlockId: 1 IfId: 2 From 02d1d233bcf1bfc04123e2277e38853f7ad7a066 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 May 2025 13:14:17 -0700 Subject: [PATCH 17/24] update exact result in test, likely because of the new pass we run --- test/reduce/gc.wast.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/reduce/gc.wast.txt b/test/reduce/gc.wast.txt index 3af5287ce99..e19d3da34ac 100644 --- a/test/reduce/gc.wast.txt +++ b/test/reduce/gc.wast.txt @@ -1,7 +1,7 @@ (module (type $0 (struct (field (mut i32)) (field funcref))) (type $1 (func (result i32))) - (global $global$0 (ref null $0) (struct.new_default $0)) + (global $global$0 (ref (exact $0)) (struct.new_default $0)) (export "use-global" (func $0)) (func $0 (result i32) (struct.set $0 0 From 57ac595a3a66030c14811da8b9f3dac4b7c67edf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 May 2025 13:40:19 -0700 Subject: [PATCH 18/24] so many tests to update --- test/example/c-api-kitchen-sink.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index 1b798654d1a..1839597deca 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -47,7 +47,7 @@ BinaryenFeatureMemory64: 2048 BinaryenFeatureRelaxedSIMD: 4096 BinaryenFeatureExtendedConst: 8192 BinaryenFeatureStrings: 16384 -BinaryenFeatureAll: 4194303 +BinaryenFeatureAll: 8388607 (f32.neg (f32.const -33.61199951171875) ) From 00b3c1b1e0cd138406e1cbba5bc581823f5ae9d2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 May 2025 07:33:37 -0700 Subject: [PATCH 19/24] fix feature reading --- src/wasm/wasm-binary.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 7f76231ccb9..228b480cf8e 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -5195,6 +5195,8 @@ void WasmBinaryReader::readFeatures(size_t payloadLen) { feature = FeatureSet::FP16; } else if (name == BinaryConsts::CustomSections::CustomDescriptorsFeature) { feature = FeatureSet::CustomDescriptors; + } else if (name == BinaryConsts::CustomSections::StringBuiltinsFeature) { + feature = FeatureSet::StringBuiltins; } else { // Silently ignore unknown features (this may be and old binaryen running // on a new wasm). From 123b8795a4e8a36db515cc7ec23bad111e2f723d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 May 2025 07:40:19 -0700 Subject: [PATCH 20/24] fix unit test --- test/unit/test_passes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/test_passes.py b/test/unit/test_passes.py index 446ed377ab7..ac05419c234 100644 --- a/test/unit/test_passes.py +++ b/test/unit/test_passes.py @@ -67,7 +67,7 @@ def test_string_builtins(self): # only do each once even if there are multiple -O2 operations. passes = self.get_passes_run(['-O2', '-O2', '-all']) self.assertEqual(passes.count('string-lifting'), 1) - self.assertEqual(passes.count('string-lowering'), 1) + self.assertEqual(passes.count('string-lowering-magic-imports'), 1) # Other passes appear twice, when -O2 is repeated self.assertEqual(passes.count('directize'), 2) @@ -75,4 +75,4 @@ def test_string_builtins(self): # Without the feature, we do not lift or lower. passes = self.get_passes_run(['-O2', '-O2', '-all', '--disable-string-builtins']) self.assertEqual(passes.count('string-lifting'), 0) - self.assertEqual(passes.count('string-lowering'), 0) + self.assertEqual(passes.count('string-lowering-magic-imports'), 0) From dfa52310d6afb9291498a5a76ad0e0e739d3dcaa Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 May 2025 09:02:22 -0700 Subject: [PATCH 21/24] gc is needed too, now, for string optimization --- README.md | 4 +++- test/lit/string-builtins.wast | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0f48cf7c838..3400c755c99 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,9 @@ There are a few differences between Binaryen IR and the WebAssembly language: stringref operations, before any default optimization passes. Those stringref operations can then be optimized (e.g., a concat of constants turns into a concatenated constant). When we are about to finish running - default optimizations, we lower stringref back into string builtins. + default optimizations, we lower stringref back into string builtins. (Note: + reference types and GC must also be enabled, as imported string operations + depend on GC arrays.) As a result, you might notice that round-trip conversions (wasm => Binaryen IR => wasm) change code a little in some corner cases. diff --git a/test/lit/string-builtins.wast b/test/lit/string-builtins.wast index 68a82f48d08..37800cea760 100644 --- a/test/lit/string-builtins.wast +++ b/test/lit/string-builtins.wast @@ -1,11 +1,18 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; Run normal -O2, which should lift, optimize, and lower strings, if the -;; string builtins feature is enabled. We optimize in the last two here. +;; string builtins feature is enabled (GC is required, as well, as the lowering +;; emits functions using arrays). We optimize in the last two here. -;; RUN: foreach %s %t wasm-opt -O2 --enable-reference-types -S -o - | filecheck %s --check-prefix=MVP -;; RUN: foreach %s %t wasm-opt -O2 -all -S -o - | filecheck %s --check-prefix=ALL -;; RUN: foreach %s %t wasm-opt -O2 --enable-reference-types --enable-string-builtins -S -o - | filecheck %s --check-prefix=ESB +;; RUN: foreach %s %t wasm-opt -O2 -S -o - --enable-reference-types \ +;; RUN: | filecheck %s --check-prefix=MVP + +;; RUN: foreach %s %t wasm-opt -O2 -S -o - -all \ +;; RUN: | filecheck %s --check-prefix=ALL + +;; RUN: foreach %s %t wasm-opt -O2 -S -o - --enable-reference-types \ +;; RUN: --enable-string-builtins --enable-gc \ +;; RUN: | filecheck %s --check-prefix=ESB (module (type $array16 (array (mut i16))) @@ -46,7 +53,7 @@ ;; ESB: (export "string.concat" (func $string.concat)) - ;; ESB: (func $string.concat (result (ref extern)) + ;; ESB: (func $string.concat (type $0) (result (ref extern)) ;; ESB-NEXT: (global.get $"string.const_\"foobar\"") ;; ESB-NEXT: ) (func $string.concat (export "string.concat") (result (ref extern)) From 77b7f6ed7efeded4443d33afc27521aaf5948c39 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 May 2025 09:02:25 -0700 Subject: [PATCH 22/24] fix: some tests have type updates due to another pass being run --- test/lit/basic/extra-branch-values.wast | 118 ++++++++++++------------ test/lit/passes/O3_stack-switching.wast | 4 +- test/lit/passes/gto_and_cfp_in_O.wast | 9 +- 3 files changed, 66 insertions(+), 65 deletions(-) diff --git a/test/lit/basic/extra-branch-values.wast b/test/lit/basic/extra-branch-values.wast index 6989bf62ca9..990a60a9ae6 100644 --- a/test/lit/basic/extra-branch-values.wast +++ b/test/lit/basic/extra-branch-values.wast @@ -28,10 +28,10 @@ (import "env" "use-i32-any" (func $use-i32-any (param i32 (ref any)))) ;; CHECK: (tag $e (type $7) (param i32)) - ;; OPT_O: (tag $e (type $5) (param i32)) + ;; OPT_O: (tag $e (type $9) (param i32)) (tag $e (param i32)) ;; CHECK: (tag $e2 (type $7) (param i32)) - ;; OPT_O: (tag $e2 (type $5) (param i32)) + ;; OPT_O: (tag $e2 (type $9) (param i32)) (tag $e2 (param i32)) ;; CHECK: (func $br_on_null-one (type $8) (param $0 i32) (param $1 anyref) (result i32) @@ -76,7 +76,7 @@ ;; CHECK-NEXT: (local.get $scratch_3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_null-one (type $6) (param $0 i32) (param $1 anyref) (result i32) + ;; OPT_O: (func $br_on_null-one (type $10) (param $0 i32) (param $1 anyref) (result i32) ;; OPT_O-NEXT: (block $block (result i32) ;; OPT_O-NEXT: (block $block0 ;; OPT_O-NEXT: (global.set $any @@ -168,7 +168,7 @@ ;; CHECK-NEXT: ) ;; OPT_O: (func $br_on_null-two (type $16) (param $0 i32) (param $1 i64) (param $2 anyref) (result i32 i64) ;; OPT_O-NEXT: (local $3 (tuple i32 i64)) - ;; OPT_O-NEXT: (block $block (type $11) (result i32 i64) + ;; OPT_O-NEXT: (block $block (type $8) (result i32 i64) ;; OPT_O-NEXT: (local.set $3 ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) @@ -254,8 +254,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_non_null-one (type $7) (param $0 i32) (param $1 anyref) (result i32 (ref any)) - ;; OPT_O-NEXT: (block $block (type $1) (result i32 (ref any)) + ;; OPT_O: (func $br_on_non_null-one (type $11) (param $0 i32) (param $1 anyref) (result i32 (ref any)) + ;; OPT_O-NEXT: (block $block (type $7) (result i32 (ref any)) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result (ref any)) @@ -350,8 +350,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_non_null-two (type $8) (param $0 i32) (param $1 i64) (param $2 anyref) (result i32 i64 (ref any)) - ;; OPT_O-NEXT: (block $block (type $4) (result i32 i64 (ref any)) + ;; OPT_O: (func $br_on_non_null-two (type $12) (param $0 i32) (param $1 i64) (param $2 anyref) (result i32 i64 (ref any)) + ;; OPT_O-NEXT: (block $block (type $6) (result i32 i64 (ref any)) ;; OPT_O-NEXT: (tuple.make 3 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (local.get $1) @@ -441,8 +441,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_cast-one (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $block (type $0) (result i32 eqref) + ;; OPT_O: (func $br_on_cast-one (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $block (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result eqref) @@ -550,7 +550,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; OPT_O: (func $br_on_cast-two (type $17) (param $0 i32) (param $1 i64) (param $2 anyref) (result i32 i64 eqref) - ;; OPT_O-NEXT: (block $block (type $12) (result i32 i64 eqref) + ;; OPT_O-NEXT: (block $block (type $4) (result i32 i64 eqref) ;; OPT_O-NEXT: (tuple.make 3 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (local.get $1) @@ -644,7 +644,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; OPT_O: (func $br_on_cast-nn (type $18) (param $0 i32) (param $1 (ref any)) (result i32 (ref eq)) - ;; OPT_O-NEXT: (block $block (type $2) (result i32 (ref eq)) + ;; OPT_O-NEXT: (block $block (type $3) (result i32 (ref eq)) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result (ref eq)) @@ -730,7 +730,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; OPT_O: (func $br_on_cast-to-nn (type $19) (param $0 i32) (param $1 anyref) (result i32 (ref eq)) - ;; OPT_O-NEXT: (block $block (type $2) (result i32 (ref eq)) + ;; OPT_O-NEXT: (block $block (type $3) (result i32 (ref eq)) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result (ref eq)) @@ -815,8 +815,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_cast_fail-one (type $7) (param $0 i32) (param $1 anyref) (result i32 (ref any)) - ;; OPT_O-NEXT: (block $block (type $1) (result i32 (ref any)) + ;; OPT_O: (func $br_on_cast_fail-one (type $11) (param $0 i32) (param $1 anyref) (result i32 (ref any)) + ;; OPT_O-NEXT: (block $block (type $7) (result i32 (ref any)) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result (ref any)) @@ -923,8 +923,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_cast_fail-two (type $8) (param $0 i32) (param $1 i64) (param $2 anyref) (result i32 i64 (ref any)) - ;; OPT_O-NEXT: (block $block (type $4) (result i32 i64 (ref any)) + ;; OPT_O: (func $br_on_cast_fail-two (type $12) (param $0 i32) (param $1 i64) (param $2 anyref) (result i32 i64 (ref any)) + ;; OPT_O-NEXT: (block $block (type $6) (result i32 i64 (ref any)) ;; OPT_O-NEXT: (tuple.make 3 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (local.get $1) @@ -1018,7 +1018,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; OPT_O: (func $br_on_cast_fail-nn (type $20) (param $0 i32) (param $1 (ref any)) (result i32 (ref any)) - ;; OPT_O-NEXT: (block $block (type $1) (result i32 (ref any)) + ;; OPT_O-NEXT: (block $block (type $7) (result i32 (ref any)) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result (ref any)) @@ -1103,8 +1103,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $br_on_cast_fail-to-nn (type $9) (param $0 i32) (param $1 anyref) (result i32 anyref) - ;; OPT_O-NEXT: (block $block (type $13) (result i32 anyref) + ;; OPT_O: (func $br_on_cast_fail-to-nn (type $13) (param $0 i32) (param $1 anyref) (result i32 anyref) + ;; OPT_O-NEXT: (block $block (type $2) (result i32 anyref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result anyref) @@ -1187,7 +1187,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $scratch_7) ;; CHECK-NEXT: ) - ;; OPT_O: (func $unreachable-fallthrough (type $6) (param $0 i32) (param $1 anyref) (result i32) + ;; OPT_O: (func $unreachable-fallthrough (type $10) (param $0 i32) (param $1 anyref) (result i32) ;; OPT_O-NEXT: (drop ;; OPT_O-NEXT: (block $l0 (result (ref any)) ;; OPT_O-NEXT: (br_on_non_null $l0 @@ -1294,7 +1294,7 @@ ;; CHECK-NEXT: ) ;; OPT_O: (func $matching-branches (type $21) (param $0 i32) (param $1 anyref) (param $2 i32) (param $3 anyref) (result i32 eqref) ;; OPT_O-NEXT: (local $4 eqref) - ;; OPT_O-NEXT: (block $block (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (block $block (type $5) (result i32 eqref) ;; OPT_O-NEXT: (local.set $4 ;; OPT_O-NEXT: (block $block0 (result eqref) ;; OPT_O-NEXT: (global.set $any @@ -1453,7 +1453,7 @@ ;; CHECK-NEXT: ) ;; OPT_O: (func $different-branches (type $22) (param $0 i32) (param $1 anyref) (param $2 i32) (param $3 eqref) (param $4 anyref) (result i32 eqref) ;; OPT_O-NEXT: (local $5 (tuple i32 eqref)) - ;; OPT_O-NEXT: (block $block (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (block $block (type $5) (result i32 eqref) ;; OPT_O-NEXT: (block $block1 ;; OPT_O-NEXT: (br $block ;; OPT_O-NEXT: (tuple.make 2 @@ -1626,7 +1626,7 @@ ;; CHECK-NEXT: ) ;; OPT_O: (func $different-branches-2 (type $23) (param $0 i32) (param $1 eqref) (param $2 anyref) (param $3 i32) (param $4 anyref) (result i32 eqref) ;; OPT_O-NEXT: (local $5 (tuple i32 eqref)) - ;; OPT_O-NEXT: (block $block (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (block $block (type $5) (result i32 eqref) ;; OPT_O-NEXT: (block $block0 ;; OPT_O-NEXT: (br $block ;; OPT_O-NEXT: (tuple.make 2 @@ -1793,7 +1793,7 @@ ;; OPT_O-NEXT: (block $block10 ;; OPT_O-NEXT: (br $block1 ;; OPT_O-NEXT: (tuple.extract 2 0 - ;; OPT_O-NEXT: (block $block (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (block $block (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result eqref) @@ -1896,7 +1896,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; OPT_O: (func $with-block-param (type $25) (param $0 i64) (param $1 anyref) (result i64 eqref) - ;; OPT_O-NEXT: (block $block (type $14) (result i64 eqref) + ;; OPT_O-NEXT: (block $block (type $1) (result i64 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $block0 (result eqref) @@ -2098,7 +2098,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $loop-results (type $9) (param $0 i32) (param $1 anyref) (result i32 anyref) + ;; OPT_O: (func $loop-results (type $13) (param $0 i32) (param $1 anyref) (result i32 anyref) ;; OPT_O-NEXT: (local $2 (tuple i32 anyref)) ;; OPT_O-NEXT: (local $3 eqref) ;; OPT_O-NEXT: (local.set $2 @@ -2107,12 +2107,12 @@ ;; OPT_O-NEXT: (local.get $1) ;; OPT_O-NEXT: ) ;; OPT_O-NEXT: ) - ;; OPT_O-NEXT: (loop $label2 (type $1) (result i32 (ref any)) - ;; OPT_O-NEXT: (block $label3 (type $1) (result i32 (ref any)) + ;; OPT_O-NEXT: (loop $label2 (type $7) (result i32 (ref any)) + ;; OPT_O-NEXT: (block $label3 (type $7) (result i32 (ref any)) ;; OPT_O-NEXT: (local.set $2 - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (br $label3 - ;; OPT_O-NEXT: (block $label1 (type $1) (result i32 (ref any)) + ;; OPT_O-NEXT: (block $label1 (type $7) (result i32 (ref any)) ;; OPT_O-NEXT: (local.set $3 ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label1 @@ -2215,13 +2215,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $if (type $10) (param $0 i32) (param $1 i32) (param $2 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $if (type $14) (param $0 i32) (param $1 i32) (param $2 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $1) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (if (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (if (type $5) (result i32 eqref) ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (then ;; OPT_O-NEXT: (global.set $any @@ -2327,13 +2327,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $else (type $10) (param $0 i32) (param $1 i32) (param $2 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $else (type $14) (param $0 i32) (param $1 i32) (param $2 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $1) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (if (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (if (type $5) (result i32 eqref) ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (then ;; OPT_O-NEXT: (tuple.make 2 @@ -2469,12 +2469,12 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; OPT_O: (func $if-else-params (type $27) (param $0 i32) (param $1 i32) (param $2 anyref) (param $3 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (if (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (if (type $5) (result i32 eqref) ;; OPT_O-NEXT: (local.get $1) ;; OPT_O-NEXT: (then ;; OPT_O-NEXT: (global.set $any @@ -2573,13 +2573,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $try-catch (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $try-catch (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (try (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (try (type $5) (result i32 eqref) ;; OPT_O-NEXT: (do ;; OPT_O-NEXT: (call $use-i32-any ;; OPT_O-NEXT: (local.get $0) @@ -2670,13 +2670,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $try-catch_all (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $try-catch_all (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (try (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (try (type $5) (result i32 eqref) ;; OPT_O-NEXT: (do ;; OPT_O-NEXT: (call $use-i32-any ;; OPT_O-NEXT: (local.get $0) @@ -2763,13 +2763,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $try-delegate (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $try-delegate (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (try (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (try (type $5) (result i32 eqref) ;; OPT_O-NEXT: (do ;; OPT_O-NEXT: (call $use-i32-any ;; OPT_O-NEXT: (local.get $0) @@ -2869,13 +2869,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $try-everything-params (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $try-everything-params (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (try (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (try (type $5) (result i32 eqref) ;; OPT_O-NEXT: (do ;; OPT_O-NEXT: (call $use-i32-any ;; OPT_O-NEXT: (local.get $0) @@ -2975,13 +2975,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $try_table (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $try_table (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (try_table (type $0) (result i32 eqref) + ;; OPT_O-NEXT: (try_table (type $5) (result i32 eqref) ;; OPT_O-NEXT: (call $use-i32-any ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (br_on_cast $label0 anyref eqref @@ -3058,13 +3058,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $try_table-params (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $try_table-params (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) ;; OPT_O-NEXT: (br $label - ;; OPT_O-NEXT: (try_table (type $2) (result i32 (ref eq)) + ;; OPT_O-NEXT: (try_table (type $3) (result i32 (ref eq)) ;; OPT_O-NEXT: (call $use-i32-any ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (br_on_cast $label0 anyref eqref @@ -3143,8 +3143,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPT_O: (func $branch-to-func (type $3) (param $0 i32) (param $1 anyref) (result i32 eqref) - ;; OPT_O-NEXT: (block $label (type $0) (result i32 eqref) + ;; OPT_O: (func $branch-to-func (type $0) (param $0 i32) (param $1 anyref) (result i32 eqref) + ;; OPT_O-NEXT: (block $label (type $5) (result i32 eqref) ;; OPT_O-NEXT: (tuple.make 2 ;; OPT_O-NEXT: (local.get $0) ;; OPT_O-NEXT: (block $label0 (result eqref) diff --git a/test/lit/passes/O3_stack-switching.wast b/test/lit/passes/O3_stack-switching.wast index d928f6614b2..262f224cd1a 100644 --- a/test/lit/passes/O3_stack-switching.wast +++ b/test/lit/passes/O3_stack-switching.wast @@ -19,9 +19,9 @@ (type $cont (cont $function_1)) ;; CHECK: (type $fiber (struct (field $handlers (ref $handlers)) (field $cont (ref $cont)))) (type $fiber (struct (field $handlers (ref $handlers)) (field $cont (ref $cont)))) - ;; CHECK: (tag $exception (type $8) (param (ref eq))) + ;; CHECK: (tag $exception (type $9) (param (ref eq))) (tag $exception (param (ref eq))) - ;; CHECK: (tag $effect (type $9) (param (ref eq)) (result (ref eq) (ref eq))) + ;; CHECK: (tag $effect (type $8) (param (ref eq)) (result (ref eq) (ref eq))) (tag $effect (param (ref eq)) (result (ref eq) (ref eq))) ;; CHECK: (func $resume (type $10) (param $0 (ref $fiber)) (param $1 (ref $closure)) (param $2 (ref eq)) (result (ref eq)) diff --git a/test/lit/passes/gto_and_cfp_in_O.wast b/test/lit/passes/gto_and_cfp_in_O.wast index 783da3a1982..78ac48d675e 100644 --- a/test/lit/passes/gto_and_cfp_in_O.wast +++ b/test/lit/passes/gto_and_cfp_in_O.wast @@ -8,10 +8,11 @@ ;; open world we do not run them. (module - ;; OPEN_WORLD: (type $struct (sub (struct (field (mut funcref)) (field (mut i32))))) - (type $struct (sub (struct (field (mut funcref)) (field (mut i32))))) + ;; OPEN_WORLD: (rec + ;; OPEN_WORLD-NEXT: (type $0 (func)) - ;; OPEN_WORLD: (type $1 (func)) + ;; OPEN_WORLD: (type $struct (sub (struct (field (mut funcref)) (field (mut i32))))) + (type $struct (sub (struct (field (mut funcref)) (field (mut i32))))) ;; OPEN_WORLD: (type $2 (func (result i32))) @@ -26,7 +27,7 @@ ;; OPEN_WORLD: (export "main" (func $main)) - ;; OPEN_WORLD: (func $by-ref (type $1) + ;; OPEN_WORLD: (func $by-ref (type $0) ;; OPEN_WORLD-NEXT: (struct.set $struct 1 ;; OPEN_WORLD-NEXT: (global.get $glob) ;; OPEN_WORLD-NEXT: (i32.const 200) From 17c50199800cd89e7d4d9caae95bed416ac483a8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 May 2025 12:15:36 -0700 Subject: [PATCH 23/24] simplify test as suggested --- test/lit/string-builtins.wast | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/test/lit/string-builtins.wast b/test/lit/string-builtins.wast index 37800cea760..126a4c09ea7 100644 --- a/test/lit/string-builtins.wast +++ b/test/lit/string-builtins.wast @@ -2,17 +2,17 @@ ;; Run normal -O2, which should lift, optimize, and lower strings, if the ;; string builtins feature is enabled (GC is required, as well, as the lowering -;; emits functions using arrays). We optimize in the last two here. +;; emits functions using arrays). We optimize identically in the last two here. ;; RUN: foreach %s %t wasm-opt -O2 -S -o - --enable-reference-types \ ;; RUN: | filecheck %s --check-prefix=MVP ;; RUN: foreach %s %t wasm-opt -O2 -S -o - -all \ -;; RUN: | filecheck %s --check-prefix=ALL +;; RUN: | filecheck %s --check-prefix=OPT ;; RUN: foreach %s %t wasm-opt -O2 -S -o - --enable-reference-types \ ;; RUN: --enable-string-builtins --enable-gc \ -;; RUN: | filecheck %s --check-prefix=ESB +;; RUN: | filecheck %s --check-prefix=OPT (module (type $array16 (array (mut i16))) @@ -38,24 +38,15 @@ ;; MVP-NEXT: (global.get $bar) ;; MVP-NEXT: ) ;; MVP-NEXT: ) - ;; ALL: (type $0 (func (result (ref extern)))) + ;; OPT: (type $0 (func (result (ref extern)))) - ;; ALL: (import "\'" "foobar" (global $"string.const_\"foobar\"" (ref extern))) + ;; OPT: (import "\'" "foobar" (global $"string.const_\"foobar\"" (ref extern))) - ;; ALL: (export "string.concat" (func $string.concat)) + ;; OPT: (export "string.concat" (func $string.concat)) - ;; ALL: (func $string.concat (type $0) (result (ref extern)) - ;; ALL-NEXT: (global.get $"string.const_\"foobar\"") - ;; ALL-NEXT: ) - ;; ESB: (type $0 (func (result (ref extern)))) - - ;; ESB: (import "\'" "foobar" (global $"string.const_\"foobar\"" (ref extern))) - - ;; ESB: (export "string.concat" (func $string.concat)) - - ;; ESB: (func $string.concat (type $0) (result (ref extern)) - ;; ESB-NEXT: (global.get $"string.const_\"foobar\"") - ;; ESB-NEXT: ) + ;; OPT: (func $string.concat (type $0) (result (ref extern)) + ;; OPT-NEXT: (global.get $"string.const_\"foobar\"") + ;; OPT-NEXT: ) (func $string.concat (export "string.concat") (result (ref extern)) ;; When we optimize, we concatenate "foo" and "bar" here to "foobar". A new ;; imported global will appear for that, and we will get it here. From 0a447e58df4a97af7a94a97db74de06e4686c0fb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 May 2025 13:39:37 -0700 Subject: [PATCH 24/24] don't fuzz string builtins yet --- scripts/fuzz_opt.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 8f832187f5c..e87b9d0b58b 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -51,8 +51,16 @@ # parameters # feature options that are always passed to the tools. -# XXX fp16 is not yet stable, remove from here when it is -CONSTANT_FEATURE_OPTS = ['--all-features', '--disable-fp16'] +CONSTANT_FEATURE_OPTS = [ + '--all-features', + # TODO fp16 is not yet stable, remove from here when it is + '--disable-fp16', + # TODO if we enable string-builtins then if the input module has strings, + # the output after lowering will have string imports, and the + # interpreter does not yet support executing those (we'd need to handle + # all the imported functions, magic constants, and the section) + '--disable-string-builtins', +] INPUT_SIZE_MIN = 1024 INPUT_SIZE_MEAN = 40 * 1024