diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 4 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-iit-eh.wast | 58 |
2 files changed, 62 insertions, 0 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 80ca7162c..347ebbbe4 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -26,6 +26,7 @@ #include <ir/bits.h> #include <ir/cost.h> #include <ir/effects.h> +#include <ir/eh-utils.h> #include <ir/find_all.h> #include <ir/gc-type-utils.h> #include <ir/iteration.h> @@ -229,6 +230,9 @@ struct OptimizeInstructions // Some patterns create locals (like when we use getResultOfFirst), which we // may need to fix up. TypeUpdating::handleNonDefaultableLocals(func, *getModule()); + // 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/test/lit/passes/optimize-instructions-iit-eh.wast b/test/lit/passes/optimize-instructions-iit-eh.wast new file mode 100644 index 000000000..b297cb7df --- /dev/null +++ b/test/lit/passes/optimize-instructions-iit-eh.wast @@ -0,0 +1,58 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --ignore-implicit-traps --optimize-instructions -all -S -o - \ +;; RUN: | filecheck %s + +(module + ;; CHECK: (type $struct.A (struct (field i32))) + (type $struct.A (struct i32)) + ;; CHECK: (global $g-struct.A (rtt $struct.A) (rtt.canon $struct.A)) + + ;; CHECK: (tag $e (param (ref null $struct.A))) + (tag $e (param (ref null $struct.A))) + (global $g-struct.A (rtt $struct.A) (rtt.canon $struct.A)) + + ;; CHECK: (func $ref-cast-statically-removed + ;; CHECK-NEXT: (local $0 (ref null $struct.A)) + ;; CHECK-NEXT: (local $1 (ref null $struct.A)) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (pop (ref null $struct.A)) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (global.get $g-struct.A) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $ref-cast-statically-removed + (try + (do) + (catch $e + (throw $e + ;; Because --ignore-implicit-traps is given, this ref.cast is assumed + ;; not to throw so this ref.cast can be statically removed. But that + ;; creates a block around this, making 'pop' nested into it, which is + ;; invalid. We fix this up at the end up OptimizeInstruction, + ;; assigning the 'pop' to a local at the start of this 'catch' body + ;; and later using 'local.get' to get it. + (ref.cast + (pop (ref null $struct.A)) + (global.get $g-struct.A) + ) + ) + ) + ) + ) +) |