summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/dae_all-features.wast255
-rw-r--r--test/lit/passes/dae_tnh.wast52
-rw-r--r--test/lit/passes/signature-pruning.wast301
3 files changed, 545 insertions, 63 deletions
diff --git a/test/lit/passes/dae_all-features.wast b/test/lit/passes/dae_all-features.wast
index d4390351f..17ea77942 100644
--- a/test/lit/passes/dae_all-features.wast
+++ b/test/lit/passes/dae_all-features.wast
@@ -109,25 +109,31 @@
(func $b33
(call $a3 (i32.const 4))
)
- ;; CHECK: (func $a4 (type $1) (param $x i32)
+ ;; CHECK: (func $a4 (type $0)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
- (func $a4 (param $x i32) ;; diff value, but with effects
+ (func $a4 (param $x i32)
+ ;; This function is called with one constant and one unreachable. We can
+ ;; remove the param despite the unreachable's effects.
)
;; CHECK: (func $b4 (type $0)
- ;; CHECK-NEXT: (call $a4
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $b4
+ ;; This call will vanish entirely, because the unreachable child executes
+ ;; first (so we cannot see here that we removed the parameter from $a4, but
+ ;; that can be confirmed in $a4 itself).
(call $a4 (unreachable))
)
;; CHECK: (func $b43 (type $0)
- ;; CHECK-NEXT: (call $a4
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $a4)
;; CHECK-NEXT: )
(func $b43
+ ;; We will remove the parameter here.
(call $a4 (i32.const 4))
)
;; CHECK: (func $a5 (type $0)
@@ -659,27 +665,33 @@
)
(module
- ;; CHECK: (type $0 (func (param i32)))
+ ;; CHECK: (type $0 (func))
- ;; CHECK: (func $0 (type $0) (param $0 i32)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (call $0
+ ;; CHECK: (func $0 (type $0)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
(func $0 (param $0 i32) (result i32)
- ;; The result of this function can be removed, which makes us modify the
- ;; returns (we should not return a value any more) and also the calls (the
- ;; calls must be dropped). The returns here are nested in each other, and one
- ;; is a recursive call to this function itself, which makes this a corner case
- ;; we might emit invalid code for.
+ ;; The returns here are nested in each other, and one is a recursive call to
+ ;; this function itself, which makes this a corner case we might emit invalid
+ ;; code for. We end up removing the parameter, and then the call vanishes as
+ ;; it was unreachable; we also remove the return as well as it is dropped in
+ ;; the other caller, below.
(return
(drop
(call $0
@@ -690,6 +702,17 @@
)
)
)
+
+ ;; CHECK: (func $other-call (type $0)
+ ;; CHECK-NEXT: (call $0)
+ ;; CHECK-NEXT: )
+ (func $other-call
+ (drop
+ (call $0
+ (i32.const 1)
+ )
+ )
+ )
)
(module
@@ -727,3 +750,193 @@
)
)
)
+
+(module
+ ;; CHECK: (type $0 (func (param f64) (result i32)))
+
+ ;; CHECK: (func $target (type $0) (param $0 f64) (result i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (local $4 i32)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (call $target
+ ;; CHECK-NEXT: (f64.const 1.1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (call $target
+ ;; CHECK-NEXT: (f64.const 4.4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $target
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $target (param $a i32) (param $b f64) (param $c i32) (result i32)
+ ;; Test removing a parameter despite calls having interesting non-unreachable
+ ;; effects. This also tests recursion of such calls. We can remove all the i32
+ ;; parameters here.
+ (call $target
+ (call $target
+ (i32.const 0)
+ (f64.const 1.1)
+ (i32.const 2)
+ )
+ (local.get $b)
+ (call $target
+ (i32.const 3)
+ (f64.const 4.4)
+ (i32.const 5)
+ )
+ )
+ )
+)
+
+(module
+ ;; CHECK: (type $0 (func))
+
+ ;; CHECK: (type $v128 (func (result v128)))
+ (type $v128 (func (result v128)))
+
+ ;; CHECK: (type $2 (func (result f32)))
+
+ ;; CHECK: (table $0 10 funcref)
+ (table $0 10 funcref)
+
+ ;; CHECK: (func $caller-effects (type $0)
+ ;; CHECK-NEXT: (local $0 v128)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result f32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (call_indirect $0 (type $v128)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $target)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $caller-effects
+ (drop
+ (call $target
+ (i64.const 0)
+ ;; We'd like to remove this unused parameter, but it has effects, so we'll
+ ;; move it to a local first.
+ (call_indirect $0 (type $v128)
+ (i32.const 0)
+ )
+ (i64.const 0)
+ )
+ )
+ )
+
+ ;; CHECK: (func $target (type $2) (result f32)
+ ;; CHECK-NEXT: (local $0 i64)
+ ;; CHECK-NEXT: (local $1 i64)
+ ;; CHECK-NEXT: (local $2 v128)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i64.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i64.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $target (param $0 i64) (param $1 v128) (param $2 i64) (result f32)
+ ;; All parameters here should vanish.
+ (unreachable)
+ )
+)
+
+(module
+ ;; CHECK: (type $0 (func (param i32 i64)))
+
+ ;; CHECK: (type $1 (func (param i64 i64)))
+
+ ;; CHECK: (func $caller-later-br (type $0) (param $x i32) (param $y i64)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (block $block
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (then
+ ;; CHECK-NEXT: (return)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (br $block)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $target
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $caller-later-br (param $x i32) (param $y i64)
+ (block $block
+ (drop
+ (call $target
+ (i64.const 0)
+ ;; We'd like to remove this unused parameter, and we can do so by moving
+ ;; it to a local, but we need to be careful: the br right after us must be
+ ;; kept around, as it is the only thing that makes the outer block have
+ ;; type none and not unreachable.
+ (block (result i32)
+ (if
+ (local.get $x)
+ (then
+ (return)
+ )
+ )
+ (i32.const 42)
+ )
+ ;; We'll move this around, but won't remove it, as explained above.
+ (br $block)
+ )
+ )
+ )
+ ;; Another call, to show the effect of removing the i32 parameter (also, if
+ ;; no calls remain after removing the unreachable one before us, then the pass
+ ;; would stop before removing parameters in $target - we don't remove params
+ ;; from functions that look dead).
+ (drop
+ (call $target
+ (local.get $y)
+ (local.get $x)
+ (local.get $y)
+ )
+ )
+ )
+
+ ;; CHECK: (func $target (type $1) (param $0 i64) (param $1 i64)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result f32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $target (param $0 i64) (param $1 i32) (param $2 i64) (result f32)
+ ;; The i32 parameter should vanish.
+ (drop
+ (local.get $0)
+ )
+ (drop
+ (local.get $2)
+ )
+ (unreachable)
+ )
+)
diff --git a/test/lit/passes/dae_tnh.wast b/test/lit/passes/dae_tnh.wast
index 33e6eb09b..6d75aed30 100644
--- a/test/lit/passes/dae_tnh.wast
+++ b/test/lit/passes/dae_tnh.wast
@@ -39,14 +39,18 @@
;; CHECK: (type $1 (func (param i32)))
;; CHECK: (func $caller (type $0)
- ;; CHECK-NEXT: (call $target
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $caller
- ;; Removing this parameter would require the type of the call to change from
- ;; unreachable to none. We don't handle such complexity and ignore such
- ;; cases.
+ ;; Removing this parameter would make the type of the call change from
+ ;; unreachable to none. But the call itself is in unreachable code, so we
+ ;; will replace it with an unreachable (and then, once the call is gone, the
+ ;; target can be better optimized; however, no other calls remain here, so
+ ;; the pass does nothing as it considers it dead at that point).
+ ;;
+ ;; This test verifies we do the proper thing even in TNH mode, as in TNH
+ ;; mode |unreachable| seems to have no effects, but for validation reasons
+ ;; we must still replace the call here.
(call $target
(unreachable)
)
@@ -59,13 +63,40 @@
)
)
-;; As above, but use a return_call. We can optimize that, since return_calls
-;; have type unreachable anyhow, and the optimization would not change the type.
+;; As above but the called target has a result.
+(module
+ ;; CHECK: (type $0 (func (result i32)))
+
+ ;; CHECK: (type $1 (func (param i32) (result i32)))
+
+ ;; CHECK: (func $caller (type $0) (result i32)
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ (func $caller (result i32)
+ ;; Again, the call is replaced by an unreachable.
+ (call $target
+ (unreachable)
+ )
+ )
+
+ ;; CHECK: (func $target (type $1) (param $0 i32) (result i32)
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: )
+ (func $target (param i32) (result i32)
+ (i32.const 42)
+ )
+)
+
+;; As above, but use a return_call. We can optimize that too (return_calls have
+;; type unreachable anyhow, and the optimization would not change the type, so
+;; it is even simpler).
(module
;; CHECK: (type $0 (func))
+ ;; CHECK: (type $1 (func (param i32)))
+
;; CHECK: (func $caller (type $0)
- ;; CHECK-NEXT: (return_call $target)
+ ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $caller
(return_call $target
@@ -73,8 +104,7 @@
)
)
- ;; CHECK: (func $target (type $0)
- ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK: (func $target (type $1) (param $0 i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $target (param i32)
diff --git a/test/lit/passes/signature-pruning.wast b/test/lit/passes/signature-pruning.wast
index 4d22ef619..cad9af82b 100644
--- a/test/lit/passes/signature-pruning.wast
+++ b/test/lit/passes/signature-pruning.wast
@@ -136,7 +136,7 @@
;; CHECK: (rec
;; CHECK-NEXT: (type $0 (func))
- ;; CHECK: (type $sig (sub (func (param i32 i64 f32))))
+ ;; CHECK: (type $sig (sub (func (param i64 f32))))
(type $sig (sub (func (param i32) (param i64) (param f32) (param f64))))
(memory 1 1)
@@ -145,19 +145,20 @@
;; CHECK: (elem declare func $foo)
- ;; CHECK: (func $foo (type $sig) (param $0 i32) (param $1 i64) (param $2 f32)
- ;; CHECK-NEXT: (local $3 f64)
+ ;; CHECK: (func $foo (type $sig) (param $0 i64) (param $1 f32)
+ ;; CHECK-NEXT: (local $2 f64)
+ ;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (i64.store
;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (f32.store
;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $foo (type $sig) (param $i32 i32) (param $i64 i64) (param $f32 f32) (param $f64 f64)
- ;; Use the middle two parameters.
+ ;; Use the middle two parameters. The other two vanish.
(i64.store
(i32.const 0)
(local.get $i64)
@@ -169,25 +170,29 @@
)
;; CHECK: (func $caller (type $0)
- ;; CHECK-NEXT: (call $foo
- ;; CHECK-NEXT: (block (result i32)
- ;; CHECK-NEXT: (call $caller)
- ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (call $caller)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $foo
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: (f32.const 2)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i64.const 1)
- ;; CHECK-NEXT: (f32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call_ref $sig
- ;; CHECK-NEXT: (i32.const 4)
;; CHECK-NEXT: (i64.const 5)
;; CHECK-NEXT: (f32.const 6)
;; CHECK-NEXT: (ref.func $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
- ;; As above, but now one of the unused parameters has a side effect which
- ;; prevents us from removing it (flattening the IR first would avoid this
- ;; limitation). We only end up removing a single unused param, the last.
+ ;; As above, but now one of the unused parameters has a side effect. We
+ ;; move it to a local, which allows us to remove it (and also the last,
+ ;; which is trivial).
(call $foo
(block (result i32)
(call $caller)
@@ -207,13 +212,13 @@
)
)
-;; As above, but with the effects on a call_ref. Once more, we can only optimize
-;; away the very last param.
+;; As above, but with the effects on a call_ref. Once more, we can optimize
+;; even with effects on a param, using locals.
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $0 (func))
- ;; CHECK: (type $sig (sub (func (param i32 i64 f32))))
+ ;; CHECK: (type $sig (sub (func (param i64 f32))))
(type $sig (sub (func (param i32) (param i64) (param f32) (param f64))))
(memory 1 1)
@@ -222,15 +227,16 @@
;; CHECK: (elem declare func $foo)
- ;; CHECK: (func $foo (type $sig) (param $0 i32) (param $1 i64) (param $2 f32)
- ;; CHECK-NEXT: (local $3 f64)
+ ;; CHECK: (func $foo (type $sig) (param $0 i64) (param $1 f32)
+ ;; CHECK-NEXT: (local $2 f64)
+ ;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (i64.store
;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (f32.store
;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $foo (type $sig) (param $i32 i32) (param $i64 i64) (param $f32 f32) (param $f64 f64)
@@ -245,19 +251,23 @@
)
;; CHECK: (func $caller (type $0)
+ ;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (call $foo
- ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 1)
;; CHECK-NEXT: (f32.const 2)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call_ref $sig
- ;; CHECK-NEXT: (block (result i32)
- ;; CHECK-NEXT: (call $caller)
- ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (call $caller)
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call_ref $sig
+ ;; CHECK-NEXT: (i64.const 5)
+ ;; CHECK-NEXT: (f32.const 6)
+ ;; CHECK-NEXT: (ref.func $foo)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i64.const 5)
- ;; CHECK-NEXT: (f32.const 6)
- ;; CHECK-NEXT: (ref.func $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
@@ -912,3 +922,232 @@
(unreachable)
)
)
+
+;; Test corner cases with var updating. To remove the parameter of $func we
+;; must move the parameter to a local first. We must then adjust local types
+;; properly while adjusting the signature (when the signature loses a parameter,
+;; local indexes change, which is a delicate dance handled by
+;; GlobalTypeRewriter::updateSignatures and ParamUtils::removeParameters;
+;; moving the parameter to a local first should not get in the way there).
+(module
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (sub (struct (field v128))))
+ (type $struct (sub (struct (field v128))))
+ ;; CHECK: (type $1 (func))
+
+ ;; CHECK: (type $func (func))
+ (type $func (func (param v128)))
+
+ ;; CHECK: (elem declare func $func)
+
+ ;; CHECK: (func $func (type $func)
+ ;; CHECK-NEXT: (local $0 v128)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func (type $func) (param $0 v128)
+ ;; The parameter will be removed.
+ (nop)
+ )
+
+ ;; CHECK: (func $caller (type $1)
+ ;; CHECK-NEXT: (local $0 (ref $struct))
+ ;; CHECK-NEXT: (local $1 externref)
+ ;; CHECK-NEXT: (local $2 v128)
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (struct.get $struct 0
+ ;; CHECK-NEXT: (local.tee $0
+ ;; CHECK-NEXT: (struct.new_default $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call_ref $func
+ ;; CHECK-NEXT: (ref.func $func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $caller (param $param externref)
+ (local $var (ref $struct))
+ ;; The parameter of this call_ref will be removed.
+ (call_ref $func
+ ;; Use a struct.get, which would error if the type the nested tee were
+ ;; incorrect (it asserts on it being a struct type).
+ (struct.get $struct 0
+ ;; Use a tee to test the updating of tee'd vars, as mentioned above.
+ (local.tee $var
+ (struct.new_default $struct)
+ )
+ )
+ (ref.func $func)
+ )
+ )
+)
+
+(module
+ ;; CHECK: (type $0 (func (param i32)))
+
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $1 (func (param i32)))
+
+ ;; CHECK: (type $2 (func (result i32)))
+
+ ;; CHECK: (type $3 (func (param i32)))
+
+ ;; CHECK: (tag $tag (param i32))
+ (tag $tag (param i32))
+
+ ;; CHECK: (func $catch-pop (type $2) (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: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $catch-pop (result i32)
+ (block $block (result i32)
+ (try $try
+ (do
+ (nop)
+ )
+ (catch $tag
+ (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.
+ (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.
+ (nop)
+ )
+ )
+ (i32.const 3)
+ )
+ )
+
+ ;; CHECK: (func $target (type $1) (param $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $target (param $x i32) (param $y i32)
+ ;; Use only the first param. The second will be removed.
+ (drop
+ (local.get $x)
+ )
+ )
+)
+
+;; As above, but remove the other parameter (the pop).
+(module
+ ;; CHECK: (type $0 (func (param i32)))
+
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $1 (func (param i32)))
+
+ ;; CHECK: (type $2 (func (result i32)))
+
+ ;; CHECK: (type $3 (func (param i32)))
+
+ ;; CHECK: (tag $tag (param i32))
+ (tag $tag (param i32))
+
+ ;; CHECK: (func $catch-pop (type $2) (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: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $catch-pop (result i32)
+ (block $block (result i32)
+ (try $try
+ (do
+ (nop)
+ )
+ (catch $tag
+ (call $target
+ (pop i32)
+ (br_if $block
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (nop)
+ )
+ )
+ (i32.const 3)
+ )
+ )
+
+ ;; CHECK: (func $target (type $1) (param $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $target (param $x i32) (param $y i32)
+ (drop
+ (local.get $y) ;; this changed from $x to $y
+ )
+ )
+)