| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. |
| |
| ;; RUN: wasm-opt %s --constraint-analysis -all -S -o - | filecheck %s |
| |
| ;; Also run after optimize-instructions, which canonicalizes the order of |
| ;; things like binary children. We want to see that this pass optimizes the |
| ;; IR that optimize-instructions emits. |
| |
| ;; RUN: wasm-opt %s --optimize-instructions --constraint-analysis -all -S -o - | filecheck %s --check-prefix=OPTIN |
| |
| (module |
| ;; CHECK: (type $array (array (mut i32))) |
| ;; OPTIN: (type $array (array (mut i32))) |
| (type $array (array (mut i32))) |
| |
| ;; CHECK: (func $simple (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $simple (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $simple |
| (local $x i32) |
| ;; Set x to 10, and then compare it to 10 and 20 using == and !=, all in a |
| ;; single basic block. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $unknown (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.add |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 30) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.div_s |
| ;; CHECK-NEXT: (i32.const 1337) |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 31) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $unknown (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 30) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.div_u |
| ;; OPTIN-NEXT: (i32.const 1337) |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 31) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $unknown |
| (local $x i32) |
| ;; Set x to an add. We can only optimize this if optimize-instructions first |
| ;; simplifies it to a constant. |
| (local.set $x |
| (i32.add |
| (i32.const 10) |
| (i32.const 20) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 30) |
| ) |
| ) |
| ;; When optimize-instructions does not help, we infer nothing. |
| (local.set $x |
| (i32.div_s |
| (i32.const 1337) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 31) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-local (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local $y i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 15) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-local (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local $y i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 15) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-local |
| (local $x i32) |
| (local $y i32) |
| ;; x is 10, y is 20 |
| (local.set $x |
| (i32.const 10) |
| ) |
| (local.set $y |
| (i32.const 20) |
| ) |
| ;; Verify those values. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 20) |
| ) |
| ) |
| ;; Overwrite x to 15. |
| (local.set $x |
| (i32.const 15) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 15) |
| ) |
| ) |
| ;; y is unchanged. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-block (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-block (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (if (result i32) |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (else |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-block (param $param i32) |
| (local $x i32) |
| (local.set $x |
| (i32.const 10) |
| ) |
| ;; We can infer into these basic blocks. |
| (if |
| (local.get $param) |
| (then |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.ne ;; also test a not-equals here; result is 0 |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ;; We can infer after the merge. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-block-split (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-block-split (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (if (result i32) |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (else |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-block-split (param $param i32) |
| (local $x i32) |
| (if |
| (local.get $param) |
| (then |
| (local.set $x |
| (i32.const 10) |
| ) |
| ) |
| (else |
| (local.set $x |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ;; x is either 10 or 20, but not known to be one or the other. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ;; TODO: test we can infer x >= 10 etc. |
| ) |
| |
| ;; CHECK: (func $multi-block-split-2 (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-block-split-2 (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-block-split-2 (param $param i32) |
| (local $x i32) |
| ;; As above, but one if arm, and a set before the if. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (if |
| (local.get $param) |
| (then |
| (local.set $x |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ;; Again, we cannot infer. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-block-split-yes (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-block-split-yes (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-block-split-yes (param $param i32) |
| (local $x i32) |
| ;; As above, but now we set 10 again in the if arm. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (if |
| (local.get $param) |
| (then |
| (local.set $x |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ;; Now we can infer 1 and 0 here. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $loop (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (loop $loop |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $loop (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (loop $loop |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $loop |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $loop (param $param i32) |
| (local $x i32) |
| ;; Set $x to 10 before the loop. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (loop $loop |
| ;; Despite the backedges, we can infer x is 10 and not 20. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| (br_if $loop |
| (local.get $param) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $loop-no (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (loop $loop |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.ne |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $loop-no (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (loop $loop |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $loop |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $loop-no (param $param i32) |
| (local $x i32) |
| ;; As above, but now with another value set in the loop. We cannot infer. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (loop $loop |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| (local.set $x |
| (i32.const 20) |
| ) |
| (br_if $loop |
| (local.get $param) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $default-var (type $0) (param $param i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local $eq eqref) |
| ;; CHECK-NEXT: (local $nn-eq (ref eq)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $default-var (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local $eq eqref) |
| ;; OPTIN-NEXT: (local $nn-eq (ref eq)) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eqz |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $default-var (param $param i32) |
| (local $x i32) |
| (local $eq eqref) |
| ;; A non-nullable local. We cannot add a get for it (it would not validate), |
| ;; but check we do not error. |
| (local $nn-eq (ref eq)) |
| ;; locals begin with default values, so we can infer here. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 0) |
| ) |
| ) |
| (drop |
| (i32.eqz |
| (local.get $x) |
| ) |
| ) |
| ;; We can infer nothing for a param. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 0) |
| ) |
| ) |
| ;; We can infer a null reference. |
| (drop |
| (ref.eq |
| (local.get $eq) |
| (ref.null eq) |
| ) |
| ) |
| (drop |
| (ref.is_null |
| (local.get $eq) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional (type $0) (param $param i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eqz |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (block |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eqz |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eqz |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional (param $param i32) |
| ;; We can infer $param is non-zero in the if's first arm, but not the second |
| ;; nor after the if. |
| ;; (Note: we fail to optimize this in OPTIN, because it folds the if arms |
| ;; first.) |
| (if |
| (local.get $param) |
| (then |
| ;; The first is false, the second true. |
| (drop |
| (i32.eqz |
| (local.get $param) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $param) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| (else |
| ;; Flipped. |
| (drop |
| (i32.eqz |
| (local.get $param) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $param) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| ) |
| (drop |
| (i32.eqz |
| (local.get $param) |
| ) |
| ) |
| (drop |
| (local.get $param) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary (type $0) (param $param i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.ne |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (block |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary (param $param i32) |
| ;; As above, but comparing param to 10. |
| (if |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary-nesting (type $2) (param $x i32) (param $y i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary-nesting (type $2) (param $x i32) (param $y i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (i32.const 20) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary-nesting (param $x i32) (param $y i32) |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (if |
| (i32.eq |
| (local.get $y) |
| (i32.const 20) |
| ) |
| (then |
| ;; x is 10 here, and y is 20. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary-contradiction (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary-contradiction (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary-contradiction (param $x i32) |
| ;; As above, but with only $x. |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| (then |
| ;; This is only reached if x is both 10 and 20, which is a |
| ;; contradiction, so it is unreachable. We optimize to unreachable |
| ;; here. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ;; After that contradiction, control flow merges, and we can infer 1 and |
| ;; 0 here (since we are still inside the x == 10 If's body). |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary-contradiction-2 (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary-contradiction-2 (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary-contradiction-2 (param $x i32) |
| ;; As above, but now the contradiction is in the inner if-else. |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| ;; x is 10 here. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| ;; We cannot get here: it would require x == 10 and x != 10. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ;; After that contradiction, control flow merges, and we can infer 1 and |
| ;; 0 here (since we are still inside the x == 10 If's body). |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary-contradiction-other (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary-contradiction-other (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 30) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary-contradiction-other (param $x i32) |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| (then |
| ;; This is only reached if x is both 10 and 20, which is a |
| ;; contradiction, so it is unreachable. We optimize to unreachable |
| ;; here, even though this is a Binary that we do not have anything |
| ;; to do with otherwise (no constraint on a local is implied by this |
| ;; expression). This checks that we optimize unreachability even on |
| ;; expressions without relevant locals. |
| (drop |
| (i32.add |
| (i32.const 10) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary-contradiction-other-default (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary-contradiction-other-default (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 30) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary-contradiction-other-default |
| (local $x i32) |
| ;; As above, but now with a single if. The contradiction tested is |
| ;; between the default value and the if condition. |
| (if |
| (local.get $x) |
| (then |
| (drop |
| ;; This is unreachable. |
| (i32.add |
| (i32.const 10) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-binary-contradiction-other-set (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-binary-contradiction-other-set (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 30) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-binary-contradiction-other-set |
| (local $x i32) |
| ;; As above, but now the contradiction tested is between a local.set and |
| ;; the if condition. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 20) |
| ) |
| (then |
| (drop |
| ;; This is unreachable. |
| (i32.add |
| (i32.const 10) |
| (i32.const 20) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $contadiction-during-flipping (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local $y i32) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $contadiction-during-flipping (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local $y i32) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $contadiction-during-flipping |
| (local $x i32) |
| (local $y i32) |
| (local.set $y |
| (i32.const 1) |
| ) |
| ;; $x == 0, $y == 1, so they are never equal, and the if body is |
| ;; unreachable. We find this out while applying the secondary facts of a |
| ;; constraint: we add $y == $x, and then apply $x's constraints to $y, |
| ;; ending up in $y with $y == 1 && $y == 0. |
| (if |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| (then |
| ;; This becomes unreachable. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-br_if (type $0) (param $param i32) |
| ;; CHECK-NEXT: (block $block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $block |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-br_if (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (block $block |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $block |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-br_if (param $param i32) |
| (block $block |
| ;; We can infer nothing yet. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| (br_if $block |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ;; Now we can, this is false. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ;; Merging after the block, we can't. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $conditional-br_if_2 (type $0) (param $param i32) |
| ;; CHECK-NEXT: (block $block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $block |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (return) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $conditional-br_if_2 (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (block $block |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $block |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (return) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $conditional-br_if_2 (param $param i32) |
| ;; As above, but with a return to avoid a final merge. |
| (block $block |
| ;; As before, we cannot infer here. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| (br_if $block |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ;; As before, we can infer 0 here. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| (return) ;; this was added |
| ) |
| ;; Because of the return, we can infer 1 here. |
| (drop |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $unreachable-br_if (type $0) (param $param i32) |
| ;; CHECK-NEXT: (block $block |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: (br_if $block |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $unreachable-br_if (type $0) (param $param i32) |
| ;; OPTIN-NEXT: (block $block |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: (br_if $block |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $unreachable-br_if (param $param i32) |
| (block $block |
| ;; We should not error on br_if in unreachable code. |
| (unreachable) |
| (br_if $block |
| (i32.eq |
| (local.get $param) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $br_on_null (type $5) (param $param anyref) |
| ;; CHECK-NEXT: (block $block |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.is_null |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (br_on_null $block |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (return) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $br_on_null (type $5) (param $param anyref) |
| ;; OPTIN-NEXT: (block $block |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (ref.is_null |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (br_on_null $block |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (return) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $br_on_null (param $param anyref) |
| (block $block |
| ;; We cannot infer here. |
| (drop |
| (ref.is_null |
| (local.get $param) |
| ) |
| ) |
| (drop |
| (br_on_null $block |
| (local.get $param) |
| ) |
| ) |
| ;; We can infer 0 here. |
| (drop |
| (ref.is_null |
| (local.get $param) |
| ) |
| ) |
| (return) |
| ) |
| ;; Because of the return, we can infer 1 here. |
| (drop |
| (ref.is_null |
| (local.get $param) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $br_on_non_null (type $5) (param $param anyref) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block $block (result (ref any)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.is_null |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_on_non_null $block |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (return) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $br_on_non_null (type $5) (param $param anyref) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (block $block (result (ref any)) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (ref.is_null |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_on_non_null $block |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (return) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $br_on_non_null (param $param anyref) |
| (drop |
| (block $block (result (ref any)) |
| ;; We cannot infer here. |
| (drop |
| (ref.is_null |
| (local.get $param) |
| ) |
| ) |
| (br_on_non_null $block |
| (local.get $param) |
| ) |
| ;; We can infer 1 here. |
| (drop |
| (ref.is_null |
| (local.get $param) |
| ) |
| ) |
| (return) |
| ) |
| ) |
| ;; Because of the return, we can infer 0 here. |
| (drop |
| (ref.is_null |
| (local.get $param) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-lt_u (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.lt_u |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-lt_u (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.lt_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ge_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-lt_u (param $x i32) |
| ;; The simple case where an inequality is seen again, in exact form. |
| (if |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| ;; We can infer 1, 0 here. |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| ;; We can infer 0, 1 here. |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-lt_s (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.lt_s |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-lt_s (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.lt_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ge_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-lt_s (param $x i32) |
| (if |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-le_u (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.le_u |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-le_u (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.le_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.gt_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-le_u (param $x i32) |
| (if |
| (i32.le_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-le_s (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.le_s |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-le_s (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.le_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.gt_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-le_s (param $x i32) |
| (if |
| (i32.le_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-gt_u (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.gt_u |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-gt_u (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.gt_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.le_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-gt_u (param $x i32) |
| (if |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-gt_s (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.gt_s |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-gt_s (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.gt_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.le_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-gt_s (param $x i32) |
| (if |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-ge_u (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.ge_u |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-ge_u (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ge_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.lt_u |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-ge_u (param $x i32) |
| (if |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $inequalities-ge_s (type $0) (param $x i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.ge_s |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $inequalities-ge_s (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ge_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.lt_s |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $inequalities-ge_s (param $x i32) |
| (if |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| (then |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| (else |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $local-changes (type $3) (param $x i32) (param $y i32) (param $z i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $local-changes (type $3) (param $x i32) (param $y i32) (param $z i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $local-changes (param $x i32) (param $y i32) (param $z i32) |
| (local.set $x |
| (local.get $y) |
| ) |
| ;; x == y but not z. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $x) |
| ) |
| ) |
| |
| ;; Set x to z. Now x == z but we can prove nothing about x and y. |
| (local.set $x |
| (local.get $z) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $x) |
| ) |
| ) |
| |
| ;; No idea about y vs z. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $y) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $local-changes-2 (type $3) (param $x i32) (param $y i32) (param $z i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $local-changes-2 (type $3) (param $x i32) (param $y i32) (param $z i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $local-changes-2 (param $x i32) (param $y i32) (param $z i32) |
| ;; As above, but the set in the middle is on y, not x. |
| (local.set $x |
| (local.get $y) |
| ) |
| ;; x == y but not z, as above. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $x) |
| ) |
| ) |
| |
| (local.set $y ;; this changed |
| (local.get $z) |
| ) |
| ;; We can prove nothing here. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $x) |
| ) |
| ) |
| |
| ;; But y == z. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $y) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $local-changes-if (type $7) (param $x i32) (param $y i32) (param $z i32) (param $w i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (local.get $w) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $local-changes-if (type $7) (param $x i32) (param $y i32) (param $z i32) (param $w i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (local.get $w) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $local-changes-if (param $x i32) (param $y i32) (param $z i32) (param $w i32) |
| ;; Local changes after if conditions set up constraints. |
| (if |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| (then |
| (if |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| (then |
| ;; x == y and x == z here. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $x) |
| ) |
| ) |
| ;; TODO: y == z |
| |
| ;; Modify y to the value of w. x is still equal to z, but no longer |
| ;; to y. |
| (local.set $y |
| (local.get $w) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $z) |
| (local.get $x) |
| ) |
| ) |
| ;; But y == w. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $w) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $w) |
| (local.get $y) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $local-changes-ne (type $3) (param $x i32) (param $y i32) (param $z i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.ne |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.ne |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.ne |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.ne |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $z) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $local-changes-ne (type $3) (param $x i32) (param $y i32) (param $z i32) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.ne |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (local.get $z) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $local-changes-ne (param $x i32) (param $y i32) (param $z i32) |
| ;; Similar to above, but testing != rather than == |
| (if |
| (i32.ne |
| (local.get $x) |
| (local.get $y) |
| ) |
| (then |
| ;; x == y is false, and we know nothing about z. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| |
| ;; Set x to z. Now x != z is false, but we can prove nothing about |
| ;; x and y. |
| (local.set $x |
| (local.get $z) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (local.get $y) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $x) |
| (local.get $z) |
| ) |
| ) |
| |
| ;; No idea about y vs z. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (local.get $z) |
| ) |
| ) |
| (drop |
| (i32.ne |
| (local.get $y) |
| (local.get $z) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-local-copy (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local $y i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-local-copy (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local $y i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 10) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-local-copy |
| (local $x i32) |
| (local $y i32) |
| ;; x is 10, y is copied. |
| (local.set $x |
| (i32.const 10) |
| ) |
| (local.set $y |
| (local.get $x) |
| ) |
| ;; Verify those values: both x and y are equal to 10. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 10) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-local-copy-if (type $2) (param $x i32) (param $y i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-local-copy-if (type $2) (param $x i32) (param $y i32) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-local-copy-if (param $x i32) (param $y i32) |
| (if |
| (i32.eq |
| (local.get $x) |
| (i32.const 42) |
| ) |
| (then |
| ;; We don't know anything yet. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 42) |
| ) |
| ) |
| ;; Copy x into y, and see that it is now equal to 42. |
| (local.set $y |
| (local.get $x) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 42) |
| ) |
| ) |
| ;; x was not changed (equal to 42) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| ) |
| (else |
| ;; We don't know anything yet. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 42) |
| ) |
| ) |
| ;; Copy x into y, and see that it is now *not* equal to 42. |
| (local.set $y |
| (local.get $x) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 42) |
| ) |
| ) |
| ;; x was not changed (not equal to 42) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-local-copy-if-2 (type $2) (param $x i32) (param $y i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-local-copy-if-2 (type $2) (param $x i32) (param $y i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-local-copy-if-2 (param $x i32) (param $y i32) |
| ;; As above, but the if's condition is on x == y, so that is where we |
| ;; apply equality between them. |
| (local.set $x |
| (i32.const 42) |
| ) |
| (if |
| (i32.eq |
| (local.get $x) |
| (local.get $y) |
| ) |
| (then |
| ;; This is true. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 42) |
| ) |
| ) |
| ;; x was not changed, so this is still true. |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $multi-local-copy-if-3 (type $2) (param $x i32) (param $y i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eq |
| ;; CHECK-NEXT: (local.get $y) |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $multi-local-copy-if-3 (type $2) (param $x i32) (param $y i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.eq |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: (local.get $y) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $multi-local-copy-if-3 (param $x i32) (param $y i32) |
| ;; As above, but the if's condition is flipped. |
| (local.set $x |
| (i32.const 42) |
| ) |
| (if |
| (i32.eq |
| (local.get $y) |
| (local.get $x) |
| ) |
| (then |
| ;; These are true. |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.eq |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $simple-array-sum (type $8) (param $param (ref $array)) (result i32) |
| ;; CHECK-NEXT: (local $index i32) |
| ;; CHECK-NEXT: (local $sum i32) |
| ;; CHECK-NEXT: (local $len i32) |
| ;; CHECK-NEXT: (local.set $len |
| ;; CHECK-NEXT: (array.len |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (loop $loop |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.ge_u |
| ;; CHECK-NEXT: (local.get $index) |
| ;; CHECK-NEXT: (local.get $len) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (return |
| ;; CHECK-NEXT: (local.get $sum) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $sum |
| ;; CHECK-NEXT: (i32.add |
| ;; CHECK-NEXT: (local.get $sum) |
| ;; CHECK-NEXT: (array.get $array |
| ;; CHECK-NEXT: (local.get $param) |
| ;; CHECK-NEXT: (local.get $index) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $index |
| ;; CHECK-NEXT: (i32.add |
| ;; CHECK-NEXT: (local.get $index) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br $loop) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $simple-array-sum (type $8) (param $param (ref $array)) (result i32) |
| ;; OPTIN-NEXT: (local $index i32) |
| ;; OPTIN-NEXT: (local $sum i32) |
| ;; OPTIN-NEXT: (local $len i32) |
| ;; OPTIN-NEXT: (local.set $len |
| ;; OPTIN-NEXT: (array.len |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (loop $loop |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.ge_u |
| ;; OPTIN-NEXT: (local.get $index) |
| ;; OPTIN-NEXT: (local.get $len) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (return |
| ;; OPTIN-NEXT: (local.get $sum) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $sum |
| ;; OPTIN-NEXT: (i32.add |
| ;; OPTIN-NEXT: (array.get $array |
| ;; OPTIN-NEXT: (local.get $param) |
| ;; OPTIN-NEXT: (local.get $index) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.get $sum) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (local.set $index |
| ;; OPTIN-NEXT: (i32.add |
| ;; OPTIN-NEXT: (local.get $index) |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br $loop) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $simple-array-sum (param $param (ref $array)) (result i32) |
| ;; A simple but realistic software bounds check that we can remove. |
| (local $index i32) |
| (local $sum i32) |
| (local $len i32) |
| ;; Stash the length in a local. |
| (local.set $len |
| (array.len |
| (local.get $param) |
| ) |
| ) |
| ;; Loop over the array. |
| (loop $loop |
| ;; If we reached the end of the array, return the sum. |
| (if |
| (i32.ge_u |
| (local.get $index) |
| (local.get $len) |
| ) |
| (then |
| (return |
| (local.get $sum) |
| ) |
| ) |
| ) |
| ;; Software bounds check, right before the actual access. After we |
| ;; optimize, the condition here becomes zero, so it will be removed later. |
| (if |
| (i32.ge_u |
| (local.get $index) |
| (local.get $len) |
| ) |
| (then |
| (unreachable) |
| ) |
| ) |
| ;; Read the array and add to the sum. |
| (local.set $sum |
| (i32.add |
| (local.get $sum) |
| (array.get $array |
| (local.get $param) |
| (local.get $index) |
| ) |
| ) |
| ) |
| ;; Increment. |
| (local.set $index |
| (i32.add |
| (local.get $index) |
| (i32.const 1) |
| ) |
| ) |
| ;; Keep looping. |
| (br $loop) |
| ) |
| ) |
| |
| ;; CHECK: (func $unreachable-loop (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: (block |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (loop $loop (result i32) |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $unreachable-loop (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: (block |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (loop $loop (result i32) |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $unreachable-loop |
| (local $x i32) |
| ;; The entire loop is unreachable. The control flow here should not cause any |
| ;; internal errors, and we can just optimize this to unreachable (though we |
| ;; keep the local.set, because of non-nullable local validation). |
| (unreachable) |
| (local.set $x |
| (loop $loop (result i32) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $set-silly (type $0) (param $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $set-silly (type $0) (param $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $set-silly (param $x i32) |
| ;; Setting x to x adds no information, and we do not store it in the IR. This |
| ;; must not lead to internal errors (we have asserts on not storing |
| ;; "proves-nothing" in the internal map, and if we wrote this, it would be |
| ;; that). |
| (local.set $x |
| (local.get $x) |
| ) |
| ;; Add some control flow to exercise the assert. |
| (if |
| (i32.const 0) |
| (then) |
| ) |
| ) |
| |
| ;; CHECK: (func $iloop (type $9) (param $0 f32) |
| ;; CHECK-NEXT: (local $1 f32) |
| ;; CHECK-NEXT: (local.set $0 |
| ;; CHECK-NEXT: (local.get $1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (loop |
| ;; CHECK-NEXT: (local.set $1 |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (loop $label |
| ;; CHECK-NEXT: (loop |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $label |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $iloop (type $9) (param $0 f32) |
| ;; OPTIN-NEXT: (local $1 f32) |
| ;; OPTIN-NEXT: (local.set $0 |
| ;; OPTIN-NEXT: (local.get $1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (if |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: (then |
| ;; OPTIN-NEXT: (loop |
| ;; OPTIN-NEXT: (local.set $1 |
| ;; OPTIN-NEXT: (local.get $0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (else |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (loop $label |
| ;; OPTIN-NEXT: (loop |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $label |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $iloop (param $0 f32) |
| ;; Regression test for an infinite loop: the specific cfg here + the |
| ;; constraints lead to a situation where, if we were not careful, we would |
| ;; think we have an infinite stream of updates in flow(). Specifically, we |
| ;; end up updating a location to a combination of two constraints {A, B} and |
| ;; then end up finding {B, A} in the next cycle, and then alternate those |
| ;; two forever. This is fixed by sorting the constraints. |
| ;; |
| ;; (There is nothing to optimize here, we just should not hang or error.) |
| (local $1 f32) |
| (local.set $0 |
| (local.get $1) |
| ) |
| (if |
| (i32.const 0) |
| (then |
| (loop |
| (local.set $1 |
| (local.get $0) |
| ) |
| ) |
| ) |
| (else |
| ) |
| ) |
| (loop $label |
| (loop |
| ) |
| (br_if $label |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $nested-binaries (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local $e eqref) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.lt_u |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $nested-binaries (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local $e eqref) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.gt_u |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $nested-binaries |
| (local $x i32) |
| (local $e eqref) |
| ;; Nested binaries. The outer one is initially not relevant - we cannot |
| ;; parse the right hand side - but after optimization it simplifies. We |
| ;; should not assert here, and only optimize the inner one, leaving the |
| ;; outer for later. |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (ref.eq |
| (local.get $e) |
| (ref.null none) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $relevant-copy (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local $y i32) |
| ;; CHECK-NEXT: (local.set $y |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $relevant-copy (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local $y i32) |
| ;; OPTIN-NEXT: (local.set $y |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $relevant-copy |
| (local $x i32) |
| (local $y i32) |
| ;; x is not relevant, but it is copied to y, which is, so we must track x as |
| ;; relevant too. |
| (local.set $y |
| (local.get $x) |
| ) |
| (drop |
| (i32.eq |
| (local.get $y) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-lt_s (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-lt_s (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-lt_s |
| ;; A constant in $x is checked against inequalities using constants. |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.lt_s |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-le_s (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-le_s (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-le_s |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.le_s |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-gt_s (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-gt_s (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-gt_s |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.gt_s |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-ge_s (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-ge_s (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-ge_s |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.ge_s |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-lt_u (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-lt_u (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-lt_u |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-le_u (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-le_u (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-le_u |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.le_u |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-gt_u (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-gt_u (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-gt_u |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $constant-inequalities-ge_u (type $1) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (local.set $x |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $constant-inequalities-ge_u (type $1) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (local.set $x |
| ;; OPTIN-NEXT: (i32.const 42) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (drop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $constant-inequalities-ge_u |
| (local $x i32) |
| (local.set $x |
| (i32.const 42) |
| ) |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 41) |
| ) |
| ) |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 42) |
| ) |
| ) |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const 43) |
| ) |
| ) |
| (drop |
| (i32.ge_u |
| (local.get $x) |
| (i32.const -1) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $flipped-contradiction (type $6) (result i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (loop $loop |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $flipped-contradiction (type $6) (result i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (loop $loop |
| ;; OPTIN-NEXT: (br_if $loop |
| ;; OPTIN-NEXT: (i32.const 1) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $loop |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (unreachable) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $flipped-contradiction (result i32) |
| (local $x i32) |
| (loop $loop (result i32) |
| ;; If we do not branch, we add the constraint x >= 1. |
| (br_if $loop |
| (i32.lt_u |
| (local.get $x) |
| (i32.const 1) |
| ) |
| ) |
| ;; If we do not branch, we add the constraint x == 0. This contradicts the |
| ;; one before, making the code after us unreachable. |
| (br_if $loop |
| (local.get $x) |
| ) |
| ;; An eqz that will become unreachable. |
| (i32.eqz |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $flipped-contradiction-no (type $6) (result i32) |
| ;; CHECK-NEXT: (local $x i32) |
| ;; CHECK-NEXT: (loop $loop (result i32) |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br_if $loop |
| ;; CHECK-NEXT: (local.get $x) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.eqz |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; OPTIN: (func $flipped-contradiction-no (type $6) (result i32) |
| ;; OPTIN-NEXT: (local $x i32) |
| ;; OPTIN-NEXT: (loop $loop (result i32) |
| ;; OPTIN-NEXT: (br_if $loop |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (br_if $loop |
| ;; OPTIN-NEXT: (local.get $x) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: (i32.eqz |
| ;; OPTIN-NEXT: (i32.const 0) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| ;; OPTIN-NEXT: ) |
| (func $flipped-contradiction-no (result i32) |
| ;; As above, but with lt replaced by gt. Now the constraints are x <= 1 and |
| ;; x == 0, which do not contradict, and nothing becomes unreachable. |
| (local $x i32) |
| (loop $loop (result i32) |
| (br_if $loop |
| (i32.gt_u |
| (local.get $x) |
| (i32.const 1) |
| ) |
| ) |
| (br_if $loop |
| (local.get $x) |
| ) |
| (i32.eqz |
| (i32.const 0) |
| ) |
| ) |
| ) |
| ) |