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