diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index a450b133b32..ac645e77549 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,8 +39,18 @@ 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()); } @@ -122,6 +133,7 @@ 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); } @@ -438,6 +450,8 @@ 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/test/lit/passes/vacuum-eh-legacy.wast b/test/lit/passes/vacuum-eh-legacy.wast index cb780206a55..ba704c94ff8 100644 --- a/test/lit/passes/vacuum-eh-legacy.wast +++ b/test/lit/passes/vacuum-eh-legacy.wast @@ -293,4 +293,56 @@ (catch_all) ) ) + + ;; 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: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $add-block-in-catch-pop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $add-block-in-catch-pop + (local $temp i32) + (try + (do + ;; We need a call so the try does not vanish entirely. + (call $add-block-in-catch-pop) + ) + (catch $e + (drop + ;; This select will be removed, and a block appear, which must be handled + ;; for the pop. + (select + (pop i32) + (local.tee $temp + (i32.const 0) + ) + (i32.const 0) + ) + ) + ;; Needed to avoid the catch being trivial. + (call $add-block-in-catch-pop) + ) + ) + ) )