diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index fe908e9d5d9..55dce6dc47c 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -229,18 +229,6 @@ def randomize_fuzz_settings(): else: LEGALIZE = False - # if GC is enabled then run --dce at the very end, to ensure that our - # binaries validate in other VMs, due to how non-nullable local validation - # and unreachable code interact. see - # https://github.com/WebAssembly/binaryen/pull/5665 - # https://github.com/WebAssembly/binaryen/issues/5599 - if '--disable-gc' not in FEATURE_OPTS: - GEN_ARGS += ['--dce'] - - # Add --dce not only when generating the original wasm but to the - # optimizations we use to create any other wasm file. - FUZZ_OPTS += ['--dce'] - if CLOSED_WORLD: GEN_ARGS += [CLOSED_WORLD_FLAG] # Enclose the world much of the time when fuzzing closed-world, so that @@ -450,13 +438,6 @@ def pick_initial_contents(): # --fuzz-exec reports a stack limit using this notation STACK_LIMIT = '[trap stack limit]' -# V8 reports this error in rare cases due to limitations in our handling of non- -# nullable locals in unreachable code, see -# https://github.com/WebAssembly/binaryen/pull/5665 -# https://github.com/WebAssembly/binaryen/issues/5599 -# and also see the --dce workaround below that also links to those issues. -V8_UNINITIALIZED_NONDEF_LOCAL = 'uninitialized non-defaultable local' - # JS exceptions are logged as exception thrown: REASON EXCEPTION_PREFIX = 'exception thrown: ' @@ -655,8 +636,6 @@ def filter_known_issues(output): # strings in this list for known issues (to which more need to be # added as necessary). HOST_LIMIT_PREFIX, - # see comment above on this constant - V8_UNINITIALIZED_NONDEF_LOCAL, # V8 does not accept nullable stringviews # (https://github.com/WebAssembly/binaryen/pull/6574) 'expected (ref stringview_wtf16), got nullref', diff --git a/src/passes/Poppify.cpp b/src/passes/Poppify.cpp index c12c7203c0d..b6452b51cde 100644 --- a/src/passes/Poppify.cpp +++ b/src/passes/Poppify.cpp @@ -132,6 +132,7 @@ struct Poppifier : BinaryenIRWriter { void emitScopeEnd(Expression* curr); void emitFunctionEnd(); void emitUnreachable(); + void emitUnreachableLocalSet(Index i); void emitDebugLocation(Expression* curr) {} // Tuple lowering methods @@ -317,6 +318,12 @@ void Poppifier::emitUnreachable() { instrs.push_back(builder.makeUnreachable()); } +void Poppifier::emitUnreachableLocalSet(Index i) { + auto& instrs = scopeStack.back().instrs; + instrs.push_back(builder.makeUnreachable()); + instrs.push_back(builder.makeLocalSet(i, builder.makePop(Type::unreachable))); +} + void Poppifier::emitTupleExtract(TupleExtract* curr) { auto& instrs = scopeStack.back().instrs; auto types = curr->tuple->type; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 83e7baa580d..2180749eac0 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -498,7 +498,10 @@ struct PrintExpressionContents printLocal(curr->index, currFunction, o); } void visitLocalSet(LocalSet* curr) { - if (curr->isTee()) { + // Print unreachable tees as sets. This makes the output valid WebAssembly + // in more cases because it avoids pushing a concrete type (which may not + // be the type required by the next instruction) onto a polymorphic stack. + if (curr->isTee() && curr->type != Type::unreachable) { printMedium(o, "local.tee "); } else { printMedium(o, "local.set "); diff --git a/src/wasm-stack.h b/src/wasm-stack.h index 6a6649d0aa4..93f484d9709 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -18,6 +18,7 @@ #define wasm_stack_h #include "ir/branch-utils.h" +#include "ir/find_all.h" #include "ir/module-utils.h" #include "ir/properties.h" #include "pass.h" @@ -123,6 +124,7 @@ class BinaryInstWriter : public OverriddenVisitor { // emit an end at the end of a function void emitFunctionEnd(); void emitUnreachable(); + void emitUnreachableLocalSet(Index index); void mapLocalsAndEmitHeader(); MappedLocals mappedLocals; @@ -243,11 +245,16 @@ class BinaryenIRWriter : public Visitor> { void emitScopeEnd(Expression* curr) { static_cast(this)->emitScopeEnd(curr); } - void emitFunctionEnd() { static_cast(this)->emitFunctionEnd(); } - void emitUnreachable() { static_cast(this)->emitUnreachable(); } + SubType& self() { return *static_cast(this); } + void emitFunctionEnd() { self().emitFunctionEnd(); } + void emitUnreachable() { self().emitUnreachable(); } + void emitUnreachableLocalSet(Index index) { + self().emitUnreachableLocalSet(index); + } void emitDebugLocation(Expression* curr) { static_cast(this)->emitDebugLocation(curr); } + void emitUnreachableLocalSets(Expression* curr); void visitPossibleBlockContents(Expression* curr); }; @@ -258,6 +265,23 @@ template void BinaryenIRWriter::write() { emitFunctionEnd(); } +// Normally we do not emit any instructions between a stack-polymorphic (i.e. +// unreachable) instruction and the end of the current control flow structure. +// However, local.sets of non-nullable locals in these unreachable regions can +// still be necessary to make later local.gets valid. We can emit just these +// sets without emitting their values; they will pull whatever type they need +// out of the unreachable. This works no matter what type the current control +// flow structure returns; it will also pull whatever values it needs out of the +// unreachable, and the sets will not push any values to get in the way. +template +void BinaryenIRWriter::emitUnreachableLocalSets(Expression* curr) { + for (auto* set : FindAll(curr).list) { + if (func->getLocalType(set->index).isNonNullable()) { + emitUnreachableLocalSet(set->index); + } + } +} + // Emits a node in a position that can contain a list of contents, like an if // arm. This will emit the node, but if it is a block with no name, just emit // its contents. This is ok to do because a list of contents is ok in the wasm @@ -279,10 +303,12 @@ void BinaryenIRWriter::visitPossibleBlockContents(Expression* curr) { } for (auto* child : block->list) { visit(child); - // Since this child was unreachable, either this child or one of its - // descendants was a source of unreachability that was actually - // emitted. Subsequent children won't be reachable, so skip them. if (child->type == Type::unreachable) { + // Since this child was unreachable, either this child or one of its + // descendants was a source of unreachability that was actually + // emitted. Subsequent children won't be reachable, so skip them. We also + // don't have to worry about local.sets here because they will not be + // visible past the end of the surrounding control flow structure anyway. break; } } @@ -294,19 +320,29 @@ void BinaryenIRWriter::visit(Expression* curr) { // unreachable instructions that just inherit unreachability from their // children, since the latter won't be reached. This (together with logic in // the control flow visitors) also ensures that the final instruction in each - // unreachable block is a source of unreachability, which means we don't need - // to emit an extra `unreachable` before the end of the block to prevent type - // errors. - bool hasUnreachableChild = false; + // unreachable block is a source of unreachability (possibly followed by a + // sequence of local.sets), which means we don't need to emit an extra + // `unreachable` before the end of the block to prevent type errors. + bool sawUnreachable = false; for (auto* child : ValueChildIterator(curr)) { + if (sawUnreachable) { + emitUnreachableLocalSets(child); + continue; + } visit(child); if (child->type == Type::unreachable) { - hasUnreachableChild = true; - break; + // Skip the following children, except for necessary local.sets they + // contain. + sawUnreachable = true; } } - if (hasUnreachableChild) { - // `curr` is not reachable, so don't emit it. + if (sawUnreachable) { + // `curr` is not reachable, so don't emit it unless it is a + // potentially-necessary local.set itself. + if (auto* set = curr->dynCast(); + set && func->getLocalType(set->index).isNonNullable()) { + emitUnreachableLocalSet(set->index); + } return; } emitDebugLocation(curr); @@ -323,13 +359,17 @@ template void BinaryenIRWriter::visitBlock(Block* curr) { auto visitChildren = [this](Block* curr, Index from) { auto& list = curr->list; - while (from < list.size()) { - auto* child = list[from]; + bool sawUnreachable = false; + for (Index i = from; i < list.size(); ++i) { + auto* child = list[i]; + if (sawUnreachable) { + emitUnreachableLocalSets(child); + continue; + } visit(child); if (child->type == Type::unreachable) { - break; + sawUnreachable = true; } - ++from; } }; @@ -354,6 +394,10 @@ void BinaryenIRWriter::visitBlock(Block* curr) { } auto afterChildren = [this](Block* curr) { + if (!curr->name) { + // Not emitting a block, so continue on in the parent. + return; + } emitScopeEnd(curr); if (curr->type == Type::unreachable) { // Since this block is unreachable, no instructions will be emitted after @@ -376,13 +420,17 @@ void BinaryenIRWriter::visitBlock(Block* curr) { Block* child; while (!curr->list.empty() && (child = curr->list[0]->dynCast())) { parents.push_back(curr); - emit(curr); + if (curr->name) { + emit(curr); + } curr = child; emitDebugLocation(curr); } // Emit the current block, which does not have a block as a child in the // first position. - emit(curr); + if (curr->name) { + emit(curr); + } visitChildren(curr, 0); afterChildren(curr); bool childUnreachable = curr->type == Type::unreachable; @@ -391,6 +439,9 @@ void BinaryenIRWriter::visitBlock(Block* curr) { auto* parent = parents.back(); parents.pop_back(); if (!childUnreachable) { + // No need to emit unreachable sets here because we will skip everything + // up to the end of the next named block, which would hide their effects + // anyway. visitChildren(parent, 1); } afterChildren(parent); @@ -504,6 +555,9 @@ class BinaryenIRToBinaryWriter writer.emitFunctionEnd(); } void emitUnreachable() { writer.emitUnreachable(); } + void emitUnreachableLocalSet(Index index) { + writer.emitUnreachableLocalSet(index); + } void emitDebugLocation(Expression* curr) { if (sourceMap) { parent.writeSourceMapLocation(curr, func); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 13f52570b22..1b235ae9301 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -329,8 +329,11 @@ void BinaryInstWriter::visitLocalSet(LocalSet* curr) { o << static_cast(BinaryConsts::LocalSet) << U32LEB(mappedLocals[std::make_pair(curr->index, i)]); } - if (!curr->isTee()) { - // This is not a tee, so just finish setting the values. + if (!curr->isTee() || curr->type == Type::unreachable) { + // This is not a tee or it is unreachable, so just finish setting the + // values. We emit unreachable sets as sets rather than tees to avoid + // pushing concrete types (which may not be correct for the next + // instruction) onto polymorphic stacks. o << static_cast(BinaryConsts::LocalSet) << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]); } else if (auto it = extractedGets.find(curr); it != extractedGets.end()) { @@ -3196,6 +3199,14 @@ void BinaryInstWriter::emitUnreachable() { o << static_cast(BinaryConsts::Unreachable); } +void BinaryInstWriter::emitUnreachableLocalSet(Index index) { + LocalSet set; + set.index = index; + set.type = Type::none; + set.value = nullptr; + visitLocalSet(&set); +} + void BinaryInstWriter::mapLocalsAndEmitHeader() { assert(func && "BinaryInstWriter: function is not set"); // Map params @@ -3583,6 +3594,13 @@ class StackIRGenerator : public BinaryenIRWriter { void emitUnreachable() { stackIR.push_back(makeStackInst(Builder(module).makeUnreachable())); } + void emitUnreachableLocalSet(Index i) { + Builder builder(module); + auto unreachable = builder.makeUnreachable(); + auto set = builder.makeLocalSet(i, unreachable); + emit(unreachable); + emit(set); + } void emitDebugLocation(Expression* curr) {} StackIR& getStackIR() { return stackIR; } diff --git a/test/lit/basic/polymorphic_stack.wast b/test/lit/basic/polymorphic_stack.wast index 2ccaa51e7db..72a3bceb454 100644 --- a/test/lit/basic/polymorphic_stack.wast +++ b/test/lit/basic/polymorphic_stack.wast @@ -121,13 +121,13 @@ ;; CHECK-TEXT-NEXT: (local $y f32) ;; CHECK-TEXT-NEXT: (drop ;; CHECK-TEXT-NEXT: (i64.eqz - ;; CHECK-TEXT-NEXT: (local.tee $x + ;; CHECK-TEXT-NEXT: (local.set $x ;; CHECK-TEXT-NEXT: (unreachable) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: (drop - ;; CHECK-TEXT-NEXT: (local.tee $y + ;; CHECK-TEXT-NEXT: (local.set $y ;; CHECK-TEXT-NEXT: (i64.eqz ;; CHECK-TEXT-NEXT: (unreachable) ;; CHECK-TEXT-NEXT: ) @@ -161,7 +161,7 @@ ;; CHECK-TEXT-NEXT: (if ;; CHECK-TEXT-NEXT: (i32.const 259) ;; CHECK-TEXT-NEXT: (then - ;; CHECK-TEXT-NEXT: (local.tee $0 + ;; CHECK-TEXT-NEXT: (local.set $0 ;; CHECK-TEXT-NEXT: (unreachable) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) @@ -225,11 +225,8 @@ ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) ;; CHECK-BIN: (func $untaken-break-should-have-value (type $0) (result i32) - ;; CHECK-BIN-NEXT: (block - ;; CHECK-BIN-NEXT: (drop - ;; CHECK-BIN-NEXT: (i32.const 0) - ;; CHECK-BIN-NEXT: ) - ;; CHECK-BIN-NEXT: (unreachable) + ;; CHECK-BIN-NEXT: (drop + ;; CHECK-BIN-NEXT: (i32.const 0) ;; CHECK-BIN-NEXT: ) ;; CHECK-BIN-NEXT: (unreachable) ;; CHECK-BIN-NEXT: ) @@ -419,11 +416,8 @@ ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG: (func $5 (type $0) (result i32) -;; CHECK-BIN-NODEBUG-NEXT: (block -;; CHECK-BIN-NODEBUG-NEXT: (drop -;; CHECK-BIN-NODEBUG-NEXT: (i32.const 0) -;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG-NEXT: (unreachable) +;; CHECK-BIN-NODEBUG-NEXT: (drop +;; CHECK-BIN-NODEBUG-NEXT: (i32.const 0) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: (unreachable) ;; CHECK-BIN-NODEBUG-NEXT: ) diff --git a/test/lit/basic/stack_switching_switch.wast b/test/lit/basic/stack_switching_switch.wast index 152ef0aedec..29ac99d9651 100644 --- a/test/lit/basic/stack_switching_switch.wast +++ b/test/lit/basic/stack_switching_switch.wast @@ -127,7 +127,7 @@ ;; CHECK-TEXT: (func $unreachable (type $2) (param $k (ref null $ct)) (result i32) ;; CHECK-TEXT-NEXT: (return - ;; CHECK-TEXT-NEXT: (local.tee $k + ;; CHECK-TEXT-NEXT: (local.set $k ;; CHECK-TEXT-NEXT: (block ;; (replaces unreachable StackSwitch we can't emit) ;; CHECK-TEXT-NEXT: (drop ;; CHECK-TEXT-NEXT: (i32.const 42) diff --git a/test/lit/basic/unreachable-local-set.wast b/test/lit/basic/unreachable-local-set.wast new file mode 100644 index 00000000000..d0658a4afc2 --- /dev/null +++ b/test/lit/basic/unreachable-local-set.wast @@ -0,0 +1,229 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s -all --generate-stack-ir --print-stack-ir | filecheck %s +;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s --check-prefix=RTRIP + +;; We normally skip emitting instructions after unreachables, but we must keep +;; local.sets of non-nullable locals in case there are later local.gets that +;; would be invalid without them. + +(module + ;; CHECK: (func $end-of-block (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; CHECK-NEXT: (local $local (ref struct)) + ;; CHECK-NEXT: nop + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: local.set $local + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $local + ;; CHECK-NEXT: ) + ;; RTRIP: (func $end-of-block (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; RTRIP-NEXT: (local $local (ref struct)) + ;; RTRIP-NEXT: (nop) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (local.set $local + ;; RTRIP-NEXT: (unreachable) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (local.get $local) + ;; RTRIP-NEXT: ) + (func $end-of-block (param $ref (ref struct)) (result (ref struct)) + (local $local (ref struct)) + (drop + (block (result i32) + (nop) + (local.set $local + (unreachable) + ) + ) + ) + (local.get $local) + ) + + ;; CHECK: (func $middle-of-block (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; CHECK-NEXT: (local $local (ref struct)) + ;; CHECK-NEXT: nop + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: local.set $local + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $local + ;; CHECK-NEXT: ) + ;; RTRIP: (func $middle-of-block (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; RTRIP-NEXT: (local $local (ref struct)) + ;; RTRIP-NEXT: (nop) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (local.set $local + ;; RTRIP-NEXT: (unreachable) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (local.get $local) + ;; RTRIP-NEXT: ) + (func $middle-of-block (param $ref (ref struct)) (result (ref struct)) + (local $local (ref struct)) + (drop + (block (result i32) + (nop) + (local.set $local + (unreachable) + ) + (i32.const 0) + ) + ) + (local.get $local) + ) + + ;; CHECK: (func $after-unreachable (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; CHECK-NEXT: (local $local (ref struct)) + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: local.set $local + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $local + ;; CHECK-NEXT: ) + ;; RTRIP: (func $after-unreachable (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; RTRIP-NEXT: (local $local (ref struct)) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (local.set $local + ;; RTRIP-NEXT: (unreachable) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (local.get $local) + ;; RTRIP-NEXT: ) + (func $after-unreachable (param $ref (ref struct)) (result (ref struct)) + (local $local (ref struct)) + (drop + (block (result i32) + (unreachable) + (local.set $local + (local.get $ref) + ) + (i32.const 0) + ) + ) + (local.get $local) + ) + + ;; CHECK: (func $nested-exprs (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; CHECK-NEXT: (local $local (ref struct)) + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: local.set $local + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $local + ;; CHECK-NEXT: ) + ;; RTRIP: (func $nested-exprs (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; RTRIP-NEXT: (local $local (ref struct)) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (local.set $local + ;; RTRIP-NEXT: (unreachable) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (local.get $local) + ;; RTRIP-NEXT: ) + (func $nested-exprs (param $ref (ref struct)) (result (ref struct)) + (local $local (ref struct)) + (drop + (block (result (ref struct)) + (ref.eq + (unreachable) + (ref.as_non_null + (local.tee $local + (local.get $ref) + ) + ) + ) + ) + ) + (local.get $local) + ) + + ;; CHECK: (func $renumbered-locals (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; CHECK-NEXT: (local $tuple (tuple i32 i32)) + ;; CHECK-NEXT: (local $local (ref struct)) + ;; CHECK-NEXT: nop + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: local.set $local + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: local.get $local + ;; CHECK-NEXT: ) + ;; RTRIP: (func $renumbered-locals (type $0) (param $ref (ref struct)) (result (ref struct)) + ;; RTRIP-NEXT: (local $tuple i32) + ;; RTRIP-NEXT: (local $2 i32) + ;; RTRIP-NEXT: (local $local (ref struct)) + ;; RTRIP-NEXT: (nop) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (local.set $local + ;; RTRIP-NEXT: (unreachable) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (local.get $local) + ;; RTRIP-NEXT: ) + (func $renumbered-locals (param $ref (ref struct)) (result (ref struct)) + ;; When the tuple is lowered, it causes subsequent locals to be mapped to + ;; new indices. We should respect that remapping when writing unreachable + ;; local.sets. + (local $tuple (tuple i32 i32)) + (local $local (ref struct)) + (drop + (block (result i32) + (nop) + (local.set $local + (unreachable) + ) + ) + ) + (local.get $local) + ) + + ;; CHECK: (func $unnamed-nested-block (type $1) (result (ref struct)) + ;; CHECK-NEXT: (local $local (ref struct)) + ;; CHECK-NEXT: block $block (result (ref struct)) + ;; CHECK-NEXT: ref.null none + ;; CHECK-NEXT: br_on_non_null $block + ;; CHECK-NEXT: ref.null none + ;; CHECK-NEXT: ref.as_non_null + ;; CHECK-NEXT: local.set $local + ;; CHECK-NEXT: local.get $local + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: end + ;; CHECK-NEXT: ) + ;; RTRIP: (func $unnamed-nested-block (type $1) (result (ref struct)) + ;; RTRIP-NEXT: (local $local (ref struct)) + ;; RTRIP-NEXT: (block $block (result (ref struct)) + ;; RTRIP-NEXT: (br_on_non_null $block + ;; RTRIP-NEXT: (ref.null none) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (local.set $local + ;; RTRIP-NEXT: (ref.as_non_null + ;; RTRIP-NEXT: (ref.null none) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (local.get $local) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (unreachable) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + (func $unnamed-nested-block (result (ref struct)) + (local $local (ref struct)) + (block $block (result (ref struct)) + ;; This unnamed intermediate block must be elided for the later local.get to + ;; be valid. + (block + ;; Use the label to ensure the outer block is emitted. + (br_on_non_null $block + (ref.null none) + ) + (local.set $local + (ref.as_non_null (ref.null none)) + ) + ) + (drop + (local.get $local) + ) + (unreachable) + ) + ) +) diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo.wast b/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo.wast index 2803d243d06..0860f5eeae3 100644 --- a/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo.wast +++ b/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo.wast @@ -43,7 +43,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (block $__asyncify_unwind ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-propagate-addlist.wast b/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-propagate-addlist.wast index 37075e800a4..7c2186dd494 100644 --- a/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-propagate-addlist.wast +++ b/test/lit/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-propagate-addlist.wast @@ -42,7 +42,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (block $__asyncify_unwind ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-eh-asserts.wast b/test/lit/passes/asyncify_pass-arg=asyncify-eh-asserts.wast index 2a9a2b244ba..59c31c447ca 100644 --- a/test/lit/passes/asyncify_pass-arg=asyncify-eh-asserts.wast +++ b/test/lit/passes/asyncify_pass-arg=asyncify-eh-asserts.wast @@ -59,7 +59,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $12 + ;; CHECK-NEXT: (local.set $12 ;; CHECK-NEXT: (block $__asyncify_unwind ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block @@ -338,7 +338,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $18 + ;; CHECK-NEXT: (local.set $18 ;; CHECK-NEXT: (block $__asyncify_unwind ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-eh.wast b/test/lit/passes/asyncify_pass-arg=asyncify-eh.wast index e3d932bb500..c07df1c9988 100644 --- a/test/lit/passes/asyncify_pass-arg=asyncify-eh.wast +++ b/test/lit/passes/asyncify_pass-arg=asyncify-eh.wast @@ -45,7 +45,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $2 + ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (block $__asyncify_unwind ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block diff --git a/test/lit/passes/code-pushing_tnh.wast b/test/lit/passes/code-pushing_tnh.wast index 74791aca91c..aa8373056d9 100644 --- a/test/lit/passes/code-pushing_tnh.wast +++ b/test/lit/passes/code-pushing_tnh.wast @@ -53,7 +53,7 @@ ;; CHECK: (func $unreachable-value ;; CHECK-NEXT: (local $x i32) - ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index 6d014d0f8b4..bdccf601edf 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -24,7 +24,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/dae2.wast b/test/lit/passes/dae2.wast index b6ed701f7f1..594ad0054de 100644 --- a/test/lit/passes/dae2.wast +++ b/test/lit/passes/dae2.wast @@ -3677,7 +3677,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $a + ;; CHECK-NEXT: (local.set $a ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $g diff --git a/test/lit/passes/gufa-cast-all.wast b/test/lit/passes/gufa-cast-all.wast index a1675982f08..acbe4d9c562 100644 --- a/test/lit/passes/gufa-cast-all.wast +++ b/test/lit/passes/gufa-cast-all.wast @@ -127,7 +127,7 @@ ;; CHECK: (func $unreachable (type $none_=>_none) ;; CHECK-NEXT: (local $a (ref $A)) - ;; CHECK-NEXT: (local.tee $a + ;; CHECK-NEXT: (local.set $a ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop diff --git a/test/lit/passes/gufa-eh-null-type.wast b/test/lit/passes/gufa-eh-null-type.wast index dd05f8388bc..4cccd1bac43 100644 --- a/test/lit/passes/gufa-eh-null-type.wast +++ b/test/lit/passes/gufa-eh-null-type.wast @@ -34,7 +34,7 @@ ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $block0 (result (ref noexn)) - ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br_on_non_null $block0 diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 14f362f5e3d..173d086e918 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -313,7 +313,7 @@ ;; CHECK-NEXT: (local $x anyref) ;; CHECK-NEXT: (local $y anyref) ;; CHECK-NEXT: (local $z anyref) - ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $get-nothing) diff --git a/test/lit/passes/heap-store-optimization.wast b/test/lit/passes/heap-store-optimization.wast index 2a773a3882f..c62078f7cba 100644 --- a/test/lit/passes/heap-store-optimization.wast +++ b/test/lit/passes/heap-store-optimization.wast @@ -774,7 +774,7 @@ ;; CHECK: (func $unreachable (type $1) ;; CHECK-NEXT: (local $ref (ref null $struct)) - ;; CHECK-NEXT: (local.tee $ref + ;; CHECK-NEXT: (local.set $ref ;; CHECK-NEXT: (block ;; (replaces unreachable StructNew we can't emit) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) diff --git a/test/lit/passes/heap2local-desc.wast b/test/lit/passes/heap2local-desc.wast index b6467beb544..ecd9189e12f 100644 --- a/test/lit/passes/heap2local-desc.wast +++ b/test/lit/passes/heap2local-desc.wast @@ -1079,7 +1079,7 @@ ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $v + ;; CHECK-NEXT: (local.set $v ;; CHECK-NEXT: (block ;; (replaces unreachable StructGet we can't emit) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block @@ -1305,7 +1305,7 @@ ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $func + ;; CHECK-NEXT: (local.set $func ;; CHECK-NEXT: (block ;; (replaces unreachable StructGet we can't emit) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; (replaces unreachable RefGetDesc we can't emit) diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast index 1f72d5f947c..ec1e06a4a1d 100644 --- a/test/lit/passes/heap2local.wast +++ b/test/lit/passes/heap2local.wast @@ -4402,7 +4402,7 @@ ;; CHECK: (func $array.cast.struct.set (type $1) ;; CHECK-NEXT: (local $eq (ref eq)) ;; CHECK-NEXT: (local $struct (ref struct)) - ;; CHECK-NEXT: (local.tee $struct + ;; CHECK-NEXT: (local.set $struct ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result nullref) diff --git a/test/lit/passes/inlining_enable-tail-call.wast b/test/lit/passes/inlining_enable-tail-call.wast index dae243dcf5b..52687ee0fd8 100644 --- a/test/lit/passes/inlining_enable-tail-call.wast +++ b/test/lit/passes/inlining_enable-tail-call.wast @@ -1175,7 +1175,7 @@ ;; CHECK-NEXT: (block $__return_call ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (br $__inlined_func$second-2$1) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/inlining_optimize-level=3.wast b/test/lit/passes/inlining_optimize-level=3.wast index 654786d5e0d..dc35fb10b23 100644 --- a/test/lit/passes/inlining_optimize-level=3.wast +++ b/test/lit/passes/inlining_optimize-level=3.wast @@ -455,7 +455,7 @@ ;; CHECK-NEXT: (block $__inlined_func$A$3 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (block $__inlined_func$C$2 (result f32) - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (block $__inlined_func$D$1 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/memory-packing_all-features.wast b/test/lit/passes/memory-packing_all-features.wast index 82e4009ffd9..01650a592bc 100644 --- a/test/lit/passes/memory-packing_all-features.wast +++ b/test/lit/passes/memory-packing_all-features.wast @@ -2497,7 +2497,7 @@ ;; CHECK: (func $0 (type $0) ;; CHECK-NEXT: (local $0 i32) - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index 0e1676ef063..c231f76d059 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -2834,7 +2834,7 @@ ;; CHECK-NEXT: (local $temp (ref null $struct)) ;; CHECK-NEXT: (block ;; (replaces unreachable StructSet we can't emit) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2863,7 +2863,7 @@ ;; CHECK-NEXT: (local $temp (ref none)) ;; CHECK-NEXT: (block ;; (replaces unreachable ArraySet we can't emit) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2978,7 +2978,7 @@ ;; CHECK: (func $non-null-bottom-ref (type $45) (result (ref func)) ;; CHECK-NEXT: (local $0 funcref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (loop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/optimize-instructions-ignore-traps.wast b/test/lit/passes/optimize-instructions-ignore-traps.wast index 2417e58d48a..8e89f71caef 100644 --- a/test/lit/passes/optimize-instructions-ignore-traps.wast +++ b/test/lit/passes/optimize-instructions-ignore-traps.wast @@ -213,7 +213,7 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (i32.eqz diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast index eb5f36382b7..dd2d0daa4d5 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -10981,7 +10981,7 @@ ;; CHECK: (func $tee-with-unreachable-value (result f64) ;; CHECK-NEXT: (local $var$0 i32) ;; CHECK-NEXT: (block $label$1 (result f64) - ;; CHECK-NEXT: (local.tee $var$0 + ;; CHECK-NEXT: (local.set $var$0 ;; CHECK-NEXT: (br_if $label$1 ;; CHECK-NEXT: (f64.const 1) ;; CHECK-NEXT: (unreachable) @@ -18704,7 +18704,7 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/precompute-gc-immutable.wast b/test/lit/passes/precompute-gc-immutable.wast index 7520c8f1266..ed8f33bf58f 100644 --- a/test/lit/passes/precompute-gc-immutable.wast +++ b/test/lit/passes/precompute-gc-immutable.wast @@ -175,7 +175,7 @@ ;; CHECK: (func $unreachable (type $2) ;; CHECK-NEXT: (local $ref-imm (ref null $struct-imm)) - ;; CHECK-NEXT: (local.tee $ref-imm + ;; CHECK-NEXT: (local.set $ref-imm ;; CHECK-NEXT: (block ;; (replaces unreachable StructNew we can't emit) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast index 6f5b1af41b3..bd4fc50c5cb 100644 --- a/test/lit/passes/precompute-gc.wast +++ b/test/lit/passes/precompute-gc.wast @@ -1066,7 +1066,7 @@ ;; CHECK: (func $get-nonnullable-in-unreachable (type $10) (result anyref) ;; CHECK-NEXT: (local $x (ref any)) - ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if @@ -1182,7 +1182,7 @@ ;; CHECK: (func $get-nonnullable-in-unreachable-tuple (type $20) (result anyref i32) ;; CHECK-NEXT: (local $x (tuple (ref any) i32)) - ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if diff --git a/test/lit/passes/remove-unused-brs_enable-multivalue.wast b/test/lit/passes/remove-unused-brs_enable-multivalue.wast index efe701e6fd4..f706cd7558f 100644 --- a/test/lit/passes/remove-unused-brs_enable-multivalue.wast +++ b/test/lit/passes/remove-unused-brs_enable-multivalue.wast @@ -3795,7 +3795,7 @@ ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $p) ;; CHECK-NEXT: (then @@ -3858,7 +3858,7 @@ ;; CHECK-NEXT: (block $label$4 (result i64) ;; CHECK-NEXT: (block $label$5 ;; CHECK-NEXT: (block $label$6 - ;; CHECK-NEXT: (local.tee $var$1 + ;; CHECK-NEXT: (local.set $var$1 ;; CHECK-NEXT: (if (result f64) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (then @@ -4055,7 +4055,7 @@ ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $label$2 - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (loop $label$5 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (drop @@ -5193,7 +5193,7 @@ ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/simplify-locals-gc.wast b/test/lit/passes/simplify-locals-gc.wast index 85ec16d99ca..ba7007a361d 100644 --- a/test/lit/passes/simplify-locals-gc.wast +++ b/test/lit/passes/simplify-locals-gc.wast @@ -73,7 +73,7 @@ ;; CHECK: (func $unreachable-struct.get (type $6) (param $x (ref $struct)) (param $y (ref $struct-immutable)) (result i32) ;; CHECK-NEXT: (local $temp i32) - ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (block ;; (replaces unreachable StructGet we can't emit) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) diff --git a/test/lit/passes/tuple-optimization.wast b/test/lit/passes/tuple-optimization.wast index 6ee5cc829b5..fce17ba0ba4 100644 --- a/test/lit/passes/tuple-optimization.wast +++ b/test/lit/passes/tuple-optimization.wast @@ -576,7 +576,7 @@ ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.tee $tuple + ;; CHECK-NEXT: (local.set $tuple ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -586,14 +586,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (tuple.extract 2 1 - ;; CHECK-NEXT: (local.tee $tuple + ;; CHECK-NEXT: (local.set $tuple ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $tuple - ;; CHECK-NEXT: (local.tee $nontuple + ;; CHECK-NEXT: (local.set $tuple + ;; CHECK-NEXT: (local.set $nontuple ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1069,7 +1069,7 @@ ;; CHECK-NEXT: (local $tuple (tuple i32 i64)) ;; CHECK-NEXT: (local $non-tuple i32) ;; CHECK-NEXT: (tuple.extract 2 0 - ;; CHECK-NEXT: (local.tee $non-tuple + ;; CHECK-NEXT: (local.set $non-tuple ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/unsubtyping.wast b/test/lit/passes/unsubtyping.wast index af406571ff2..bbbeb8e7252 100644 --- a/test/lit/passes/unsubtyping.wast +++ b/test/lit/passes/unsubtyping.wast @@ -2030,7 +2030,7 @@ ;; CHECK: (func $test (type $3) (param $C (ref $C)) (result (ref $A) (ref $A)) ;; CHECK-NEXT: (local $Bs (tuple (ref $B) (ref $B))) ;; CHECK-NEXT: (block $l - ;; CHECK-NEXT: (local.tee $Bs + ;; CHECK-NEXT: (local.set $Bs ;; CHECK-NEXT: (block ;; CHECK-NEXT: (tuple.drop 2 ;; CHECK-NEXT: (tuple.make 2 diff --git a/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt b/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt index 8d4847a976b..c07a6cea041 100644 --- a/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt +++ b/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt @@ -4,7 +4,7 @@ (block $label$1 (block $label$2 (loop $label$3 - (local.tee $var$0 + (local.set $var$0 (block $label$4 (unreachable) ) diff --git a/test/passes/simplify-locals_all-features.txt b/test/passes/simplify-locals_all-features.txt index 9daee90a264..72870ef17df 100644 --- a/test/passes/simplify-locals_all-features.txt +++ b/test/passes/simplify-locals_all-features.txt @@ -915,7 +915,7 @@ ) (func $drop-tee-unreachable (type $FUNCSIG$v) (local $x i32) - (local.tee $x + (local.set $x (unreachable) ) (drop diff --git a/test/passes/simplify-locals_all-features_disable-exception-handling.txt b/test/passes/simplify-locals_all-features_disable-exception-handling.txt index 92356286763..0b3b4fe96aa 100644 --- a/test/passes/simplify-locals_all-features_disable-exception-handling.txt +++ b/test/passes/simplify-locals_all-features_disable-exception-handling.txt @@ -909,7 +909,7 @@ ) (func $drop-tee-unreachable (type $FUNCSIG$v) (local $x i32) - (local.tee $x + (local.set $x (unreachable) ) (drop