blob: 6b96ca8443d0f95b8bd17003dfb1cf23d36d875f [file]
;; 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: (import "a" "b" (func $import (type $7) (result i32)))
;; OPTIN: (import "a" "b" (func $import (type $7) (result i32)))
(import "a" "b" (func $import (result 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: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; 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: (block
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (block
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; 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: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; 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: (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-default (type $1)
;; OPTIN-NEXT: (local $x i32)
;; 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-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) ;; this is 0, hence the if is not taken
(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.const 0)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; 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.const 0)
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (block
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; 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. We can also infer 0 for the if
;; condition.
(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 $4) (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 $4) (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 $4) (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 $4) (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 $8) (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 $8) (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: (i32.const 10)
;; 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: (i32.const 10)
;; 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: (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: )
;; 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 (which is 42) 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: (i32.const 42)
;; 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: (i32.const 42)
;; 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) ;; this is 42
(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: (i32.const 42)
;; 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: (i32.const 42)
;; 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 $9) (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 $9) (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 $10) (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 $10) (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.const 1)
;; 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: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $nested-binaries
(local $x i32)
(local $e eqref)
;; Nested binaries of different types. We can apply the local.gets and then
;; optimize the ref.eq to 1 and the lt_u to 1 as well. (This does not fully
;; work out in OPTIN due to reordering, but Precompute would handle it.)
(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: (i32.const 0)
;; 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: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $relevant-copy
(local $x i32)
(local $y i32)
;; x has no sets or uses but for a copy to $y, but we still optimize here.
(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) (param $x i32) (result i32)
;; CHECK-NEXT: (loop $loop
;; CHECK-NEXT: (br_if $loop
;; CHECK-NEXT: (i32.lt_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; 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) (param $x i32) (result i32)
;; OPTIN-NEXT: (loop $loop
;; OPTIN-NEXT: (br_if $loop
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (br_if $loop
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $flipped-contradiction (param $x i32) (result 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) (param $x i32) (result i32)
;; CHECK-NEXT: (loop $loop (result i32)
;; CHECK-NEXT: (br_if $loop
;; CHECK-NEXT: (i32.gt_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; 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) (param $x i32) (result i32)
;; OPTIN-NEXT: (loop $loop (result i32)
;; OPTIN-NEXT: (br_if $loop
;; OPTIN-NEXT: (i32.gt_u
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; 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 (param $x i32) (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.
(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)
)
)
)
;; CHECK: (func $tee (type $1)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local $y i32)
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (local.tee $y
;; CHECK-NEXT: (i32.const 10)
;; 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 $tee (type $1)
;; OPTIN-NEXT: (local $x i32)
;; OPTIN-NEXT: (local $y i32)
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (local.tee $y
;; OPTIN-NEXT: (i32.const 10)
;; 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 $tee
;; We can read values through tees.
(local $x i32)
(local $y i32)
(local.set $x
(local.tee $y
(i32.const 10)
)
)
(drop
(i32.eq
(local.get $x)
(i32.const 10)
)
)
(drop
(i32.eq
(local.get $y)
(i32.const 10)
)
)
)
;; CHECK: (func $fallthrough (type $1)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (call $fallthrough)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $fallthrough (type $1)
;; OPTIN-NEXT: (local $x i32)
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (call $fallthrough)
;; OPTIN-NEXT: (i32.const 10)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $fallthrough
;; We can read values through a fallthrough.
(local $x i32)
(local.set $x
(block (result i32)
(call $fallthrough)
(i32.const 10)
)
)
(drop
(i32.eq
(local.get $x)
(i32.const 10)
)
)
)
;; CHECK: (func $fallthrough-get (type $1)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local $z i32)
;; CHECK-NEXT: (local $w i32)
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $z
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $w
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $fallthrough-get (type $1)
;; OPTIN-NEXT: (local $x i32)
;; OPTIN-NEXT: (local $z i32)
;; OPTIN-NEXT: (local $w i32)
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.set $z
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.set $w
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $fallthrough-get
(local $x i32)
(local $z i32)
(local $w i32)
;; $x gets the initial value of $z (0) via block fallthrough. We should
;; notice that $z is relevant, i.e., we need to track its values, even
;; though we get it through a fallthrough and not directly.
(local.set $x
(block (result i32)
(local.get $z)
)
)
;; $z is modified to 42.
(local.set $z (i32.const 42))
;; $w gets the updated value of $z (42), also via block fallthrough.
(local.set $w
(block (result i32)
(local.get $z)
)
)
;; 0 == 42 is 0 at runtime. If we did not mark $z as relevant, we would see
;; $x and $w as both equal to $z, i.e., that they are themselves equal, and
;; misoptimize this to 1. We optimize to 0 here.
(drop
(i32.eq
(local.get $x)
(local.get $w)
)
)
)
;; CHECK: (func $fallthrough-tee (type $0) (param $param i32)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local $z i32)
;; CHECK-NEXT: (local $w i32)
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (local.tee $param
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $z
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $w
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $fallthrough-tee (type $0) (param $param i32)
;; OPTIN-NEXT: (local $x i32)
;; OPTIN-NEXT: (local $z i32)
;; OPTIN-NEXT: (local $w i32)
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (local.tee $param
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.set $z
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.set $w
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $fallthrough-tee (param $param i32)
(local $x i32)
(local $z i32)
(local $w i32)
;; Similar to above, but now a tee is used for the fallthrough.
(local.set $x
(local.tee $param ;; this changed
(local.get $z)
)
)
(local.set $z (i32.const 42))
(local.set $w
(block (result i32)
(local.get $z)
)
)
;; As before, this is optimized to 0.
(drop
(i32.eq
(local.get $x)
(local.get $w)
)
)
)
;; CHECK: (func $eqz-condition (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $eqz-condition (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $eqz-condition (param $x i32)
;; Verify we parse an eqz condition and can optimize after it.
(if
(i32.eqz
(local.get $x)
)
(then
;; Also test we parse this binary properly, and see it is equivalent to
;; the eqz.
(drop
(i32.eq
(local.get $x)
(i32.const 0)
)
)
)
)
)
;; CHECK: (func $eqz-condition-64 (type $11) (param $x i64)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i64.eqz
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $eqz-condition-64 (type $11) (param $x i64)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i64.eqz
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $eqz-condition-64 (param $x i64)
;; As above, but i64.
(if
(i64.eqz
(local.get $x)
)
(then
(drop
(i64.eq
(local.get $x)
(i64.const 0)
)
)
)
)
)
;; CHECK: (func $sign-unsigned-less-more-mix (type $0) (param $0 i32)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (br_if $block
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1024)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.gt_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const -1992)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $sign-unsigned-less-more-mix (type $0) (param $0 i32)
;; OPTIN-NEXT: (block $block
;; OPTIN-NEXT: (br_if $block
;; OPTIN-NEXT: (i32.ge_s
;; OPTIN-NEXT: (local.get $0)
;; OPTIN-NEXT: (i32.const 1024)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.gt_u
;; OPTIN-NEXT: (local.get $0)
;; OPTIN-NEXT: (i32.const -1992)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $sign-unsigned-less-more-mix (param $0 i32)
(block $block
(br_if $block
(i32.ge_s
(local.get $0)
(i32.const 1024)
)
)
;; Here we know $0 <_s 1024. That includes non-negative numbers like 0 as
;; well as negative numbers. The following *unsigned* inequality might or
;; might not be true, so we optimize nothing.
(drop
(i32.gt_u
(local.get $0)
(i32.const -1992)
)
)
)
)
;; CHECK: (func $sign-unsigned-less-more-mix-2 (type $0) (param $0 i32)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (br_if $block
;; CHECK-NEXT: (i32.gt_s
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const -1023)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.gt_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const -1992)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $sign-unsigned-less-more-mix-2 (type $0) (param $0 i32)
;; OPTIN-NEXT: (block $block
;; OPTIN-NEXT: (br_if $block
;; OPTIN-NEXT: (i32.gt_s
;; OPTIN-NEXT: (local.get $0)
;; OPTIN-NEXT: (i32.const -1023)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.gt_u
;; OPTIN-NEXT: (local.get $0)
;; OPTIN-NEXT: (i32.const -1992)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $sign-unsigned-less-more-mix-2 (param $0 i32)
;; Similar to the above, but the 1024 was replaced by -1023.
(block $block
(br_if $block
(i32.gt_s
(local.get $0)
(i32.const -1023) ;; this changed
)
)
;; Here we know $0 <=_s -1023. This includes most numbers with the sign
;; bit set, except for the lowest in absolute value. That implies the
;; following *unsigned* inequality might or might not be true, so we
;; optimize nothing.
(drop
(i32.gt_u
(local.get $0)
(i32.const -1992)
)
)
)
)
;; CHECK: (func $sign-unsigned-less-more-mix-3-yes (type $0) (param $0 i32)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (br_if $block
;; CHECK-NEXT: (i32.gt_s
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const -4096)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $sign-unsigned-less-more-mix-3-yes (type $0) (param $0 i32)
;; OPTIN-NEXT: (block $block
;; OPTIN-NEXT: (br_if $block
;; OPTIN-NEXT: (i32.gt_s
;; OPTIN-NEXT: (local.get $0)
;; OPTIN-NEXT: (i32.const -4096)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $sign-unsigned-less-more-mix-3-yes (param $0 i32)
;; Similar to the above, but the 1024 was replaced by -4096.
(block $block
(br_if $block
(i32.gt_s
(local.get $0)
(i32.const -4096) ;; this changed
)
)
;; Now we can optimize: there is no overlap possible, so this is 0.
(drop
(i32.gt_u
(local.get $0)
(i32.const -1992)
)
)
)
)
;; CHECK: (func $eqz_eqz (type $0) (param $a i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $eqz_eqz (type $0) (param $a i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $eqz_eqz (param $a i32)
(if
;; !!a => a is not 0.
(i32.eqz
(i32.eqz
(local.get $a)
)
)
(then
(drop
;; This is true.
(i32.ne
(local.get $a)
(i32.const 0)
)
)
)
)
)
;; CHECK: (func $pair (type $2) (param $a i32) (param $b i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $b)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; 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 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $b)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $pair (type $2) (param $a i32) (param $b i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $b)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; 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: (else
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $b)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $pair (param $a i32) (param $b i32)
;; Two constraints in one if condition.
(if
(i32.and
;; a == 0
(i32.eqz
(local.get $a)
)
;; b == 42
(i32.eq
(local.get $b)
(i32.const 42)
)
)
(then
;; These are all true.
(drop
(i32.eq
(local.get $a)
(i32.const 0)
)
)
(drop
(i32.eq
(local.get $b)
(i32.const 42)
)
)
;; This is not.
(drop
(i32.eq
(local.get $a)
(i32.const 42)
)
)
)
(else
;; The same expressions as in the (then ..). Here, at least one must be
;; false, not not necessarily all of them, so we infer nothing.
(drop
(i32.eq
(local.get $a)
(i32.const 0)
)
)
(drop
(i32.eq
(local.get $b)
(i32.const 42)
)
)
(drop
(i32.eq
(local.get $a)
(i32.const 42)
)
)
;; A silly extra instruction to stop optimize-instructions from
;; folding the if-else arms.
(drop
(i32.const 42)
)
)
)
)
;; CHECK: (func $pair-same-local (type $0) (param $a i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.gt_u
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.gt_u
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; 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 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $pair-same-local (type $0) (param $a i32)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (if (result i32)
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.gt_u
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.gt_u
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (else
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $pair-same-local (param $a i32)
;; Similar to above, but now the two ANDed conditions are about the same
;; local
(if
(i32.and
;; a > 42
(i32.gt_u
(local.get $a)
(i32.const 42)
)
;; a > 1337
(i32.gt_u
(local.get $a)
(i32.const 1337)
)
)
(then
;; This is true.
(drop
(i32.gt_u
(local.get $a)
(i32.const 1337)
)
)
)
(else
;; The negation of a > 42 && a > 1337 is a <= 42 || a <= 1337, so we
;; can infer a <= 1337.
(drop
(i32.le_u
(local.get $a)
(i32.const 1337)
)
)
)
)
)
;; CHECK: (func $pair-same-local-bad-or (type $0) (param $a i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; 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.ne
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 500)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 500)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $pair-same-local-bad-or (type $0) (param $a i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; 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.ne
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 500)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (else
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 500)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $pair-same-local-bad-or (param $a i32)
;; As above, but the OR we do for the else fails.
(if
(i32.and
;; a != 42 && a != 1337
(i32.ne
(local.get $a)
(i32.const 42)
)
(i32.ne
(local.get $a)
(i32.const 1337)
)
)
(then
;; These are true.
(drop
(i32.ne
(local.get $a)
(i32.const 42)
)
)
(drop
(i32.ne
(local.get $a)
(i32.const 1337)
)
)
;; This is unknown.
(drop
(i32.ne
(local.get $a)
(i32.const 500)
)
)
)
(else
;; ORing a == 42 || a == 1337, we get nothing useful, and can prove
;; nothing. TODO: we could infer a span here
(drop
(i32.eq
(local.get $a)
(i32.const 42)
)
)
(drop
(i32.eq
(local.get $a)
(i32.const 1337)
)
)
(drop
(i32.eq
(local.get $a)
(i32.const 500)
)
)
)
)
)
;; CHECK: (func $pair-partial (type $0) (param $a i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; 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 $a)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $pair-partial (type $0) (param $a i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (else
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $pair-partial (param $a i32)
(if
(i32.and
;; a == 42
(i32.eq
(local.get $a)
(i32.const 42)
)
;; ANDed with something we know nothing about
(call $import)
)
(then
;; a must be 42, to get here.
(drop
(i32.eq
(local.get $a)
(i32.const 42)
)
)
)
(else
;; But we don't know anything about a here: we get to this place when
;; a != 42 OR the unknown was 0, so a could be anything.
(drop
(i32.eq
(local.get $a)
(i32.const 42)
)
)
;; A silly extra instruction to stop optimize-instructions from
;; folding the if-else arms.
(drop
(i32.const 42)
)
)
)
)
;; CHECK: (func $several (type $12) (param $a i32) (param $b i32) (param $c i32) (param $d i32) (param $e i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $b)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $d)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; 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: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $c)
;; CHECK-NEXT: (i32.const 40)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $several (type $12) (param $a i32) (param $b i32) (param $c i32) (param $d i32) (param $e i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $b)
;; OPTIN-NEXT: (i32.const 10)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $a)
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $d)
;; OPTIN-NEXT: (i32.const 20)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $e)
;; OPTIN-NEXT: (i32.const 30)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; 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: (drop
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $c)
;; OPTIN-NEXT: (i32.const 40)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $several (param $a i32) (param $b i32) (param $c i32) (param $d i32) (param $e i32)
;; Four constraints in one if condition.
(if
(i32.and
(i32.and
;; !!a => a is not 0.
(i32.eqz
(i32.eqz
(local.get $a)
)
)
;; b == 10
(i32.eq
(local.get $b)
(i32.const 10)
)
)
(i32.and
;; d == 20
(i32.eq
(local.get $d)
(i32.const 20)
)
;; e == 30
(i32.eq
(local.get $e)
(i32.const 30)
)
)
)
(then
;; These are all true.
(drop
(i32.ne
(local.get $a)
(i32.const 0)
)
)
(drop
(i32.eq
(local.get $b)
(i32.const 10)
)
)
(drop
(i32.eq
(local.get $d)
(i32.const 20)
)
)
(drop
(i32.eq
(local.get $e)
(i32.const 30)
)
)
;; This is false.
(drop
(i32.eq
(local.get $a)
(i32.const 0)
)
)
;; This local is unknown.
(drop
(i32.eq
(local.get $c)
(i32.const 40)
)
)
)
)
)
;; CHECK: (func $three.contradiction.middle (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.lt_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $three.contradiction.middle (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.lt_s
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ge_s
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (block
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $three.contradiction.middle (param $x i32)
;; First we set x == 0, then x < 0, then x >= 0. The first two are a
;; contradiction. We should not error (after a contradiction, we should not
;; apply further constraints), and can optimize away the if body.
(if
(i32.and
(i32.eqz
(local.get $x)
)
(i32.and
(i32.lt_s
(local.get $x)
(i32.const 0)
)
(i32.ge_s
(local.get $x)
(i32.const 0)
)
)
)
(then
(drop
(i32.eqz
(local.get $x)
)
)
)
)
)
;; CHECK: (func $br_if_and (type $0) (param $param i32)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (br_if $block
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $param)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $param)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $param)
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $br_if_and (type $0) (param $param i32)
;; OPTIN-NEXT: (block $block
;; OPTIN-NEXT: (br_if $block
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $param)
;; OPTIN-NEXT: (i32.const 10)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $param)
;; OPTIN-NEXT: (i32.const 20)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (return)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $param)
;; OPTIN-NEXT: (i32.const 30)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $br_if_and (param $param i32)
;; An AND in a br_if condition.
(block $block
(br_if $block
(i32.and
(i32.ne
(local.get $param)
(i32.const 10)
)
(i32.ne
(local.get $param)
(i32.const 20)
)
)
)
(return)
)
;; If we get here, param != 10 && param != 20. We optimize each arm of the
;; AND here.
(drop
(i32.and
(i32.ne
(local.get $param)
(i32.const 10)
)
(i32.ne
(local.get $param)
(i32.const 20)
)
)
)
;; This one we don't know.
(drop
(i32.ne
(local.get $param)
(i32.const 30)
)
)
)
;; CHECK: (func $tee-condition (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition (param $x i32)
;; We can parse the tee in the condition below. The constraint is saying
;; $x == 42.
(if
(i32.eq
(local.tee $x
(call $import)
)
(i32.const 42)
)
(then
;; $x == 42, so this is false.
(drop
(i32.eqz
(local.get $x)
)
)
)
)
)
;; CHECK: (func $tee-condition-later-get (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; 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 $tee-condition-later-get (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; 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 $tee-condition-later-get (param $x i32)
;; The nested ANDs here include a tee and a later get, which is fine.
(if
(i32.and
(i32.ne
(local.tee $x
(call $import)
)
(i32.const 42)
)
(i32.ne
(local.get $x)
(i32.const 1337)
)
)
(then
;; $x != 42 && $x != 1337, so these are true.
(drop
(i32.ne
(local.get $x)
(i32.const 42)
)
)
(drop
(i32.ne
(local.get $x)
(i32.const 1337)
)
)
)
)
)
;; CHECK: (func $tee-condition-later-get-2 (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-later-get-2 (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-later-get-2 (param $x i32)
;; A later get without two ANDs - in the same comparison. We can infer the
;; comparison is 1.
(if
(i32.eq
(local.tee $x
(i32.const 42)
)
(local.get $x)
)
(then
;; $x == 42, so this is true.
(drop
(i32.eq
(local.get $x)
(i32.const 42)
)
)
)
)
)
;; CHECK: (func $tee-condition-later-tee (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-later-tee (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-later-tee (param $x i32)
;; Reverse the tee and get order. $x appears twice, with two different
;; values, so we give up here.
;; TODO: use SSA
(if
(i32.and
(i32.ne
(local.get $x)
(i32.const 42)
)
(i32.ne
(local.tee $x
(call $import)
)
(i32.const 1337)
)
)
(then
;; We infer nothing here TODO: we could infer the last
(drop
(i32.ne
(local.get $x)
(i32.const 42)
)
)
(drop
(i32.ne
(local.get $x)
(i32.const 1337)
)
)
)
)
)
;; CHECK: (func $tee-condition-later-tee-different-local (type $2) (param $x i32) (param $y i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.tee $y
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; 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 $tee-condition-later-tee-different-local (type $2) (param $x i32) (param $y i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.tee $y
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 1337)
;; OPTIN-NEXT: )
;; 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 $tee-condition-later-tee-different-local (param $x i32) (param $y i32)
;; As above, a get and a tee that look like they interfere, but now the
;; local indexes are different. This is fine.
(if
(i32.and
(i32.ne
(local.get $x)
(i32.const 42)
)
(i32.ne
(local.tee $y
(call $import)
)
(i32.const 1337)
)
)
(then
;; $x != 42 && $y != 1337, so these are true.
(drop
(i32.ne
(local.get $x)
(i32.const 42)
)
)
(drop
(i32.ne
(local.get $y)
(i32.const 1337)
)
)
)
)
)
;; CHECK: (func $tee-condition-eqz (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-eqz (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-eqz (param $x i32)
;; Testing for parsing of tee in an eqz.
(if
(i32.eqz
(local.tee $x
(call $import)
)
)
(then
;; This is true.
(drop
(i32.eqz
(local.get $x)
)
)
)
)
)
;; CHECK: (func $tee-condition-eqz-eqz (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-eqz-eqz (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-eqz-eqz (param $x i32)
;; Testing for parsing of tee in an eqz^2. In the OPTIN case, the double
;; eqz is optimized out, and we test a bare local.tee in a condition.
(if
(i32.eqz
(i32.eqz
(local.tee $x
(call $import)
)
)
)
(then
;; This is false.
(drop
(i32.eqz
(local.get $x)
)
)
)
)
)
;; CHECK: (func $tee-test (type $0) (param $x 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.eqz
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-test (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 42)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-test (param $x i32)
;; A tee not in the condition, but in the test that we want to optimize.
(if
;; $x == 42.
(i32.eq
(local.get $x)
(i32.const 42)
)
(then
;; The $x being tested is not the same as the one the constraint was on,
;; so we do not optimize.
(drop
(i32.eqz
(local.tee $x
(call $import)
)
)
)
)
)
)
;; CHECK: (func $tee-condition-another (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.ne
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-another (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.ne
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.const 1)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-another (param $x i32)
;; Two tees of the same local.
(if
(i32.ne
(local.tee $x
(i32.const 0)
)
(local.tee $x
(i32.const 1)
)
)
(then
;; We know that $x == 1 here (the last tee; first should not confuse
;; us).
(drop
(i32.eq
(local.get $x)
(i32.const 1)
)
)
)
)
)
;; CHECK: (func $tee-condition-nested (type $2) (param $x i32) (param $y i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.tee $y
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; 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.eq
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-nested (type $2) (param $x i32) (param $y i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 10)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.tee $y
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (i32.const 20)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 30)
;; OPTIN-NEXT: )
;; 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.eq
;; OPTIN-NEXT: (local.get $y)
;; OPTIN-NEXT: (i32.const 30)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-nested (param $x i32) (param $y i32)
;; A second set is nested inside the tee. $x initially seems like it must be
;; equal to 10 in the If body, but it is set to 20 after.
(if
(i32.and
(i32.eq
(local.get $x)
(i32.const 10)
)
(i32.eq
(local.tee $y
(block (result i32)
(local.set $x
(i32.const 20)
)
(call $import)
)
)
(i32.const 30)
)
)
(then
;; This is false: $x was 10 (if the first ANDed expression was true),
;; but $x was set to 20 after.
(drop
(i32.eq
(local.get $x)
(i32.const 10)
)
)
;; This is true.
(drop
(i32.eq
(local.get $x)
(i32.const 20)
)
)
;; We don't infer this, even though we could: the get and later set of
;; $x make us give up. TODO
(drop
(i32.eq
(local.get $y)
(i32.const 30)
)
)
)
)
)
;; CHECK: (func $tee-condition-nested-2 (type $3) (param $x i32) (param $y i32) (param $z i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.tee $y
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (local.set $z
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; 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: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-condition-nested-2 (type $3) (param $x i32) (param $y i32) (param $z i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 10)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.tee $y
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (local.set $z
;; OPTIN-NEXT: (i32.const 20)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 30)
;; OPTIN-NEXT: )
;; 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: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-condition-nested-2 (param $x i32) (param $y i32) (param $z i32)
;; As above, but the second set is of another local. Without any conflict,
;; we can infer more.
(if
(i32.and
(i32.eq
(local.get $x)
(i32.const 10)
)
(i32.eq
(local.tee $y
(block (result i32)
(local.set $z ;; this changed
(i32.const 20)
)
(call $import)
)
)
(i32.const 30)
)
)
(then
;; These are all true.
(drop
(i32.eq
(local.get $x)
(i32.const 10)
)
)
(drop
(i32.eq
(local.get $y)
(i32.const 30)
)
)
(drop
(i32.eq
(local.get $z)
(i32.const 20)
)
)
)
)
)
;; CHECK: (func $tee-condition-nested-get (type $2) (param $x i32) (param $y i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.tee $y
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; 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 $tee-condition-nested-get (type $2) (param $x i32) (param $y i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: (i32.const 10)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.eq
;; OPTIN-NEXT: (local.tee $y
;; OPTIN-NEXT: (block (result i32)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (i32.const 30)
;; OPTIN-NEXT: )
;; 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 $tee-condition-nested-get (param $x i32) (param $y i32)
;; As $tee-condition-nested, but rather than a nested *set*, a get. A get
;; is not a problem for us.
(if
(i32.and
(i32.eq
(local.get $x)
(i32.const 10)
)
(i32.eq
(local.tee $y
(block (result i32)
(drop
(local.get $x) ;; this changed.
)
(call $import)
)
)
(i32.const 30)
)
)
(then
;; These are all true.
(drop
(i32.eq
(local.get $x)
(i32.const 10)
)
)
(drop
(i32.eq
(local.get $y)
(i32.const 30)
)
)
)
)
)
;; CHECK: (func $tee-trample-simple (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $tee-trample-simple (type $0) (param $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.and
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (call $import)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (i32.eqz
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $tee-trample-simple (param $x i32)
(if
(i32.and
;; $x == 0
(i32.eqz
(local.get $x)
)
;; But then trample $x with an unknown value.
(local.tee $x
(call $import)
)
)
(then
;; $x may not be 0 here, as it was trampled, so we infer nothing.
(drop
(i32.eqz
(local.get $x)
)
)
)
)
)
;; CHECK: (func $eqz-ref-is-null (type $4) (param $x anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $eqz-ref-is-null (type $4) (param $x anyref)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (ref.is_null
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $eqz-ref-is-null (param $x anyref)
(if
(i32.eqz
(ref.is_null
(local.get $x)
)
)
(then
;; $x is not null here, so ref.is_null($x) is false (0).
(drop
(ref.is_null
(local.get $x)
)
)
)
(else
;; $x is null here, so ref.is_null($x) is true (1).
(drop
(ref.is_null
(local.get $x)
)
)
)
)
)
;; CHECK: (func $local.get (type $0) (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $local.get (type $0) (param $x i32)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $local.get (param $x i32)
(if
(local.get $x)
(then
(drop
;; This is non-zero, but we can't optimze.
(local.get $x)
)
)
(else
(drop
;; This is zero.
(local.get $x)
)
)
)
)
;; CHECK: (func $local.get.refinalize (type $1)
;; CHECK-NEXT: (local $x anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $local.get.refinalize (type $1)
;; OPTIN-NEXT: (local $x anyref)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (block (result nullref)
;; OPTIN-NEXT: (ref.null none)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $local.get.refinalize
(local $x anyref)
;; The local.get below is null. After we apply a null there, we refinalize
;; the block's type to nullref.
(drop
(block (result anyref)
(local.get $x)
)
)
)
;; CHECK: (func $local.get.impossible.cast (type $13) (result (ref func))
;; CHECK-NEXT: (local $x (ref func))
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (ref.cast (ref nofunc)
;; CHECK-NEXT: (ref.null nofunc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; OPTIN: (func $local.get.impossible.cast (type $13) (result (ref func))
;; OPTIN-NEXT: (local $x (ref func))
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
(func $local.get.impossible.cast (result (ref func))
(local $x (ref func))
;; The cast here traps at runtime. We do not have a valid value to put in
;; place of the local.get (it is not refined enough), but we know it is
;; unreachable. (In OPTIN, we figure out the set's value is unreachable even
;; earlier.)
(local.set $x
(ref.cast (ref func)
(ref.null func)
)
)
(local.get $x)
)
;; CHECK: (func $local.get.no.v128 (type $1)
;; CHECK-NEXT: (local $x v128)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $local.get.no.v128 (type $1)
;; OPTIN-NEXT: (local $x v128)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $local.get.no.v128
(local $x v128)
;; We know the value here, but do not copy v128 constants, which are large.
;; TODO: should we optimize this?
(drop
(local.get $x)
)
)
;; CHECK: (func $local.get.unreachable (type $1)
;; CHECK-NEXT: (local $x i32)
;; 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 $local.get.unreachable (type $1)
;; OPTIN-NEXT: (local $x i32)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (i32.const 0)
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (unreachable)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $local.get.unreachable
(local $x i32)
(if
(local.get $x)
(then
;; $x is 0, so we never get here, and this is unreachable.
(drop
(local.get $x)
)
)
)
)
;; CHECK: (func $local.get.float (type $1)
;; CHECK-NEXT: (local $x f64)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (f64.eq
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (f64.const nan:0x8000000000000)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $local.get.float (type $1)
;; OPTIN-NEXT: (local $x f64)
;; OPTIN-NEXT: (if
;; OPTIN-NEXT: (f64.eq
;; OPTIN-NEXT: (local.tee $x
;; OPTIN-NEXT: (f64.const nan:0x8000000000000)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (then
;; OPTIN-NEXT: (nop)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $local.get.float
(local $x f64)
;; The condition here ends up comparing $x to itself. That is normally 1,
;; but not with a nan. We do not optimize floats for this reason (without
;; --fast-math, see constraint-analysis-float.wast).
(if
(f64.eq
(local.tee $x
(f64.const nan)
)
(local.get $x)
)
(then
(nop)
)
)
)
;; CHECK: (func $local.get.internalized-string (type $1)
;; CHECK-NEXT: (local $x anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $x
;; CHECK-NEXT: (any.convert_extern
;; CHECK-NEXT: (string.const "foo")
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPTIN: (func $local.get.internalized-string (type $1)
;; OPTIN-NEXT: (local $x anyref)
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (ref.null none)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (local.set $x
;; OPTIN-NEXT: (any.convert_extern
;; OPTIN-NEXT: (string.const "foo")
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
;; OPTIN-NEXT: (drop
;; OPTIN-NEXT: (local.get $x)
;; OPTIN-NEXT: )
;; OPTIN-NEXT: )
(func $local.get.internalized-string
(local $x anyref)
;; A null can be propagated.
(drop
(local.get $x)
)
;; A non-null value, like an internalized string, is not optimized (we could
;; emit an any.convert_extern of a strong.const, but it increases size, so
;; we leave this for passes like Precompute and GUFA).
;; TODO: should we optimize this?
(local.set $x
(any.convert_extern
(string.const "foo")
)
)
(drop
(local.get $x)
)
)
)