diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 32fb39f314c..98594e32586 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "ir/eh-utils.h" #include "ir/utils.h" namespace wasm { @@ -140,10 +139,7 @@ void ReFinalize::visitRethrow(Rethrow* curr) { curr->finalize(); } void ReFinalize::visitThrowRef(ThrowRef* curr) { curr->finalize(); } void ReFinalize::visitNop(Nop* curr) { curr->finalize(); } void ReFinalize::visitUnreachable(Unreachable* curr) { curr->finalize(); } -void ReFinalize::visitPop(Pop* curr) { - curr->finalize(); - seenPop = true; -} +void ReFinalize::visitPop(Pop* curr) { curr->finalize(); } void ReFinalize::visitTupleMake(TupleMake* curr) { curr->finalize(); } void ReFinalize::visitTupleExtract(TupleExtract* curr) { curr->finalize(); } void ReFinalize::visitRefI31(RefI31* curr) { curr->finalize(); } @@ -224,11 +220,7 @@ void ReFinalize::visitDataSegment(DataSegment* curr) { WASM_UNREACHABLE("unimp"); } void ReFinalize::visitTag(Tag* curr) { WASM_UNREACHABLE("unimp"); } -void ReFinalize::visitFunction(Function* curr) { - if (seenPop && addedBlock) { - EHUtils::handleBlockNestedPops(curr, *getModule()); - } -} +void ReFinalize::visitFunction(Function* curr) {} void ReFinalize::visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); } void ReFinalize::updateBreakValueType(Name name, Type type) { @@ -251,7 +243,6 @@ void ReFinalize::replaceUntaken(Expression* value, Expression* otherChild) { otherChild = builder.makeDrop(otherChild); } replaceCurrent(builder.makeBlock({value, otherChild}, Type::unreachable)); - addedBlock = true; } else if (value) { replaceCurrent(value); } else { diff --git a/src/ir/eh-utils.cpp b/src/ir/eh-utils.cpp index 19f48477a70..0c78160b1f3 100644 --- a/src/ir/eh-utils.cpp +++ b/src/ir/eh-utils.cpp @@ -15,8 +15,10 @@ */ #include "ir/eh-utils.h" -#include "ir/branch-utils.h" #include "ir/find_all.h" +#include "ir/iteration.h" +#include "ir/properties.h" +#include "wasm-builder.h" namespace wasm { @@ -37,9 +39,6 @@ getFirstPop(Expression* catchBody, bool& isPopNested, Expression**& popPtr) { Expression* firstChild = catchBody; isPopNested = false; popPtr = nullptr; - // When there are multiple expressions within a catch body, an implicit - // block is created within it for convenience purposes. - auto* implicitBlock = catchBody->dynCast(); // Go down the line for the first child until we reach a leaf. A pop should be // in that first-descendant line. @@ -64,24 +63,19 @@ getFirstPop(Expression* catchBody, bool& isPopNested, Expression**& popPtr) { // run more than once return nullptr; } - if (firstChild->is()) { - // If there are no branches that targets the implicit block, it will be - // removed when written back. But if there are branches that target the - // implicit block, + if (auto* block = firstChild->dynCast()) { + // An unnamed block will be removed when written back. But if the block + // has a name, // (catch $e // (block $l0 // (pop i32) ;; within a block! // (br $l0) // ... // ) - // This cannot be removed, so this is considered a nested pop (which we - // should fix). - if (firstChild == implicitBlock) { - if (BranchUtils::BranchSeeker::has(implicitBlock, - implicitBlock->name)) { - isPopNested = true; - } - } else { + // ) + // It may be emitted in the binary format, so this is considered a + // nested pop (which we should fix). + if (block->name.is()) { isPopNested = true; } } else if (firstChild->is() || firstChild->is()) { diff --git a/src/ir/utils.h b/src/ir/utils.h index 44c3ef82869..38cf99c8a00 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -154,10 +154,6 @@ struct ReFinalize // Replace an untaken branch/switch with an unreachable value. // A condition may also exist and may or may not be unreachable. void replaceUntaken(Expression* value, Expression* condition); - - // If we see a pop and also add a block, we need to do EH fixups. - bool seenPop = false; - bool addedBlock = false; }; // Re-finalize a single node. This is slow, if you want to refinalize diff --git a/src/passes/AbstractTypeRefining.cpp b/src/passes/AbstractTypeRefining.cpp index 59ace68d495..b7b12733835 100644 --- a/src/passes/AbstractTypeRefining.cpp +++ b/src/passes/AbstractTypeRefining.cpp @@ -36,7 +36,6 @@ #include #include "ir/drop.h" -#include "ir/eh-utils.h" #include "ir/localize.h" #include "ir/module-utils.h" #include "ir/subtypes.h" @@ -320,7 +319,6 @@ struct AbstractTypeRefining : public Pass { struct Preoptimizer : WalkerPass> { const TypeMapper::TypeUpdates& mapping; - bool addedBlock = false; Preoptimizer(const TypeMapper::TypeUpdates& mapping) : mapping(mapping) {} @@ -331,7 +329,6 @@ struct AbstractTypeRefining : public Pass { } Block* localizeChildren(Expression* curr) { - addedBlock = true; return ChildLocalizer( curr, getFunction(), *getModule(), getPassOptions()) .getChildrenReplacement(); @@ -420,7 +417,6 @@ struct AbstractTypeRefining : public Pass { // optimize to. In this case it must trap. replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref), builder.makeUnreachable())); - addedBlock = true; } else { // The descriptor is abstract, but it has a subtype that is not // (which we want to optimize to). We know this will only succeed if @@ -490,17 +486,10 @@ struct AbstractTypeRefining : public Pass { if (getFunction()) { replaceCurrent(getDroppedChildrenAndAppend( curr, *getModule(), getPassOptions(), builder.makeUnreachable())); - addedBlock = true; } else { curr->desc = builder.makeRefNull(HeapType::none); } } - - void visitFunction(Function* func) { - if (addedBlock) { - EHUtils::handleBlockNestedPops(func, *getModule()); - } - } } preoptimizer(mapping); preoptimizer.run(getPassRunner(), &module); preoptimizer.runOnModuleCode(getPassRunner(), &module); diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp index 7964818121a..91a4c9dd547 100644 --- a/src/passes/CodeFolding.cpp +++ b/src/passes/CodeFolding.cpp @@ -61,7 +61,6 @@ #include "ir/branch-utils.h" #include "ir/effects.h" -#include "ir/eh-utils.h" #include "ir/find_all.h" #include "ir/iteration.h" #include "ir/label-utils.h" @@ -119,9 +118,6 @@ struct CodeFolding // Set when we optimized and believe another pass is warranted. bool anotherPass; - // Set when we optimized in a manner that requires EH fixups specifically, - // which is generally the case when we wrap things in a block. - bool needEHFixups; // pass state @@ -286,7 +282,6 @@ struct CodeFolding anotherPass = true; while (anotherPass) { anotherPass = false; - needEHFixups = false; Super::doWalkFunction(func); optimizeTerminatingTails(unreachableTails); // optimize returns at the end, so we can benefit from a fallthrough if @@ -301,9 +296,6 @@ struct CodeFolding unoptimizables.clear(); modifieds.clear(); exitingBranchCache.clear(); - if (needEHFixups) { - EHUtils::handleBlockNestedPops(func, *getModule()); - } } } @@ -629,7 +621,6 @@ struct CodeFolding // ensure the replacement has the same type, so the outside is not surprised block->finalize(oldType); replaceCurrent(block); - needEHFixups = true; } // optimize tails that terminate control flow in this function, so we @@ -899,7 +890,6 @@ struct CodeFolding // ensure the replacement has the same type, so the outside is not surprised outer->finalize(getFunction()->getResults()); getFunction()->body = outer; - needEHFixups = true; return true; } diff --git a/src/passes/ConstraintAnalysis.cpp b/src/passes/ConstraintAnalysis.cpp index 4854f533c87..d89e709151c 100644 --- a/src/passes/ConstraintAnalysis.cpp +++ b/src/passes/ConstraintAnalysis.cpp @@ -72,7 +72,6 @@ #include "cfg/wto.h" #include "ir/constraint.h" #include "ir/drop.h" -#include "ir/eh-utils.h" #include "ir/literal-utils.h" #include "ir/local-graph.h" #include "ir/properties.h" @@ -390,7 +389,6 @@ struct ConstraintAnalysis if (refinalize) { ReFinalize().walkFunctionInModule(getFunction(), getModule()); - EHUtils::handleBlockNestedPops(getFunction(), *getModule()); } } diff --git a/src/passes/DeadArgumentElimination2.cpp b/src/passes/DeadArgumentElimination2.cpp index 6fd7adfd893..fc2a35bd746 100644 --- a/src/passes/DeadArgumentElimination2.cpp +++ b/src/passes/DeadArgumentElimination2.cpp @@ -44,7 +44,6 @@ #include "analysis/lattices/bool.h" #include "ir/effects.h" -#include "ir/eh-utils.h" #include "ir/intrinsics.h" #include "ir/label-utils.h" #include "ir/local-graph.h" @@ -1113,9 +1112,6 @@ struct Optimizer assert(!hasRemovedResult || !func->body->type.isConcrete()); - // We may have moved pops around. Fix them. - EHUtils::handleBlockNestedPops(func, *wasm); - // We may have introduced a new non-nullable local whose sets do not // structurally dominate its gets. Fix it. if (hasNewNonNullableLocal) { diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp index c82c73998ff..caeb66e7cc1 100644 --- a/src/passes/DeadCodeElimination.cpp +++ b/src/passes/DeadCodeElimination.cpp @@ -28,7 +28,6 @@ // have no side effects. // -#include "ir/eh-utils.h" #include "ir/iteration.h" #include "ir/properties.h" #include "ir/type-updating.h" @@ -56,10 +55,6 @@ struct DeadCodeElimination // as we remove code, we must keep the types of other nodes valid TypeUpdater typeUpdater; - // Information used to decide whether we need EH fixups at the end - bool hasPop = false; // Do we have a 'pop' in this function? - bool addedBlock = false; // Have we added blocks in this function? - Expression* replaceCurrent(Expression* expression) { auto* old = getCurrent(); if (old == expression) { @@ -77,10 +72,6 @@ struct DeadCodeElimination } void visitExpression(Expression* curr) { - if (curr->is()) { - hasPop = true; - } - if (!Properties::isControlFlowStructure(curr)) { // Control flow structures require special handling, but others are // simple. @@ -113,7 +104,6 @@ struct DeadCodeElimination if (remainingChildren.size() == 1) { replaceCurrent(remainingChildren[0]); } else { - addedBlock = true; replaceCurrent(builder.makeBlock(remainingChildren)); } } @@ -195,15 +185,6 @@ struct DeadCodeElimination WASM_UNREACHABLE("unimplemented DCE control flow structure"); } } - - void visitFunction(Function* curr) { - // We conservatively run the EH pop fixup if this function has a 'pop' and - // if we have ever added blocks in the optimization, which may have moved - // pops into the blocks. - if (hasPop && addedBlock) { - EHUtils::handleBlockNestedPops(curr, *getModule()); - } - } }; Pass* createDeadCodeEliminationPass() { return new DeadCodeElimination(); } diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 14f2fe8dacf..8c0840f9588 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -31,7 +31,6 @@ #include "call-utils.h" #include "ir/drop.h" -#include "ir/eh-utils.h" #include "ir/find_all.h" #include "ir/table-utils.h" #include "ir/utils.h" @@ -53,8 +52,6 @@ struct FunctionDirectizer : public WalkerPass> { FunctionDirectizer(const TableUtils::TableInfoMap& tables) : tables(tables) {} - bool optimized = false; - void visitCallIndirect(CallIndirect* curr) { auto& table = tables.at(curr->table); if (!table.canOptimizeByEntry()) { @@ -65,7 +62,6 @@ struct FunctionDirectizer : public WalkerPass> { std::vector operands(curr->operands.begin(), curr->operands.end()); makeDirectCall(operands, curr->target, table, curr); - optimized = true; return; } @@ -78,7 +74,6 @@ struct FunctionDirectizer : public WalkerPass> { *getFunction(), *getModule())) { replaceCurrent(calls); - optimized = true; // Note that types may have changed, as the utility here can add locals // which require fixups if they are non-nullable, for example. changedTypes = true; @@ -86,17 +81,9 @@ struct FunctionDirectizer : public WalkerPass> { } } - bool hasTry = false; - - void visitTry(Try* curr) { hasTry = true; } - void doWalkFunction(Function* func) { WalkerPass>::doWalkFunction(func); - if (optimized && hasTry) { - EHUtils::handleBlockNestedPops(func, *getModule()); - } - if (changedTypes) { ReFinalize().walkFunctionInModule(func, getModule()); } diff --git a/src/passes/Flatten.cpp b/src/passes/Flatten.cpp index 10c791f609e..183a9885ac2 100644 --- a/src/passes/Flatten.cpp +++ b/src/passes/Flatten.cpp @@ -39,7 +39,6 @@ #include #include -#include #include #include #include @@ -376,10 +375,6 @@ struct Flatten } // the body may have preludes curr->body = getPreludesWithExpression(originalBody, curr->body); - - // Flatten can generate blocks within 'catch', making pops invalid. Fix them - // up. - EHUtils::handleBlockNestedPops(curr, *getModule()); } private: diff --git a/src/passes/GUFA.cpp b/src/passes/GUFA.cpp index 533c033524e..cea22d46025 100644 --- a/src/passes/GUFA.cpp +++ b/src/passes/GUFA.cpp @@ -44,7 +44,6 @@ // #include "ir/drop.h" -#include "ir/eh-utils.h" #include "ir/possible-contents.h" #include "ir/properties.h" #include "ir/utils.h" @@ -318,9 +317,6 @@ struct GUFAOptimizer return; } - // We may add blocks around pops, which we must fix up. - EHUtils::handleBlockNestedPops(func, *getModule()); - // If we are in "optimizing" mode, we'll also run some more passes on this // function that we just optimized. If not, leave now. if (!optimizing) { diff --git a/src/passes/GlobalTypeOptimization.cpp b/src/passes/GlobalTypeOptimization.cpp index 5ed3574f4e9..4ed7ccd6e6b 100644 --- a/src/passes/GlobalTypeOptimization.cpp +++ b/src/passes/GlobalTypeOptimization.cpp @@ -22,7 +22,6 @@ // * Fields that are never read from can be removed entirely. // -#include "ir/eh-utils.h" #include "ir/js-utils.h" #include "ir/localize.h" #include "ir/names.h" @@ -677,8 +676,6 @@ struct GlobalTypeOptimization : public Pass { return std::make_unique(parent); } - bool needEHFixups = false; - // Expressions that might trap that have been removed from module-level // initializers. These need to be placed in new globals to preserve any // instantiation-time traps. @@ -710,8 +707,6 @@ struct GlobalTypeOptimization : public Pass { if (func) { ChildLocalizer localizer(curr, func, *getModule(), getPassOptions()); replaceCurrent(localizer.getReplacement()); - // Adding a block here requires EH fixups. - needEHFixups = true; } // Remove and reorder operands. @@ -766,7 +761,6 @@ struct GlobalTypeOptimization : public Pass { getFunction(), getModule(), getPassOptions()); - needEHFixups = true; Expression* replacement = builder.makeDrop(builder.makeRefAs(RefAsNonNull, flipped)); // We only remove fields with no reads, so if this set is atomic, @@ -775,12 +769,6 @@ struct GlobalTypeOptimization : public Pass { replaceCurrent(replacement); } } - - void visitFunction(Function* curr) { - if (needEHFixups) { - EHUtils::handleBlockNestedPops(curr, *getModule()); - } - } }; struct IndexUpdater : public WalkerPass> { diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp index a7b9adb07a7..090bec3af2d 100644 --- a/src/passes/Heap2Local.cpp +++ b/src/passes/Heap2Local.cpp @@ -153,7 +153,6 @@ #include "ir/abstract.h" #include "ir/bits.h" #include "ir/branch-utils.h" -#include "ir/eh-utils.h" #include "ir/local-graph.h" #include "ir/parents.h" #include "ir/properties.h" @@ -1608,16 +1607,9 @@ struct Heap2Local { // some cases, so to be careful here use a fairly small limit. return size < 20; } - - // Also note if a pop exists here, as they may require fixups. - bool hasPop = false; - - void visitPop(Pop* curr) { hasPop = true; } } finder; finder.walk(func->body); - bool optimized = false; - // First, lower non-escaping arrays into structs. That allows us to handle // arrays in a single place, and let all the rest of this pass assume we are // working on structs. We are in fact only optimizing struct-like arrays @@ -1637,7 +1629,6 @@ struct Heap2Local { auto* structNew = Array2Struct(allocation, analyzer, func, wasm).structNew; Struct2Local(structNew, analyzer, func, wasm); - optimized = true; resetAnalysisData(); } } @@ -1654,17 +1645,9 @@ struct Heap2Local { *localGraph, *parents, *branchTargets, passOptions, wasm); if (!analyzer.escapes(allocation)) { Struct2Local(allocation, analyzer, func, wasm); - optimized = true; resetAnalysisData(); } } - - // We conservatively run the EH pop fixup if this function has a 'pop' and - // if we have ever optimized, as all of the things we do here involve - // creating blocks, so we might have moved pops into the blocks. - if (finder.hasPop && optimized) { - EHUtils::handleBlockNestedPops(func, wasm); - } } void resetAnalysisData() { diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index fc06b1da524..12328467dc2 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -268,10 +267,6 @@ struct OptimizeInstructions FinalOptimizer optimizer(getPassOptions()); optimizer.walkFunction(func); } - - // Some patterns create blocks that can interfere 'catch' and 'pop', nesting - // the 'pop' into a block making it invalid. - EHUtils::handleBlockNestedPops(func, *getModule()); } // Set to true when one of the visitors makes a change (either replacing the diff --git a/src/passes/OptimizeNoReturn.cpp b/src/passes/OptimizeNoReturn.cpp index fc4895b0b1e..a58ac8c98a8 100644 --- a/src/passes/OptimizeNoReturn.cpp +++ b/src/passes/OptimizeNoReturn.cpp @@ -23,7 +23,6 @@ // (DeadArgumentElimination) is a convenient place to do that. // -#include "ir/eh-utils.h" #include "ir/intrinsics.h" #include "ir/utils.h" #include "pass.h" @@ -51,14 +50,7 @@ struct OptimizeNoReturn Expression** callp = nullptr; Expression** dropp = nullptr; - // If we optimize in the presence of Trys, we may need to run fixups later. - bool hasTry = false; - void visitExpression(Expression* curr) { - if (curr->is()) { - hasTry = true; - } - if (auto* call = curr->dynCast()) { if (callp) { // There was a call before us, handle it first. @@ -116,9 +108,6 @@ struct OptimizeNoReturn if (refinalize) { ReFinalize().walkFunctionInModule(curr, getModule()); - if (hasTry) { - EHUtils::handleBlockNestedPops(curr, *getModule()); - } } } diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp index bba1e2cba2d..6e9dfed15e9 100644 --- a/src/passes/TypeRefining.cpp +++ b/src/passes/TypeRefining.cpp @@ -25,7 +25,6 @@ // themselves. // -#include "ir/eh-utils.h" #include "ir/find_all.h" #include "ir/lubs.h" #include "ir/possible-contents.h" @@ -399,7 +398,6 @@ struct TypeRefining : public Pass { bool requiresNonNullableLocalFixups() override { return false; } TypeRefining& parent; - bool addedBlock = false; ReadUpdater(TypeRefining& parent) : parent(parent) {} @@ -429,7 +427,6 @@ struct TypeRefining : public Pass { Builder builder(*getModule()); replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref), builder.makeUnreachable())); - addedBlock = true; return; } @@ -459,12 +456,6 @@ struct TypeRefining : public Pass { // ourselves here, before.) curr->type = newFieldType; } - - void visitFunction(Function* func) { - if (addedBlock) { - EHUtils::handleBlockNestedPops(func, *getModule()); - } - } }; ReadUpdater updater(*this); @@ -592,7 +583,6 @@ struct TypeRefining : public Pass { } bool refinalize = false; - bool addedBlock = false; // Fix up a given value so it fits into the type the location it is // written to. @@ -607,7 +597,6 @@ struct TypeRefining : public Pass { Builder builder(*getModule()); auto heapType = type.getHeapType(); if (heapType.isBottom()) { - addedBlock = true; auto* drop = builder.makeDrop(value); if (type.isNonNullableRef()) { // This will just trap. Make it trap, and update parents' types. @@ -624,9 +613,6 @@ struct TypeRefining : public Pass { if (refinalize) { ReFinalize().walkFunctionInModule(func, getModule()); } - if (addedBlock) { - EHUtils::handleBlockNestedPops(func, *getModule()); - } } }; diff --git a/src/passes/Unsubtyping.cpp b/src/passes/Unsubtyping.cpp index 54dd7154b18..cc6b2251fd9 100644 --- a/src/passes/Unsubtyping.cpp +++ b/src/passes/Unsubtyping.cpp @@ -19,7 +19,6 @@ #include #include "ir/effects.h" -#include "ir/eh-utils.h" #include "ir/js-utils.h" #include "ir/localize.h" #include "ir/module-utils.h" @@ -1076,7 +1075,6 @@ struct Unsubtyping : Pass, Noter { // collecting and iterating over all the types, though. struct Rewriter : WalkerPass> { const TypeTree& types; - bool needEHFixups = false; // Allocations that might trap that have been removed from module-level // initializers. These need to be placed in new globals to preserve any @@ -1118,7 +1116,6 @@ struct Unsubtyping : Pass, Noter { block->list.push_back(curr); block->type = curr->type; replaceCurrent(block); - needEHFixups = true; } else { // We are dropping this descriptor, but it might have a potential trap // nested inside it. In that case we need to preserve the trap by @@ -1130,12 +1127,6 @@ struct Unsubtyping : Pass, Noter { } curr->desc = nullptr; } - - void visitFunction(Function* curr) { - if (needEHFixups) { - EHUtils::handleBlockNestedPops(curr, *getModule()); - } - } }; Rewriter rewriter(types); diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index 86938891110..1da4f542a3d 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -39,18 +38,9 @@ struct Vacuum : public WalkerPass> { std::unique_ptr create() override { return std::make_unique(); } - // Track whether we need to fix up pops at the end: adding a block in a Try - // can require that. - bool hasTry = false; - bool addedBlocks = false; - void doWalkFunction(Function* func) { walk(func->body); - if (hasTry && addedBlocks) { - EHUtils::handleBlockNestedPops(func, *getModule()); - } - ReFinalize().walkFunctionInModule(func, getModule()); } @@ -133,7 +123,6 @@ struct Vacuum : public WalkerPass> { if (curr->type.isDefaultable()) { auto* dummy = Builder(*getModule()) .makeConstantExpression(Literal::makeZeros(curr->type)); - addedBlocks = true; return getDroppedChildrenAndAppend( curr, *getModule(), getPassOptions(), dummy); } @@ -448,8 +437,6 @@ struct Vacuum : public WalkerPass> { } void visitTry(Try* curr) { - hasTry = true; - // If try's body does not throw, the whole try-catch can be replaced with // the try's body. if (!EffectAnalyzer(getPassOptions(), *getModule(), curr->body).throws()) { diff --git a/src/passes/param-utils.cpp b/src/passes/param-utils.cpp index bbfbf02134d..c3fbcde8db8 100644 --- a/src/passes/param-utils.cpp +++ b/src/passes/param-utils.cpp @@ -16,7 +16,6 @@ #include "passes/param-utils.h" #include "cfg/liveness-traversal.h" -#include "ir/eh-utils.h" #include "ir/function-utils.h" #include "ir/localize.h" #include "ir/possible-constant.h" @@ -306,19 +305,9 @@ void localizeCallsTo(const std::unordered_set& callTargets, auto* replacement = localizer.getReplacement(); if (replacement != curr) { replaceCurrent(replacement); - optimized = true; onChange(getFunction()); } } - - bool optimized = false; - - void visitFunction(Function* curr) { - if (optimized) { - // Localization can add blocks, which might move pops. - EHUtils::handleBlockNestedPops(curr, *getModule()); - } - } }; LocalizerPass(callTargets, onChange).run(runner, &wasm); @@ -363,15 +352,6 @@ void localizeCallsTo(const std::unordered_set& callTargets, auto* replacement = localizer.getReplacement(); if (replacement != call) { replaceCurrent(replacement); - optimized = true; - } - } - - bool optimized = false; - - void visitFunction(Function* curr) { - if (optimized) { - EHUtils::handleBlockNestedPops(curr, *getModule()); } } }; diff --git a/src/tools/wasm-reduce/wasm-reduce.cpp b/src/tools/wasm-reduce/wasm-reduce.cpp index 4d769ed30c1..a2027ff679e 100644 --- a/src/tools/wasm-reduce/wasm-reduce.cpp +++ b/src/tools/wasm-reduce/wasm-reduce.cpp @@ -28,7 +28,6 @@ #include #include "ir/branch-utils.h" -#include "ir/eh-utils.h" #include "ir/iteration.h" #include "ir/localize.h" #include "ir/properties.h" @@ -1223,8 +1222,6 @@ struct Reducer return std::make_unique(); }; - bool needEHFixups = false; - void visitCall(Call* curr) { // Replace calls to functions we have removed. if (getModule()->getFunctionOrNull(curr->target)) { @@ -1245,9 +1242,6 @@ struct Reducer block->list.push_back(replacement); block->type = originalType; replaceCurrent(block); - // We added a block around content here, possibly causing us to need - // EH fixups later. - needEHFixups = true; } void visitRefFunc(RefFunc* curr) { // Replace references to functions we have removed. @@ -1258,11 +1252,6 @@ struct Reducer replaceCurrent( builder.makeBlock({builder.makeUnreachable()}, curr->type)); } - void visitFunction(Function* curr) { - if (needEHFixups) { - EHUtils::handleBlockNestedPops(curr, *getModule()); - } - } }; PassRunner runner(module.get()); runner.add(std::make_unique()); diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 587ed87db36..12766dff8f9 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1935,17 +1935,34 @@ Result<> IRBuilder::makePop(Type type) { // We don't actually want to create a new Pop expression here because we // already create them automatically when starting a legacy catch block that // needs one. Just verify that the Pop we are being asked to make is the same - // type as the Pop we have already made. - auto& scope = getScope(); - if (!scope.getCatch() || scope.exprStack.size() != 1 || - !scope.exprStack[0]->is()) { + // type as the Pop we have already made, and move it into the current scope if + // we have entered unnamed blocks since the catch began. + ScopeCtx* catchScope = nullptr; + for (int i = int(scopeStack.size()) - 1; i >= 0; --i) { + auto& scope = scopeStack[i]; + if (scope.getCatch()) { + catchScope = &scope; + break; + } + auto* block = scope.getBlock(); + if (!block || block->name || !scope.exprStack.empty()) { + break; + } + } + if (!catchScope || catchScope->exprStack.size() != 1 || + !catchScope->exprStack[0]->is()) { return Err{ "pop instructions may only appear at the beginning of catch blocks"}; } - auto expectedType = scope.exprStack[0]->type; + auto* pop = catchScope->exprStack[0]; + auto expectedType = pop->type; if (!Type::isSubType(expectedType, type)) { return Err{std::string("Expected pop of type ") + expectedType.toString()}; } + if (catchScope != &getScope()) { + catchScope->exprStack.pop_back(); + pushSynthetic(pop); + } return Ok{}; } diff --git a/test/lit/basic/exception-handling-legacy.wast b/test/lit/basic/exception-handling-legacy.wast index d4014fa8ce4..11bdb4ca77c 100644 --- a/test/lit/basic/exception-handling-legacy.wast +++ b/test/lit/basic/exception-handling-legacy.wast @@ -126,7 +126,6 @@ ;; CHECK-BIN-NEXT: (local $1 i64) ;; CHECK-BIN-NEXT: (local $scratch (tuple i32 i64)) ;; CHECK-BIN-NEXT: (local $scratch_3 i32) - ;; CHECK-BIN-NEXT: (local $4 (tuple i32 i64)) ;; CHECK-BIN-NEXT: (try ;; CHECK-BIN-NEXT: (do ;; CHECK-BIN-NEXT: (throw $e-i32-i64 @@ -135,30 +134,25 @@ ;; CHECK-BIN-NEXT: ) ;; CHECK-BIN-NEXT: ) ;; CHECK-BIN-NEXT: (catch $e-i32-i64 - ;; CHECK-BIN-NEXT: (local.set $4 - ;; CHECK-BIN-NEXT: (pop (tuple i32 i64)) - ;; CHECK-BIN-NEXT: ) - ;; CHECK-BIN-NEXT: (block - ;; CHECK-BIN-NEXT: (local.set $x - ;; CHECK-BIN-NEXT: (block (result i32) - ;; CHECK-BIN-NEXT: (local.set $scratch_3 - ;; CHECK-BIN-NEXT: (tuple.extract 2 0 - ;; CHECK-BIN-NEXT: (local.tee $scratch - ;; CHECK-BIN-NEXT: (local.get $4) - ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: (local.set $x + ;; CHECK-BIN-NEXT: (block (result i32) + ;; CHECK-BIN-NEXT: (local.set $scratch_3 + ;; CHECK-BIN-NEXT: (tuple.extract 2 0 + ;; CHECK-BIN-NEXT: (local.tee $scratch + ;; CHECK-BIN-NEXT: (pop (tuple i32 i64)) ;; CHECK-BIN-NEXT: ) ;; CHECK-BIN-NEXT: ) - ;; CHECK-BIN-NEXT: (local.set $1 - ;; CHECK-BIN-NEXT: (tuple.extract 2 1 - ;; CHECK-BIN-NEXT: (local.get $scratch) - ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: (local.set $1 + ;; CHECK-BIN-NEXT: (tuple.extract 2 1 + ;; CHECK-BIN-NEXT: (local.get $scratch) ;; CHECK-BIN-NEXT: ) - ;; CHECK-BIN-NEXT: (local.get $scratch_3) ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: (local.get $scratch_3) ;; CHECK-BIN-NEXT: ) - ;; CHECK-BIN-NEXT: (drop - ;; CHECK-BIN-NEXT: (local.get $x) - ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: (drop + ;; CHECK-BIN-NEXT: (local.get $x) ;; CHECK-BIN-NEXT: ) ;; CHECK-BIN-NEXT: ) ;; CHECK-BIN-NEXT: ) @@ -1390,7 +1384,6 @@ ;; CHECK-BIN-NODEBUG-NEXT: (local $1 i64) ;; CHECK-BIN-NODEBUG-NEXT: (local $scratch (tuple i32 i64)) ;; CHECK-BIN-NODEBUG-NEXT: (local $scratch_3 i32) -;; CHECK-BIN-NODEBUG-NEXT: (local $4 (tuple i32 i64)) ;; CHECK-BIN-NODEBUG-NEXT: (try ;; CHECK-BIN-NODEBUG-NEXT: (do ;; CHECK-BIN-NODEBUG-NEXT: (throw $tag$2 @@ -1399,30 +1392,25 @@ ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: (catch $tag$2 -;; CHECK-BIN-NODEBUG-NEXT: (local.set $4 -;; CHECK-BIN-NODEBUG-NEXT: (pop (tuple i32 i64)) -;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG-NEXT: (block -;; CHECK-BIN-NODEBUG-NEXT: (local.set $0 -;; CHECK-BIN-NODEBUG-NEXT: (block (result i32) -;; CHECK-BIN-NODEBUG-NEXT: (local.set $scratch_3 -;; CHECK-BIN-NODEBUG-NEXT: (tuple.extract 2 0 -;; CHECK-BIN-NODEBUG-NEXT: (local.tee $scratch -;; CHECK-BIN-NODEBUG-NEXT: (local.get $4) -;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: (local.set $0 +;; CHECK-BIN-NODEBUG-NEXT: (block (result i32) +;; CHECK-BIN-NODEBUG-NEXT: (local.set $scratch_3 +;; CHECK-BIN-NODEBUG-NEXT: (tuple.extract 2 0 +;; CHECK-BIN-NODEBUG-NEXT: (local.tee $scratch +;; CHECK-BIN-NODEBUG-NEXT: (pop (tuple i32 i64)) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG-NEXT: (local.set $1 -;; CHECK-BIN-NODEBUG-NEXT: (tuple.extract 2 1 -;; CHECK-BIN-NODEBUG-NEXT: (local.get $scratch) -;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: (local.set $1 +;; CHECK-BIN-NODEBUG-NEXT: (tuple.extract 2 1 +;; CHECK-BIN-NODEBUG-NEXT: (local.get $scratch) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG-NEXT: (local.get $scratch_3) ;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: (local.get $scratch_3) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG-NEXT: (drop -;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) -;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: (drop +;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) diff --git a/test/lit/basic/pop-fixup.wast b/test/lit/basic/pop-fixup.wast index f3578b178a9..fd460ac2116 100644 --- a/test/lit/basic/pop-fixup.wast +++ b/test/lit/basic/pop-fixup.wast @@ -9,18 +9,14 @@ ;; CHECK: (func $stacky (type $0) ;; CHECK-NEXT: (local $scratch i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (local.get $scratch) @@ -39,19 +35,15 @@ ;; CHECK: (func $stacky-later (type $0) ;; CHECK-NEXT: (local $scratch i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) @@ -73,20 +65,16 @@ ;; CHECK: (func $tuple (type $0) ;; CHECK-NEXT: (local $scratch (tuple i32 i32)) ;; CHECK-NEXT: (local $scratch_1 i32) - ;; CHECK-NEXT: (local $2 (tuple i32 i32)) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e2 - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (pop (tuple i32 i32)) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch_1 ;; CHECK-NEXT: (tuple.extract 2 0 ;; CHECK-NEXT: (local.tee $scratch - ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (pop (tuple i32 i32)) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -112,20 +100,16 @@ ;; CHECK: (func $stacky-tuple (type $0) ;; CHECK-NEXT: (local $scratch (tuple i32 i32)) ;; CHECK-NEXT: (local $scratch_1 i32) - ;; CHECK-NEXT: (local $2 (tuple i32 i32)) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e2 - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (pop (tuple i32 i32)) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch_1 ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch - ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (pop (tuple i32 i32)) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (tuple.extract 2 0 @@ -157,21 +141,17 @@ ;; CHECK-NEXT: (local $0 (tuple i32 i32)) ;; CHECK-NEXT: (local $scratch (tuple i32 i32)) ;; CHECK-NEXT: (local $scratch_2 i32) - ;; CHECK-NEXT: (local $3 (tuple i32 i32)) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e2 - ;; CHECK-NEXT: (local.set $3 - ;; CHECK-NEXT: (pop (tuple i32 i32)) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch_2 ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch ;; CHECK-NEXT: (local.tee $0 - ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (pop (tuple i32 i32)) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) diff --git a/test/lit/binary/stacky-eh-legacy.test b/test/lit/binary/stacky-eh-legacy.test index 9c933574c67..c0c1546382f 100644 --- a/test/lit/binary/stacky-eh-legacy.test +++ b/test/lit/binary/stacky-eh-legacy.test @@ -48,19 +48,15 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (local $scratch i32) -;; CHECK-NEXT: (local $4 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag$0 -;; CHECK-NEXT: (local.set $4 -;; CHECK-NEXT: (pop i32) -;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $scratch -;; CHECK-NEXT: (local.get $4) +;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 3) diff --git a/test/lit/binary/stacky-nn-tuple.test b/test/lit/binary/stacky-nn-tuple.test index c7ab57e9090..13a8aaae020 100644 --- a/test/lit/binary/stacky-nn-tuple.test +++ b/test/lit/binary/stacky-nn-tuple.test @@ -57,64 +57,58 @@ ;; CHECK-NEXT: (local $scratch_4 (ref null $0)) ;; CHECK-NEXT: (local $scratch_5 (ref null $0)) ;; CHECK-NEXT: (local $scratch_6 (ref null $0)) -;; CHECK-NEXT: (local $7 (tuple (ref null $0) (ref null $1))) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag$0 -;; CHECK-NEXT: (local.set $7 -;; CHECK-NEXT: (pop (tuple (ref null $0) (ref null $1))) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (block -;; CHECK-NEXT: (local.set $0 -;; CHECK-NEXT: (block (result (ref null $0)) -;; CHECK-NEXT: (local.set $scratch_4 -;; CHECK-NEXT: (tuple.extract 2 0 -;; CHECK-NEXT: (local.tee $scratch -;; CHECK-NEXT: (local.get $7) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (local.set $1 -;; CHECK-NEXT: (tuple.extract 2 1 -;; CHECK-NEXT: (local.get $scratch) +;; CHECK-NEXT: (local.set $0 +;; CHECK-NEXT: (block (result (ref null $0)) +;; CHECK-NEXT: (local.set $scratch_4 +;; CHECK-NEXT: (tuple.extract 2 0 +;; CHECK-NEXT: (local.tee $scratch +;; CHECK-NEXT: (pop (tuple (ref null $0) (ref null $1))) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (local.get $scratch_4) ;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (drop -;; CHECK-NEXT: (ref.as_non_null -;; CHECK-NEXT: (block (result (ref null $0)) -;; CHECK-NEXT: (local.set $scratch_5 -;; CHECK-NEXT: (local.get $0) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (drop -;; CHECK-NEXT: (local.get $1) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (local.get $scratch_5) +;; CHECK-NEXT: (local.set $1 +;; CHECK-NEXT: (tuple.extract 2 1 +;; CHECK-NEXT: (local.get $scratch) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) +;; CHECK-NEXT: (local.get $scratch_4) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (drop +;; CHECK-NEXT: ) +;; CHECK-NEXT: (drop +;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (block (result (ref null $0)) -;; CHECK-NEXT: (local.set $scratch_6 +;; CHECK-NEXT: (local.set $scratch_5 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (local.set $2 +;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (local.get $scratch_6) +;; CHECK-NEXT: (local.get $scratch_5) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (drop -;; CHECK-NEXT: (ref.as_non_null -;; CHECK-NEXT: (local.get $2) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (drop +;; CHECK-NEXT: (block (result (ref null $0)) +;; CHECK-NEXT: (local.set $scratch_6 +;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) +;; CHECK-NEXT: (local.set $2 +;; CHECK-NEXT: (local.get $1) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (local.get $scratch_6) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (drop +;; CHECK-NEXT: (ref.as_non_null +;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) -;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) +;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/abstract-type-refining-desc.wast b/test/lit/passes/abstract-type-refining-desc.wast index 1b4966b88aa..7b0ab882917 100644 --- a/test/lit/passes/abstract-type-refining-desc.wast +++ b/test/lit/passes/abstract-type-refining-desc.wast @@ -1297,18 +1297,14 @@ (tag $tag-any (param anyref)) ;; YESTNH: (func $struct-new-pop (type $7) - ;; YESTNH-NEXT: (local $0 (ref none)) ;; YESTNH-NEXT: (try ;; YESTNH-NEXT: (do ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (catch $tag-desc - ;; YESTNH-NEXT: (local.set $0 - ;; YESTNH-NEXT: (pop (ref none)) - ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (drop ;; YESTNH-NEXT: (block ;; YESTNH-NEXT: (drop - ;; YESTNH-NEXT: (local.get $0) + ;; YESTNH-NEXT: (pop (ref none)) ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (unreachable) ;; YESTNH-NEXT: ) @@ -1317,18 +1313,14 @@ ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: ) ;; NO_TNH: (func $struct-new-pop (type $7) - ;; NO_TNH-NEXT: (local $0 (ref none)) ;; NO_TNH-NEXT: (try ;; NO_TNH-NEXT: (do ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (catch $tag-desc - ;; NO_TNH-NEXT: (local.set $0 - ;; NO_TNH-NEXT: (pop (ref none)) - ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (drop ;; NO_TNH-NEXT: (block ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (local.get $0) + ;; NO_TNH-NEXT: (pop (ref none)) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (unreachable) ;; NO_TNH-NEXT: ) @@ -1337,8 +1329,8 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) (func $struct-new-pop - ;; Wrapping a dropped pop in a block when replacing an impossible - ;; struct.new_default_desc requires fixing up the block-nested pop. + ;; Wrapping a dropped pop in an unnamed block when replacing an impossible + ;; struct.new_default_desc validates properly even with a pop. (try (do) (catch $tag-desc @@ -1352,18 +1344,14 @@ ) ;; YESTNH: (func $ref-get-desc-pop (type $7) - ;; YESTNH-NEXT: (local $0 (ref $struct)) ;; YESTNH-NEXT: (try ;; YESTNH-NEXT: (do ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (catch $tag-struct - ;; YESTNH-NEXT: (local.set $0 - ;; YESTNH-NEXT: (pop (ref $struct)) - ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (drop ;; YESTNH-NEXT: (block ;; YESTNH-NEXT: (drop - ;; YESTNH-NEXT: (local.get $0) + ;; YESTNH-NEXT: (pop (ref $struct)) ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (unreachable) ;; YESTNH-NEXT: ) @@ -1372,18 +1360,14 @@ ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: ) ;; NO_TNH: (func $ref-get-desc-pop (type $7) - ;; NO_TNH-NEXT: (local $0 (ref $struct)) ;; NO_TNH-NEXT: (try ;; NO_TNH-NEXT: (do ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (catch $tag-struct - ;; NO_TNH-NEXT: (local.set $0 - ;; NO_TNH-NEXT: (pop (ref $struct)) - ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (drop ;; NO_TNH-NEXT: (block ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (local.get $0) + ;; NO_TNH-NEXT: (pop (ref $struct)) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (unreachable) ;; NO_TNH-NEXT: ) @@ -1408,18 +1392,14 @@ ;; YESTNH: (func $ref-cast-desc-pop (type $8) (param $desc (ref null $desc2)) ;; YESTNH-NEXT: (local $1 anyref) ;; YESTNH-NEXT: (local $2 (ref null $desc2)) - ;; YESTNH-NEXT: (local $3 anyref) ;; YESTNH-NEXT: (try ;; YESTNH-NEXT: (do ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (catch $tag-any - ;; YESTNH-NEXT: (local.set $3 - ;; YESTNH-NEXT: (pop anyref) - ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (drop ;; YESTNH-NEXT: (block (result (ref none)) ;; YESTNH-NEXT: (local.set $1 - ;; YESTNH-NEXT: (local.get $3) + ;; YESTNH-NEXT: (pop anyref) ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (local.set $2 ;; YESTNH-NEXT: (local.get $desc) @@ -1435,18 +1415,14 @@ ;; NO_TNH: (func $ref-cast-desc-pop (type $8) (param $desc (ref null $desc2)) ;; NO_TNH-NEXT: (local $1 anyref) ;; NO_TNH-NEXT: (local $2 (ref $desc2)) - ;; NO_TNH-NEXT: (local $3 anyref) ;; NO_TNH-NEXT: (try ;; NO_TNH-NEXT: (do ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (catch $tag-any - ;; NO_TNH-NEXT: (local.set $3 - ;; NO_TNH-NEXT: (pop anyref) - ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (drop ;; NO_TNH-NEXT: (block (result (ref none)) ;; NO_TNH-NEXT: (local.set $1 - ;; NO_TNH-NEXT: (local.get $3) + ;; NO_TNH-NEXT: (pop anyref) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (local.set $2 ;; NO_TNH-NEXT: (ref.as_non_null @@ -1462,7 +1438,7 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) (func $ref-cast-desc-pop (param $desc (ref null $desc2)) - ;; Same for ref.cast_desc_eq localized into a block. + ;; Same for ref.cast_desc_eq localized into an unnamed block. (try (do) (catch $tag-any @@ -1479,20 +1455,16 @@ ;; YESTNH: (func $br-on-cast-desc-pop (type $8) (param $desc (ref null $desc2)) ;; YESTNH-NEXT: (local $1 anyref) ;; YESTNH-NEXT: (local $2 (ref null $desc2)) - ;; YESTNH-NEXT: (local $3 anyref) ;; YESTNH-NEXT: (drop ;; YESTNH-NEXT: (block $l (result (ref none)) ;; YESTNH-NEXT: (try ;; YESTNH-NEXT: (do ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (catch $tag-any - ;; YESTNH-NEXT: (local.set $3 - ;; YESTNH-NEXT: (pop anyref) - ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (drop ;; YESTNH-NEXT: (block (result anyref) ;; YESTNH-NEXT: (local.set $1 - ;; YESTNH-NEXT: (local.get $3) + ;; YESTNH-NEXT: (pop anyref) ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: (local.set $2 ;; YESTNH-NEXT: (local.get $desc) @@ -1511,20 +1483,16 @@ ;; NO_TNH: (func $br-on-cast-desc-pop (type $8) (param $desc (ref null $desc2)) ;; NO_TNH-NEXT: (local $1 anyref) ;; NO_TNH-NEXT: (local $2 (ref $desc2)) - ;; NO_TNH-NEXT: (local $3 anyref) ;; NO_TNH-NEXT: (drop ;; NO_TNH-NEXT: (block $l (result (ref none)) ;; NO_TNH-NEXT: (try ;; NO_TNH-NEXT: (do ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (catch $tag-any - ;; NO_TNH-NEXT: (local.set $3 - ;; NO_TNH-NEXT: (pop anyref) - ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (drop ;; NO_TNH-NEXT: (block (result anyref) ;; NO_TNH-NEXT: (local.set $1 - ;; NO_TNH-NEXT: (local.get $3) + ;; NO_TNH-NEXT: (pop anyref) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (local.set $2 ;; NO_TNH-NEXT: (ref.as_non_null @@ -1543,7 +1511,7 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) (func $br-on-cast-desc-pop (param $desc (ref null $desc2)) - ;; Same for br_on_cast_desc_eq localized into a block. + ;; Same for br_on_cast_desc_eq localized into an unnamed block. (drop (block $l (result (ref $struct2)) (try diff --git a/test/lit/passes/code-folding-eh-legacy.wast b/test/lit/passes/code-folding-eh-legacy.wast index a2fc562c926..7128cfed0da 100644 --- a/test/lit/passes/code-folding-eh-legacy.wast +++ b/test/lit/passes/code-folding-eh-legacy.wast @@ -341,29 +341,23 @@ ) ;; CHECK: (func $if-arms-in-catch (type $0) (result i32) - ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e-i32 - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -373,8 +367,8 @@ (unreachable) ) (catch $e-i32 - ;; These if arms can be folded, after which the if is replaced by a - ;; block, so we need a fixup for the pop. + ;; These if arms can be folded, after which the if is replaced by an + ;; unnamed block, which validates properly even with a pop. (if (pop i32) (then diff --git a/test/lit/passes/constraint-analysis-eh.wast b/test/lit/passes/constraint-analysis-eh.wast index 47e9cb27713..358aab2c926 100644 --- a/test/lit/passes/constraint-analysis-eh.wast +++ b/test/lit/passes/constraint-analysis-eh.wast @@ -37,31 +37,25 @@ ;; CHECK: (func $pop-unreachable-result (type $2) (result i32) ;; CHECK-NEXT: (local $x i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $pop-unreachable-result (result i32) (local $x i32) - ;; As above, but now with a result. This adds a block we need to fix up EH - ;; for. + ;; As above, but now with a result. This adds an unnamed block, which + ;; validates properly even with a pop. (try (result i32) (do (i32.const 10) diff --git a/test/lit/passes/constraint-analysis.wast b/test/lit/passes/constraint-analysis.wast index b5bba9857d5..d444460146d 100644 --- a/test/lit/passes/constraint-analysis.wast +++ b/test/lit/passes/constraint-analysis.wast @@ -7267,7 +7267,7 @@ (local.get $x) ) ) - + ;; CHECK: (func $asymmetric-contradiction (type $2) (param $0 i32) (param $1 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.and diff --git a/test/lit/passes/dae2.wast b/test/lit/passes/dae2.wast index a74e9709612..94d184f8486 100644 --- a/test/lit/passes/dae2.wast +++ b/test/lit/passes/dae2.wast @@ -3402,24 +3402,18 @@ (tag $e (param i32)) ;; CHECK: (func $test (type $0) - ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $callee) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (call $callee) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -3430,7 +3424,7 @@ ) (catch $e ;; When we optimize out the parameter, the dropped pop will be inside a - ;; new block. This is invalid, so we must fix it up. + ;; new unnamed block, which validates properly even with a pop. (call $callee (pop i32) ) diff --git a/test/lit/passes/dce-eh-legacy.wast b/test/lit/passes/dce-eh-legacy.wast index 2bc87f0819b..7f792fb96b8 100644 --- a/test/lit/passes/dce-eh-legacy.wast +++ b/test/lit/passes/dce-eh-legacy.wast @@ -118,23 +118,17 @@ ) ;; CHECK: (func $call-pop-catch (type $0) - ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $label ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e-i32 - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $label) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $label) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -147,8 +141,8 @@ (nop) ) (catch $e-i32 - ;; This call is unreachable and can be removed. The pop, however, must - ;; be carefully handled while we do so, to not break validation. + ;; This call is unreachable and can be removed, leaving the pop in an + ;; unnamed block, which validates properly. (call $helper-i32-i32 (pop i32) (br $label) @@ -167,24 +161,18 @@ ) ;; CHECK: (func $pop-within-block (type $4) (result i32) - ;; CHECK-NEXT: (local $0 eqref) ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e-eqref - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop eqref) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (pop eqref) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -196,16 +184,8 @@ ) (catch $e-eqref (drop - ;; Optimization moves the 'pop' inside a block, which needs to be - ;; extracted out of the block at the end. - ;; (block - ;; (drop - ;; (struct.new $struct.0 - ;; (pop eqref) - ;; ) - ;; ) - ;; (unreachable) - ;; ) + ;; Optimization moves the 'pop' inside an unnamed block, which + ;; validates properly even with a pop. (ref.eq (struct.new $struct (pop (ref null eq)) diff --git a/test/lit/passes/directize_all-features.wast b/test/lit/passes/directize_all-features.wast index 8973492c671..f1725d60e15 100644 --- a/test/lit/passes/directize_all-features.wast +++ b/test/lit/passes/directize_all-features.wast @@ -2000,18 +2000,14 @@ (elem (i32.const 0) $0) ;; CHECK: (func $0 (type $ii) (param $0 i32) (result i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -2021,18 +2017,14 @@ ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; IMMUT: (func $0 (type $ii) (param $0 i32) (result i32) - ;; IMMUT-NEXT: (local $1 i32) ;; IMMUT-NEXT: (try ;; IMMUT-NEXT: (do ;; IMMUT-NEXT: ) ;; IMMUT-NEXT: (catch $e - ;; IMMUT-NEXT: (local.set $1 - ;; IMMUT-NEXT: (pop i32) - ;; IMMUT-NEXT: ) ;; IMMUT-NEXT: (drop ;; IMMUT-NEXT: (block ;; IMMUT-NEXT: (drop - ;; IMMUT-NEXT: (local.get $1) + ;; IMMUT-NEXT: (pop i32) ;; IMMUT-NEXT: ) ;; IMMUT-NEXT: (unreachable) ;; IMMUT-NEXT: ) @@ -2046,7 +2038,7 @@ (do) (catch $e ;; This is out of bounds (100 is far too large), so this will trap. We emit - ;; a block with the pop, and must handle that properly. + ;; an unnamed block with the pop, which validates properly. (drop (call_indirect (type $ii) (pop i32) diff --git a/test/lit/passes/flatten-eh-legacy.wast b/test/lit/passes/flatten-eh-legacy.wast index 3d22b41a4e5..2d4341ab97a 100644 --- a/test/lit/passes/flatten-eh-legacy.wast +++ b/test/lit/passes/flatten-eh-legacy.wast @@ -57,36 +57,29 @@ ;; CHECK: (func $try_catch_pop_fixup (type $1) ;; CHECK-NEXT: (local $0 i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (block $l0 ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e-i32 - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $l0) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $l0) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $try_catch_pop_fixup - ;; After --flatten, a block is created within the 'catch', which makes the - ;; pop's location invalid. This tests whether it is fixed up correctly after - ;; --flatten. + ;; After --flatten, an unnamed block is created within the 'catch', which + ;; validates properly even with a pop. (block $l0 (try (do) @@ -179,7 +172,6 @@ ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (local $4 i32) - ;; CHECK-NEXT: (local $5 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (local.set $3 @@ -187,26 +179,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e-i32 - ;; CHECK-NEXT: (local.set $5 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $5) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $3 - ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast index 98b0ef505ec..da1cce7add6 100644 --- a/test/lit/passes/gto-removals.wast +++ b/test/lit/passes/gto-removals.wast @@ -1640,8 +1640,8 @@ ) ) -;; A struct with a pop, which requires EH fixups to avoid popping in a nested -;; block. +;; A struct with a pop. The block we emit is unnamed, and validates properly +;; even with a pop. (module ;; CHECK: (rec ;; CHECK-NEXT: (type $struct (struct)) @@ -1658,18 +1658,14 @@ ;; CHECK: (func $func (type $1) ;; CHECK-NEXT: (local $0 i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref (exact $struct))) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gufa-cast-all.wast b/test/lit/passes/gufa-cast-all.wast index acbe4d9c562..b0b61925fde 100644 --- a/test/lit/passes/gufa-cast-all.wast +++ b/test/lit/passes/gufa-cast-all.wast @@ -393,10 +393,9 @@ ) -;; Regression test for bug where optimizing expressions containing a Pop could -;; result in the Pop becoming invalidly nested inside a Block (created to -;; preserve side effects), and the optimizer failed to run the nested pop fixup -;; because it didn't mark the function as optimized. +;; Optimizing expressions containing a Pop results in the Pop being nested +;; inside unnamed Blocks (created to preserve side effects), which validate +;; properly even with a pop. (module ;; CHECK: (type $array (sub (array anyref))) (type $array (sub (array (ref null any)))) @@ -408,7 +407,6 @@ (tag $tag (type $tag-sig) (param (ref null $array))) ;; CHECK: (func $test (type $2) - ;; CHECK-NEXT: (local $0 (ref null $array)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (try (result (ref i31)) ;; CHECK-NEXT: (do @@ -417,14 +415,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop (ref null $array)) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.i31 ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (pop (ref null $array)) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 173d086e918..294a1311222 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -1914,7 +1914,6 @@ (tag $empty (param)) ;; CHECK: (func $func (type $0) - ;; CHECK-NEXT: (local $0 anyref) ;; CHECK-NEXT: (throw $nothing ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) @@ -1922,15 +1921,12 @@ ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $nothing - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop anyref) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (pop anyref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) @@ -2140,7 +2136,6 @@ (tag $tag (param (ref null any)) (param (ref null any))) ;; CHECK: (func $func (type $1) - ;; CHECK-NEXT: (local $0 (tuple anyref anyref)) ;; CHECK-NEXT: (throw $tag ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (struct.new_default $struct) @@ -2149,13 +2144,10 @@ ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop (tuple anyref anyref)) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (tuple.drop 2 - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (pop (tuple anyref anyref)) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) @@ -4169,7 +4161,6 @@ ) ;; CHECK: (func $rethrow (type $0) - ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (try $l0 ;; CHECK-NEXT: (do ;; CHECK-NEXT: (throw $e-i32 @@ -4177,20 +4168,15 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e-i32 - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (rethrow $l0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (rethrow $l0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gufa-tags.wast b/test/lit/passes/gufa-tags.wast index 4bac560900b..2429e4cb246 100644 --- a/test/lit/passes/gufa-tags.wast +++ b/test/lit/passes/gufa-tags.wast @@ -17,8 +17,6 @@ (tag $tag$f32 (param f32)) ;; CHECK: (func $test (type $2) - ;; CHECK-NEXT: (local $0 i32) - ;; CHECK-NEXT: (local $1 f32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (throw $tag$i32 @@ -26,26 +24,20 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag$i32 - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag$f32 - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop f32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (pop f32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast index 11d9659db5f..63d1422a484 100644 --- a/test/lit/passes/heap2local.wast +++ b/test/lit/passes/heap2local.wast @@ -4485,7 +4485,7 @@ ) ) -;; Pops require fixups. +;; Pops in unnamed blocks. (module (type $struct (struct (field (mut i32)))) @@ -4503,19 +4503,15 @@ ;; CHECK: (func $struct-with-pop (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (local.get $1) @@ -4533,8 +4529,8 @@ ) (catch $tag (drop - ;; We create a block when we replace the struct with locals, which the - ;; pop must be moved out of. + ;; We create an unnamed block when we replace the struct with locals, + ;; which validates properly even with a pop. (struct.new $struct (pop i32) ) @@ -4551,19 +4547,15 @@ ;; CHECK-NEXT: (local $4 i32) ;; CHECK-NEXT: (local $5 i32) ;; CHECK-NEXT: (local $6 i32) - ;; CHECK-NEXT: (local $7 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $7 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref null $2)) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $7) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $4 diff --git a/test/lit/passes/inlining-eh-legacy.wast b/test/lit/passes/inlining-eh-legacy.wast index ac59e520211..f318df6aa16 100644 --- a/test/lit/passes/inlining-eh-legacy.wast +++ b/test/lit/passes/inlining-eh-legacy.wast @@ -1,5 +1,6 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. ;; RUN: wasm-opt %s --inlining -all -S -o - | filecheck %s +;; RUN: wasm-opt %s --inlining --roundtrip -all -q (module ;; --------------------------------------------------------------------------- @@ -102,13 +103,17 @@ ;; CHECK: (func $caller-with-pop (type $0) ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag$0 + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $__inlined_func$callee-b$2 ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: ) @@ -120,10 +125,9 @@ (try (do) (catch $tag$0 - ;; After this $callee-b is inlined, there will be an additional block - ;; surrounding this 'pop'. However, that block has no breaks to it, and - ;; will be considered the implicit block of the catch scope, so no - ;; fixups are done. + ;; After this $callee-b is inlined, there will be a named block + ;; surrounding this 'pop', so we fix it up by hoisting the 'pop' to a + ;; local. (call $callee-b (pop i32) ) diff --git a/test/lit/passes/optimize-noreturn.wast b/test/lit/passes/optimize-noreturn.wast index 344a4555de2..f314471a425 100644 --- a/test/lit/passes/optimize-noreturn.wast +++ b/test/lit/passes/optimize-noreturn.wast @@ -232,7 +232,6 @@ ) ;; CHECK: (func $pop (type $0) - ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (throw $e @@ -240,23 +239,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (call $defined-param - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (call $defined-param + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $pop - ;; After adding a block with an unreachable, the pop will need handling. + ;; After adding an unnamed block with an unreachable, this still validates + ;; properly even with a pop. (try (do (throw $e (i32.const 1)) diff --git a/test/lit/passes/signature-pruning.wast b/test/lit/passes/signature-pruning.wast index d86e855dbe8..cea131adf6c 100644 --- a/test/lit/passes/signature-pruning.wast +++ b/test/lit/passes/signature-pruning.wast @@ -982,33 +982,27 @@ ;; CHECK: (func $catch-pop (type $1) (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (block $block (result i32) ;; CHECK-NEXT: (try $try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (br_if $block - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $target - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (br_if $block + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (call $target + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 3) @@ -1024,15 +1018,14 @@ (call $target (pop i32) ;; We can remove this parameter by moving it to a local first, which - ;; also moves the pop, which then needs to be fixed up. + ;; also moves the pop into an unnamed block. (br_if $block (i32.const 1) (i32.const 2) ) ) - ;; This nop causes the call to be in a block. When we add another - ;; block to hold the code that we move, we'd get an error if we don't - ;; apply fixups. + ;; This nop causes the call to be in a block. The block we add to hold + ;; the moved code is unnamed, and validates properly even with a pop. (nop) ) ) @@ -1069,33 +1062,27 @@ ;; CHECK: (func $catch-pop (type $1) (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (block $block (result i32) ;; CHECK-NEXT: (try $try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (br_if $block - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $target - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (br_if $block + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (call $target + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 3) diff --git a/test/lit/passes/type-refining-gufa.wast b/test/lit/passes/type-refining-gufa.wast index 5975e8fb3da..b6d54dbae73 100644 --- a/test/lit/passes/type-refining-gufa.wast +++ b/test/lit/passes/type-refining-gufa.wast @@ -925,8 +925,8 @@ ) ) -;; Handle block-nested pops created when updating writes to and reads from -;; refined fields. +;; Verify that blocks created around pops when updating writes to and reads from +;; refined fields are unnamed and validate properly. (module ;; NRML: (rec ;; NRML-NEXT: (type $struct (struct (field eqref) (field nullref))) @@ -978,7 +978,6 @@ ;; GUFA: (export "read" (func $read)) ;; GUFA: (func $write (type $3) - ;; GUFA-NEXT: (local $0 eqref) ;; GUFA-NEXT: (drop ;; GUFA-NEXT: (struct.new_default $struct) ;; GUFA-NEXT: ) @@ -986,14 +985,11 @@ ;; GUFA-NEXT: (do ;; GUFA-NEXT: ) ;; GUFA-NEXT: (catch $ref - ;; GUFA-NEXT: (local.set $0 - ;; GUFA-NEXT: (pop eqref) - ;; GUFA-NEXT: ) ;; GUFA-NEXT: (drop ;; GUFA-NEXT: (struct.new $struct ;; GUFA-NEXT: (block (result nullref) ;; GUFA-NEXT: (drop - ;; GUFA-NEXT: (local.get $0) + ;; GUFA-NEXT: (pop eqref) ;; GUFA-NEXT: ) ;; GUFA-NEXT: (ref.null none) ;; GUFA-NEXT: ) @@ -1014,8 +1010,8 @@ ;; O3O3-NEXT: ) (func $write (export "write") ;; In GUFA, the first field is refined to nullref, so the write operand in - ;; the catch block is replaced with a block that drops the pop and produces - ;; a null. The newly nested pop must be fixed up. + ;; the catch block is replaced with an unnamed block that drops the pop and + ;; produces a null, which validates properly even with a pop. (drop (struct.new_default $struct) ) @@ -1033,18 +1029,14 @@ ) ;; NRML: (func $read (type $3) - ;; NRML-NEXT: (local $0 nullref) ;; NRML-NEXT: (try ;; NRML-NEXT: (do ;; NRML-NEXT: ) ;; NRML-NEXT: (catch $null - ;; NRML-NEXT: (local.set $0 - ;; NRML-NEXT: (pop nullref) - ;; NRML-NEXT: ) ;; NRML-NEXT: (drop ;; NRML-NEXT: (block ;; NRML-NEXT: (drop - ;; NRML-NEXT: (local.get $0) + ;; NRML-NEXT: (pop nullref) ;; NRML-NEXT: ) ;; NRML-NEXT: (unreachable) ;; NRML-NEXT: ) @@ -1053,18 +1045,14 @@ ;; NRML-NEXT: ) ;; NRML-NEXT: ) ;; GUFA: (func $read (type $3) - ;; GUFA-NEXT: (local $0 nullref) ;; GUFA-NEXT: (try ;; GUFA-NEXT: (do ;; GUFA-NEXT: ) ;; GUFA-NEXT: (catch $null - ;; GUFA-NEXT: (local.set $0 - ;; GUFA-NEXT: (pop nullref) - ;; GUFA-NEXT: ) ;; GUFA-NEXT: (drop ;; GUFA-NEXT: (block ;; GUFA-NEXT: (drop - ;; GUFA-NEXT: (local.get $0) + ;; GUFA-NEXT: (pop nullref) ;; GUFA-NEXT: ) ;; GUFA-NEXT: (unreachable) ;; GUFA-NEXT: ) @@ -1073,8 +1061,8 @@ ;; GUFA-NEXT: ) ;; GUFA-NEXT: ) (func $read (export "read") - ;; Reading from a null reference is replaced with a block that drops the pop - ;; and traps. The newly nested pop must be fixed up. + ;; Reading from a null reference is replaced with an unnamed block that + ;; drops the pop and traps, which validates properly even with a pop. (try (do) (catch $null diff --git a/test/lit/passes/unsubtyping-desc.wast b/test/lit/passes/unsubtyping-desc.wast index 787d9338335..daf93d80f5c 100644 --- a/test/lit/passes/unsubtyping-desc.wast +++ b/test/lit/passes/unsubtyping-desc.wast @@ -1242,8 +1242,7 @@ ) ;; Removing a descriptor from a struct.new_desc uses ChildLocalizer, which wraps -;; the allocation in a block. Ensure any nested `pop` inside a catch block is -;; hoisted out of the new block so the IR remains valid. +;; the allocation in an unnamed block, which validates properly even with a pop. (module (rec ;; CHECK: (rec @@ -1260,18 +1259,14 @@ (tag $e (param (ref (exact $A.desc)))) ;; CHECK: (func $pop-in-struct-new-desc (type $3) ;; CHECK-NEXT: (local $0 (ref (exact $A.desc))) - ;; CHECK-NEXT: (local $1 (ref (exact $A.desc))) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop (ref (exact $A.desc))) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref (exact $A))) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (pop (ref (exact $A.desc))) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.new_default $A) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/vacuum-eh-legacy.wast b/test/lit/passes/vacuum-eh-legacy.wast index ba704c94ff8..c98774f3854 100644 --- a/test/lit/passes/vacuum-eh-legacy.wast +++ b/test/lit/passes/vacuum-eh-legacy.wast @@ -296,28 +296,22 @@ ;; CHECK: (func $add-block-in-catch-pop (type $void) ;; CHECK-NEXT: (local $temp i32) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (call $add-block-in-catch-pop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $add-block-in-catch-pop) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $add-block-in-catch-pop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -330,8 +324,8 @@ ) (catch $e (drop - ;; This select will be removed, and a block appear, which must be handled - ;; for the pop. + ;; This select will be removed, and an unnamed block will appear, + ;; which validates properly even with a pop. (select (pop i32) (local.tee $temp diff --git a/test/lit/passes/vacuum-eh-pop.wast b/test/lit/passes/vacuum-eh-pop.wast index f3ab99031a3..ac58759fcc5 100644 --- a/test/lit/passes/vacuum-eh-pop.wast +++ b/test/lit/passes/vacuum-eh-pop.wast @@ -12,7 +12,6 @@ (tag $tag (type $func) (param i32)) ;; CHECK: (func $test (type $1) (result i32) - ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $block (result i32) ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do @@ -21,13 +20,10 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $tag - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (pop i32) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -40,9 +36,9 @@ (func $test (result i32) (block $block (result i32) ;; Vacuum cannot simplify the body here, but it will make a change to the - ;; unreachable br_if, replacing it with its dropped children (as the branch - ;; is untaken, and we want to remove that reference to $block). While doing - ;; so we must update the IR to handle the pop. + ;; unreachable br_if, replacing it with an unnamed block containing its + ;; dropped children (as the branch is untaken, and we want to remove that + ;; reference to $block), which validates properly even with a pop. (try (do (call $import diff --git a/test/spec/exception-handling-legacy.wast b/test/spec/exception-handling-legacy.wast index 6b463187762..c485474048f 100644 --- a/test/spec/exception-handling-legacy.wast +++ b/test/spec/exception-handling-legacy.wast @@ -535,8 +535,8 @@ (do) (catch $e-i32 (throw $e-i32 - (block (result i32) - (pop i32) ;; pop is within a block + (block $l0 (result i32) + (pop i32) ;; pop is within a named block ) ) )