blob: 14c2170fb5e2d786dcb3b12676114450efc1827e [file]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --optimize-instructions -all -S -o - | filecheck %s
(module
;; CHECK: (type $shared-struct (shared (struct (field (mut i32)))))
;; CHECK: (type $shared-array (shared (array (mut i32))))
;; CHECK: (type $shared-array-func (shared (array (mut (ref null (shared func))))))
;; CHECK: (type $struct (struct (field (mut i32))))
(type $struct (struct (field (mut i32))))
(type $shared-struct (shared (struct (field (mut i32)))))
(type $shared-array (shared (array (mut i32))))
(type $shared-array-func (shared (array (mut (ref null (shared func))))))
;; CHECK: (data $data "hello")
(data $data "hello")
;; CHECK: (elem $elem (ref null (shared func)))
(elem $elem (ref null (shared func)))
;; CHECK: (func $publish-shared-struct-new (type $2) (result (ref $shared-struct))
;; CHECK-NEXT: (struct.new $shared-struct
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-struct-new (result (ref $shared-struct))
;; Publish of a shared struct allocation can be removed.
(publish
(struct.new $shared-struct
(i32.const 1)
)
)
)
;; CHECK: (func $publish-shared-struct-new-default (type $2) (result (ref $shared-struct))
;; CHECK-NEXT: (struct.new_default $shared-struct)
;; CHECK-NEXT: )
(func $publish-shared-struct-new-default (result (ref $shared-struct))
;; Publish of a shared struct.new_default can be removed.
(publish
(struct.new_default $shared-struct)
)
)
;; CHECK: (func $publish-shared-array-new (type $4) (result (ref $shared-array))
;; CHECK-NEXT: (array.new $shared-array
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-array-new (result (ref $shared-array))
;; Publish of a shared array allocation can be removed.
(publish
(array.new $shared-array
(i32.const 1)
(i32.const 10)
)
)
)
;; CHECK: (func $publish-shared-array-new-default (type $4) (result (ref $shared-array))
;; CHECK-NEXT: (array.new_default $shared-array
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-array-new-default (result (ref $shared-array))
;; Publish of a shared array.new_default can be removed.
(publish
(array.new_default $shared-array
(i32.const 10)
)
)
)
;; CHECK: (func $publish-shared-array-new-data (type $4) (result (ref $shared-array))
;; CHECK-NEXT: (array.new_data $shared-array $data
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-array-new-data (result (ref $shared-array))
;; Publish of a shared array.new_data can be removed.
(publish
(array.new_data $shared-array $data
(i32.const 0)
(i32.const 1)
)
)
)
;; CHECK: (func $publish-shared-array-new-elem (type $9) (result (ref $shared-array-func))
;; CHECK-NEXT: (array.new_elem $shared-array-func $elem
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-array-new-elem (result (ref $shared-array-func))
;; Publish of a shared array.new_elem can be removed.
(publish
(array.new_elem $shared-array-func $elem
(i32.const 0)
(i32.const 1)
)
)
)
;; CHECK: (func $publish-shared-array-new-fixed (type $4) (result (ref $shared-array))
;; CHECK-NEXT: (array.new_fixed $shared-array 2
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-array-new-fixed (result (ref $shared-array))
;; Publish of a shared array.new_fixed can be removed.
(publish
(array.new_fixed $shared-array 2
(i32.const 1)
(i32.const 2)
)
)
)
;; CHECK: (func $publish-shared-struct-new-in-block (type $2) (result (ref $shared-struct))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (struct.new $shared-struct
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-shared-struct-new-in-block (result (ref $shared-struct))
;; A block is a transparent fallthrough, so publish of the block containing
;; an allocation can be removed.
(publish
(block (result (ref $shared-struct))
(nop)
(struct.new $shared-struct
(i32.const 1)
)
)
)
)
;; CHECK: (func $publish-through-ref-as-alloc (type $2) (result (ref $shared-struct))
;; CHECK-NEXT: (struct.new $shared-struct
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-through-ref-as-alloc (result (ref $shared-struct))
;; RefAsNonNull is a transparent fallthrough, so publish of ref.as_non_null
;; of an allocation can be removed.
(publish
(ref.as_non_null
(struct.new $shared-struct
(i32.const 1)
)
)
)
)
;; CHECK: (func $publish-publish (type $3) (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-publish (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; Publish of publish can be removed.
(publish
(publish
(local.get $x)
)
)
)
;; CHECK: (func $publish-publish-block (type $3) (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-publish-block (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; The outer publish can look through the block to find the inner publish
;; and remove itself.
(publish
(block (result (ref $shared-struct))
(nop)
(publish
(local.get $x)
)
)
)
)
;; CHECK: (func $publish-publish-alloc (type $2) (result (ref $shared-struct))
;; CHECK-NEXT: (struct.new $shared-struct
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-publish-alloc (result (ref $shared-struct))
;; Both publishes are removed: the inner publish wraps an allocation, and
;; the outer publish wraps a publish/allocation.
(publish
(publish
(struct.new $shared-struct
(i32.const 1)
)
)
)
)
;; CHECK: (func $publish-unshared-struct (type $10) (param $x (ref $struct)) (result (ref $struct))
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $publish-unshared-struct (param $x (ref $struct)) (result (ref $struct))
;; Publish of an unshared struct reference is removed because publish only
;; affects shared objects.
(publish
(local.get $x)
)
)
;; CHECK: (func $publish-shared-i31 (type $11) (param $x (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $publish-shared-i31 (param $x (ref (shared i31))) (result (ref (shared i31)))
;; Publish of a shared i31 is removed because i31 is not an array or struct.
(publish
(local.get $x)
)
)
;; CHECK: (func $publish-shared-extern (type $12) (param $x (ref null (shared extern))) (result (ref null (shared extern)))
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $publish-shared-extern (param $x (ref null (shared extern))) (result (ref null (shared extern)))
;; Publish of a shared extern reference is removed.
(publish
(local.get $x)
)
)
;; CHECK: (func $publish-shared-func (type $13) (param $x (ref null (shared func))) (result (ref null (shared func)))
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $publish-shared-func (param $x (ref null (shared func))) (result (ref null (shared func)))
;; Publish of a shared func reference is removed.
(publish
(local.get $x)
)
)
;; CHECK: (func $publish-shared-none (type $14) (param $x (ref null (shared none))) (result (ref null (shared none)))
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $publish-shared-none (param $x (ref null (shared none))) (result (ref null (shared none)))
;; Publish of a shared none reference is removed.
(publish
(local.get $x)
)
)
;; CHECK: (func $publish-shared-null-fallthrough (type $7) (result (ref null $shared-struct))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
(func $publish-shared-null-fallthrough (result (ref null $shared-struct))
;; The operand of publish has type (ref null $shared-struct), but its
;; fallthrough is a shared null (type (ref null (shared none))). Because
;; null cannot be a struct or array, the publish can be removed.
(publish
(block (result (ref null $shared-struct))
(nop)
(ref.null (shared none))
)
)
)
;; CHECK: (func $keep-shared-any (type $15) (param $x (ref (shared any))) (result (ref (shared any)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-any (param $x (ref (shared any))) (result (ref (shared any)))
;; Publish of a shared any reference cannot be removed because it may refer
;; to a shared struct or array.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-null-any (type $16) (param $x (ref null (shared any))) (result (ref null (shared any)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-null-any (param $x (ref null (shared any))) (result (ref null (shared any)))
;; Publish of a nullable shared any reference cannot be removed because it
;; may refer to a shared struct or array.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-eq (type $17) (param $x (ref (shared eq))) (result (ref (shared eq)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-eq (param $x (ref (shared eq))) (result (ref (shared eq)))
;; Publish of a shared eq reference cannot be removed because it may refer
;; to a shared struct or array.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-struct (type $18) (param $x (ref (shared struct))) (result (ref (shared struct)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-struct (param $x (ref (shared struct))) (result (ref (shared struct)))
;; Publish of a shared abstract struct cannot be removed without knowing its
;; allocation history.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-array (type $19) (param $x (ref (shared array))) (result (ref (shared array)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-array (param $x (ref (shared array))) (result (ref (shared array)))
;; Publish of a shared abstract array cannot be removed without knowing its
;; allocation history.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-specific-struct (type $3) (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-specific-struct (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; Publish of an unknown shared struct cannot be removed.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-null-specific-struct (type $20) (param $x (ref null $shared-struct)) (result (ref null $shared-struct))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-null-specific-struct (param $x (ref null $shared-struct)) (result (ref null $shared-struct))
;; Publish of a nullable unknown shared struct cannot be removed.
(publish
(local.get $x)
)
)
;; CHECK: (func $keep-shared-specific-array (type $21) (param $x (ref $shared-array)) (result (ref $shared-array))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $keep-shared-specific-array (param $x (ref $shared-array)) (result (ref $shared-array))
;; Publish of an unknown shared array cannot be removed.
(publish
(local.get $x)
)
)
;; CHECK: (func $ref-cast-through-publish (type $3) (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-through-publish (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; ref.cast looks through publish to find the fallthrough type and optimizes
;; away the redundant cast.
(ref.cast (ref $shared-struct)
(publish
(local.get $x)
)
)
)
;; CHECK: (func $ref-as-through-publish (type $3) (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-as-through-publish (param $x (ref $shared-struct)) (result (ref $shared-struct))
;; ref.as_non_null looks through publish to see the operand is already
;; non-null and optimizes away the check.
(ref.as_non_null
(publish
(local.get $x)
)
)
)
;; CHECK: (func $struct-get-through-publish-null (type $22) (result i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $struct-get-through-publish-null (result i32)
;; The publish is first removed because its operand is a null reference
;; (which cannot be a struct or array), after which struct.get traps on the
;; null reference.
(struct.get $shared-struct 0
(publish
(ref.null $shared-struct)
)
)
)
;; CHECK: (func $publish-unreachable (type $8) (result (ref (shared any)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-unreachable (result (ref (shared any)))
;; Publish of an unreachable instruction is not modified.
(publish
(unreachable)
)
)
;; CHECK: (func $publish-unreachable-block (type $8) (result (ref (shared any)))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $publish-unreachable-block (result (ref (shared any)))
;; Publish of a block containing an unreachable instruction is eliminated
;; because the fallthrough has a non-shared type.
(publish
(block (result (ref (shared any)))
(nop)
(unreachable)
)
)
)
;; CHECK: (func $publish-tee (type $7) (result (ref null $shared-struct))
;; CHECK-NEXT: (local $x (ref null $shared-struct))
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (struct.new $shared-struct
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-tee (result (ref null $shared-struct))
;; An intervening local.tee does not prevent the publish from being removed.
;; If the teed local was used to write to the object before publishing it,
;; we would not remove the publish (see next test).
(local $x (ref null $shared-struct))
(publish
(local.tee $x
(struct.new $shared-struct
(i32.const 1)
)
)
)
)
;; CHECK: (func $publish-write-fallthrough (type $23) (result (ref null (shared any)))
;; CHECK-NEXT: (local $s (ref null $shared-struct))
;; CHECK-NEXT: (block $l (result (ref null (shared any)))
;; CHECK-NEXT: (publish
;; CHECK-NEXT: (br_if $l
;; CHECK-NEXT: (local.tee $s
;; CHECK-NEXT: (struct.new_default $shared-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (struct.set $shared-struct 0
;; CHECK-NEXT: (local.get $s)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $publish-write-fallthrough (result (ref null (shared any)))
(local $s (ref null $shared-struct))
(block $l (result (ref null (shared any)))
;; Now the tee is used to write to the published object. We do not
;; optimize.
(publish
(br_if $l
(local.tee $s
(struct.new_default $shared-struct)
)
(block (result i32)
(struct.set $shared-struct 0
(local.get $s)
(i32.const 10)
)
(i32.const 0)
)
)
)
)
)
)