summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp4
-rw-r--r--test/lit/passes/optimize-instructions-iit-eh.wast58
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)
+ )
+ )
+ )
+ )
+ )
+)