| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. |
| ;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. |
| |
| ;; RUN: foreach %s %t wasm-opt --remove-unused-brs --all-features -S -o - | filecheck %s |
| |
| (module |
| ;; CHECK: (type $vector (array (mut i32))) |
| (type $vector (array (mut i32))) |
| ;; CHECK: (type $struct (struct (field (ref null $vector)))) |
| (type $struct (struct (field (ref null $vector)))) |
| ;; CHECK: (type $2 (func (param i32))) |
| |
| ;; CHECK: (type $3 (func (result (ref null $struct)))) |
| |
| ;; CHECK: (type $4 (func (result f64))) |
| |
| ;; CHECK: (type $5 (func (result i32))) |
| |
| ;; CHECK: (type $6 (func (param i32) (result funcref))) |
| |
| ;; CHECK: (type $7 (func (param funcref))) |
| |
| ;; CHECK: (type $8 (func)) |
| |
| ;; CHECK: (type $9 (func (param funcref) (result funcref))) |
| |
| ;; CHECK: (type $10 (func (result funcref))) |
| |
| ;; CHECK: (import "out" "log" (func $log (type $2) (param i32))) |
| (import "out" "log" (func $log (param i32))) |
| ;; CHECK: (elem declare func $br_on_non_null $br_on_null $i32_=>_none $none_=>_i32) |
| |
| ;; CHECK: (func $foo (type $3) (result (ref null $struct)) |
| ;; CHECK-NEXT: (if (result (ref null $struct)) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (struct.new $struct |
| ;; CHECK-NEXT: (array.new_default $vector |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (ref.null none) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $foo (result (ref null $struct)) |
| (if (result (ref null $struct)) |
| (i32.const 1) |
| (then |
| (struct.new $struct |
| ;; regression test for computing the cost of an array.new_default, which |
| ;; lacks the optional field "init" |
| (array.new_default $vector |
| (i32.const 1) |
| ) |
| ) |
| ) |
| (else |
| (ref.null $struct) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $test-prefinalize (type $4) (result f64) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (loop $loop (result f64) |
| ;; CHECK-NEXT: (if (result f64) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (f64.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (block $block (result f64) |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (i32.eqz |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $test-prefinalize (result f64) |
| (local $x i32) |
| (loop $loop (result f64) |
| (block $block (result f64) |
| (drop |
| (br_if $block |
| (f64.const 0) |
| (local.get $x) |
| ) |
| ) |
| (if |
| (i32.const 0) |
| (then |
| (unreachable) |
| ) |
| ) |
| ;; this will be moved from $block into the if right before it. we must be |
| ;; careful to properly finalize() things, as if we finalize the block too |
| ;; early - before the if - then the block ends in a none type, which is |
| ;; invalid. |
| (br $loop) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $none_=>_i32 (type $5) (result i32) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $none_=>_i32 (result i32) |
| (unreachable) |
| ) |
| ;; CHECK: (func $i32_=>_none (type $2) (param $0 i32) |
| ;; CHECK-NEXT: ) |
| (func $i32_=>_none (param i32) |
| ) |
| ;; CHECK: (func $selectify (type $6) (param $x i32) (result funcref) |
| ;; CHECK-NEXT: (select (result (ref func)) |
| ;; CHECK-NEXT: (ref.func $none_=>_i32) |
| ;; CHECK-NEXT: (ref.func $i32_=>_none) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $selectify (param $x i32) (result funcref) |
| ;; this if has arms with different function types, for which funcref is the |
| ;; LUB |
| (if (result funcref) |
| (local.get $x) |
| (then |
| (ref.func $none_=>_i32) |
| ) |
| (else |
| (ref.func $i32_=>_none) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $br_on_null (type $7) (param $x funcref) |
| ;; CHECK-NEXT: (block $null |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.null nofunc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br $null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.func $br_on_null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (br_on_null $null |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $br_on_null (param $x funcref) |
| (block $null |
| ;; A null reference to bottom is definitely null, and the br is always taken. |
| (drop |
| (br_on_null $null (ref.null nofunc)) |
| ) |
| ;; On the other hand, if we know the input is not null, the branch will never |
| ;; be taken. |
| (drop |
| (br_on_null $null (ref.func $br_on_null)) |
| ) |
| ;; If we don't know whether the input is null, we can't optimize. |
| (drop |
| (br_on_null $null (local.get $x)) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $br_on_null-fallthrough (type $8) |
| ;; CHECK-NEXT: (local $x funcref) |
| ;; CHECK-NEXT: (block $null |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $x |
| ;; CHECK-NEXT: (ref.null nofunc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br $null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.tee $x |
| ;; CHECK-NEXT: (ref.func $br_on_null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $br_on_null-fallthrough |
| ;; This is the same as above, but now the necessary type information comes |
| ;; from fallthrough values. |
| (local $x funcref) |
| (block $null |
| ;; Definitely taken. |
| (drop |
| (br_on_null $null (local.tee $x (ref.null nofunc))) |
| ) |
| ;; Definitely not taken. Optimizable, but still requires a cast for validity. |
| (drop |
| (br_on_null $null (local.tee $x (ref.func $br_on_null))) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $br_on_non_null (type $9) (param $x funcref) (result funcref) |
| ;; CHECK-NEXT: (block $non-null (result (ref func)) |
| ;; CHECK-NEXT: (br $non-null |
| ;; CHECK-NEXT: (ref.func $br_on_non_null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.null nofunc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_on_non_null $non-null |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $br_on_non_null (param $x funcref) (result funcref) |
| (block $non-null (result (ref func)) |
| ;; A non-null reference is not null, and the br is always taken. |
| (br_on_non_null $non-null |
| (ref.func $br_on_non_null) |
| ) |
| ;; On the other hand, if we know the input is null, the branch will never be |
| ;; taken. |
| (br_on_non_null $non-null |
| (ref.null nofunc) |
| ) |
| ;; If we don't know whether the input is null, we can't optimize. |
| (br_on_non_null $non-null |
| (local.get $x) |
| ) |
| (unreachable) |
| ) |
| ) |
| |
| ;; CHECK: (func $br_on_non_null-fallthrough (type $10) (result funcref) |
| ;; CHECK-NEXT: (local $x funcref) |
| ;; CHECK-NEXT: (block $non-null (result (ref func)) |
| ;; CHECK-NEXT: (br $non-null |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.tee $x |
| ;; CHECK-NEXT: (ref.func $br_on_non_null) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $x |
| ;; CHECK-NEXT: (ref.null nofunc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $br_on_non_null-fallthrough (result funcref) |
| ;; Same as above, but now using fallthrough values. |
| (local $x funcref) |
| (block $non-null (result (ref func)) |
| ;; Definitely taken. Requires cast. |
| (br_on_non_null $non-null |
| (local.tee $x (ref.func $br_on_non_null)) |
| ) |
| ;; Definitely not taken. |
| (br_on_non_null $non-null |
| (local.tee $x (ref.null nofunc)) |
| ) |
| (unreachable) |
| ) |
| ) |
| ) |