blob: dd4934e0a766a8fb17189766e8308d0777793070 [file] [edit]
;; 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)
)
)