| ;; 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) |
| ) |
| ) |