| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. |
| ;; RUN: wasm-opt %s --vacuum -all -S -o - | filecheck %s |
| |
| (module |
| ;; CHECK: (type $"{}" (struct)) |
| |
| ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects (type $2) (param i32 i32 funcref) (result anyref))) |
| (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects (param i32 i32 funcref) (result (ref null any)))) |
| ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects.non.null (type $3) (param i32 i32 funcref) (result (ref any)))) |
| (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects.non.null (param i32 i32 funcref) (result (ref any)))) |
| |
| (type $"{}" (struct)) |
| |
| ;; CHECK: (func $drop-ref-as (type $4) (param $x anyref) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.cast i31ref |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $drop-ref-as (param $x anyref) |
| ;; Without -tnh, we must assume all casts can have a trap effect, and so |
| ;; we cannot remove anything here. |
| (drop |
| (ref.as_non_null |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (ref.cast i31ref |
| (local.get $x) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $vacuum-nonnull (type $1) |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: ) |
| (func $vacuum-nonnull |
| (drop |
| (if (result (ref $"{}")) |
| (i32.const 1) |
| ;; This block's result is not used. As a consequence vacuum will try to |
| ;; generate a replacement zero for the block's fallthrough value. A |
| ;; non-nullable reference is a problem for that, since we don't want to |
| ;; synthesize and allocate a new struct value. Vacuum should not error |
| ;; on this case, though. Instead, the end result of this function should |
| ;; simply be empty, as everything here can be vacuumed away. |
| (then |
| (block (result (ref $"{}")) |
| (struct.new $"{}") |
| ) |
| ) |
| (else |
| (unreachable) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $drop-i31.get (type $5) (param $ref i31ref) (param $ref-nn (ref i31)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i31.get_s |
| ;; CHECK-NEXT: (local.get $ref) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $drop-i31.get (param $ref i31ref) (param $ref-nn (ref i31)) |
| ;; A nullable get might trap, so only the second item can be removed. |
| (drop |
| (i31.get_s |
| (local.get $ref) |
| ) |
| ) |
| (drop |
| (i31.get_s |
| (local.get $ref-nn) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $ref.cast.null.block (type $6) (param $ref (ref $"{}")) (result structref) |
| ;; CHECK-NEXT: (ref.cast (ref $"{}") |
| ;; CHECK-NEXT: (local.get $ref) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $ref.cast.null.block (param $ref (ref $"{}")) (result (ref null struct)) |
| ;; We can vacuum away the block, which will make this ref.cast null operate |
| ;; on a non-nullable input. That is, we are refining the input to the cast. |
| ;; The cast must be updated properly following that, to be a non-nullable |
| ;; cast. |
| (ref.cast (ref null $"{}") |
| (block (result (ref null $"{}")) |
| (local.get $ref) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $dropped-calls (type $1) |
| ;; CHECK-NEXT: (block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $helper-i32) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $helper-i32) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $helper-ref) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $helper-ref) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $helper-i32) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $helper-i32) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (call $call.without.effects.non.null |
| ;; CHECK-NEXT: (call $helper-i32) |
| ;; CHECK-NEXT: (call $helper-i32) |
| ;; CHECK-NEXT: (ref.func $helper-two-refs-non-null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $dropped-calls |
| ;; The calls' outputs are used in a computation that itself has no effects, |
| ;; and is dropped, so we don't need it. But we can't remove the calls |
| ;; themselves, which should be all that remains, with drops of them (there |
| ;; will also be blocks, which merge-blocks would remove). |
| (drop |
| (i32.add |
| (call $helper-i32) |
| (call $helper-i32) |
| ) |
| ) |
| (drop |
| (ref.eq |
| (call $helper-ref) |
| (call $helper-ref) |
| ) |
| ) |
| ;; The call.without.effects can be removed, but not the two calls nested in |
| ;; it. |
| (drop |
| (call $call.without.effects |
| (call $helper-i32) |
| (call $helper-i32) |
| (ref.func $helper-two-refs) |
| ) |
| ) |
| ;; The non-null case however is tricky, and we do not handle it atm. TODO |
| (drop |
| (call $call.without.effects.non.null |
| (call $helper-i32) |
| (call $helper-i32) |
| (ref.func $helper-two-refs-non-null) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $helper-i32 (type $7) (result i32) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| (func $helper-i32 (result i32) |
| (i32.const 1) |
| ) |
| |
| ;; CHECK: (func $helper-ref (type $8) (result eqref) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $helper-ref (result eqref) |
| (unreachable) |
| ) |
| |
| ;; CHECK: (func $helper-two-refs (type $9) (param $0 i32) (param $1 i32) (result anyref) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $helper-two-refs (param i32) (param i32) (result (ref null any)) |
| (unreachable) |
| ) |
| |
| ;; CHECK: (func $helper-two-refs-non-null (type $10) (param $0 i32) (param $1 i32) (result (ref any)) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $helper-two-refs-non-null (param i32) (param i32) (result (ref any)) |
| (unreachable) |
| ) |
| ) |