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