blob: e3f9cd436f0712d092c059a8020433cddbabc380 [file]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: foreach %s %t wasm-opt -all --dae2 --closed-world -S -o - | filecheck %s
(module
;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (result i32)
;; Unused result should be removed.
(i32.const 42)
)
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (call $test)
;; CHECK-NEXT: )
(func $caller
(drop (call $test))
)
)
(module
;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (result i32)
;; Same, but this time there is no caller at all.
(i32.const 42)
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $test (type $0) (result i32 i64)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i64.const 100)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (result i32 i64)
;; One of the results is unused. Since we don't support partial result
;; removal, we keep both.
(tuple.make 2 (i32.const 42) (i64.const 100))
)
;; CHECK: (func $caller (type $2)
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (call $test)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
(global.set $g (tuple.extract 2 0 (call $test)))
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i64.const 100)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (result i32 i64)
;; Fully unused tuple results can still be removed.
(tuple.make 2 (i32.const 42) (i64.const 100))
)
)
(module
;; CHECK: (func $callee (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $callee (param i32) (result i32)
(local.get 0)
)
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $callee)
;; CHECK-NEXT: )
(func $caller
;; $callee's result is unused, so its parameter is also unused.
(drop (call $callee (i32.const 42)))
)
)
(module
;; CHECK: (func $callee (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $callee (param i32) (result i32)
(local.get 0)
)
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (call $callee)
;; CHECK-NEXT: )
(func $caller (param i32)
;; Same, but now the $caller further has a param that is unused.
(drop (call $callee (local.get 0)))
)
)
(module
;; CHECK: (func $callee (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $callee (param i32) (result i32)
(block (result i32)
(block (result i32)
(local.get 0)
)
)
)
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (call $callee)
;; CHECK-NEXT: )
(func $caller (param i32)
;; Same, but now with intermediate expressions.
(drop
(block (result i32)
(call $callee
(block (result i32)
(local.get 0)
)
)
)
)
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $callee (type $0) (param $0 i32) (result i32)
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $callee (param i32) (result i32)
(local.get 0)
)
;; CHECK: (func $caller (type $2) (param $0 i32)
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (call $callee
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller (param i32)
;; $callee's result is used, so $callee's param and $caller's param are also
;; used.
(global.set $g (call $callee (local.get 0)))
)
)
(module
;; CHECK: (func $other (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $other (result i32)
(i32.const 42)
)
;; CHECK: (func $callee (type $0)
;; CHECK-NEXT: (call $other)
;; CHECK-NEXT: )
(func $callee (result i32)
(call $other)
)
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (call $callee)
;; CHECK-NEXT: )
(func $caller
;; $callee's result is unused, so $other's result should also be unused.
(drop (call $callee))
)
)
(module
;; CHECK: (func $other (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $other (result i32)
(block (result i32)
(i32.const 42)
)
)
;; CHECK: (func $callee (type $0)
;; CHECK-NEXT: (call $other)
;; CHECK-NEXT: )
(func $callee (result i32)
(block (result i32)
(call $other)
)
)
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (call $callee)
;; CHECK-NEXT: )
(func $caller
;; Same, but now with intermediate expressions.
(drop
(block (result i32)
(call $callee)
)
)
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $target (type $0) (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(func $target (result i32) (i32.const 42))
;; CHECK: (func $caller (type $2)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (call $target)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller (local $x i32)
;; The result is used indirectly via a local. It cannot be removed.
(local.set $x (call $target))
(global.set $g (local.get $x))
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $target (type $0) (result i32)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
(func $target (result i32) (i32.const 1))
;; CHECK: (func $caller (type $2)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (call $target)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (i32.const 100)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
;; The result is used in control flow. It cannot be removed.
(if (call $target)
(then (global.set $g (i32.const 100)))
)
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $target (type $0) (result i32)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
(func $target (result i32) (i32.const 1))
;; CHECK: (func $caller (type $2)
;; CHECK-NEXT: (block $l
;; CHECK-NEXT: (br_if $l
;; CHECK-NEXT: (call $target)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (i32.const 100)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
(block $l
;; Same, but now the control flow is a br_if instead of an if.
(br_if $l
(call $target)
)
(global.set $g (i32.const 100))
)
)
)
(module
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (func $target (type $0) (result i32)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
(func $target (result i32) (i32.const 1))
;; CHECK: (func $caller (type $2)
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (call $target)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
;; The result is combined with other values and then used.
(global.set $g (i32.add (call $target) (i32.const 2)))
)
)
(module
;; CHECK: (func $target (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $target (result i32) (i32.const 1))
;; CHECK: (func $caller (type $0)
;; CHECK-NEXT: (call $target)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $caller
;; The result is combined with other values, but not used.
(drop (i32.add (call $target) (i32.const 2)))
)
;; CHECK: (func $main (type $0)
;; CHECK-NEXT: (call $caller)
;; CHECK-NEXT: )
(func $main
(call $caller)
)
)