diff --git a/src/passes/GUFA.cpp b/src/passes/GUFA.cpp index a4567aaea6d..addba6b7ee3 100644 --- a/src/passes/GUFA.cpp +++ b/src/passes/GUFA.cpp @@ -97,8 +97,8 @@ struct GUFAOptimizer std::unordered_map newContents; Expression* replaceCurrent(Expression* rep) { + optimized = true; newContents[rep] = oracle.getContents(getCurrent()); - return WalkerPass< PostWalker>>::replaceCurrent(rep); @@ -140,7 +140,6 @@ struct GUFAOptimizer // code. replaceCurrent(getDroppedChildrenAndAppend( curr, wasm, options, builder.makeUnreachable())); - optimized = true; return; } @@ -169,7 +168,6 @@ struct GUFAOptimizer // valid here. if (Type::isSubType(c->type, curr->type)) { replaceCurrent(getDroppedChildrenAndAppend(curr, wasm, options, c)); - optimized = true; } else { // The type is not compatible: we cannot place |c| in this location, even // though we have proven it is the only value possible here. @@ -214,7 +212,6 @@ struct GUFAOptimizer assert(Properties::isConstantExpression(c)); replaceCurrent(getDroppedChildrenAndAppend( curr, wasm, options, builder.makeUnreachable())); - optimized = true; } } } @@ -391,7 +388,6 @@ struct GUFAOptimizer if (oracleType.isRef() && oracleType != curr->type && Type::isSubType(oracleType, curr->type)) { replaceCurrent(Builder(*getModule()).makeRefCast(curr, oracleType)); - optimized = true; } } }; diff --git a/test/lit/passes/gufa-cast-all.wast b/test/lit/passes/gufa-cast-all.wast index 28248674883..bffd88e7714 100644 --- a/test/lit/passes/gufa-cast-all.wast +++ b/test/lit/passes/gufa-cast-all.wast @@ -392,3 +392,65 @@ ) ) + +;; 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. +(module + ;; CHECK: (type $array (sub (array anyref))) + (type $array (sub (array (ref null any)))) + ;; CHECK: (type $tag-sig (func (param (ref null $array)))) + (type $tag-sig (func (param (ref null $array)))) + ;; CHECK: (type $2 (func)) + + ;; CHECK: (tag $tag (type $tag-sig) (param (ref null $array))) + (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 + ;; CHECK-NEXT: (ref.i31 + ;; CHECK-NEXT: (i32.const 0) + ;; 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: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test + (drop + (try (result (ref i31)) + (do + ;; This doesn't throw, so everything in the catch is unreachable. + (ref.i31 (i32.const 0)) + ) + (catch $tag + (ref.i31 + (ref.eq + (pop (ref null $array)) + (ref.i31 (i32.const 0)) + ) + ) + ) + ) + ) + ) +)