(module (global $global$0 (mut i32) (i32.const 1)) (func $basics (param $x i32) (local $y i32) (local $z f32) (local $w i64) (local $t f64) (drop (local.get $x)) ;; keep as param get (drop (local.get $y)) ;; turn into get of 0-init (drop (local.get $z)) (drop (local.get $w)) (drop (local.get $t)) (local.set $x (i32.const 100)) ;; overwrite param (drop (local.get $x)) ;; no longer a param! (local.set $t (f64.const 2)) ;; overwrite local (drop (local.get $t)) (local.set $t (f64.const 33)) ;; overwrite local AGAIN (drop (local.get $t)) (drop (local.get $t)) ;; use twice ) (func $if (param $p i32) (local $x i32) (local $y i32) (drop (if i32 (i32.const 1) (local.get $x) (local.get $y) ) ) (if (i32.const 1) (local.set $x (i32.const 1)) ) (drop (local.get $x)) ;; same but with param (if (i32.const 1) (local.set $p (i32.const 1)) ) (drop (local.get $p)) ;; if-else (if (i32.const 1) (local.set $x (i32.const 2)) (nop) ) (drop (local.get $x)) (if (i32.const 1) (nop) (local.set $x (i32.const 3)) ) (drop (local.get $x)) (if (i32.const 1) (local.set $x (i32.const 4)) (local.set $x (i32.const 5)) ) (drop (local.get $x)) (if (i32.const 1) (local.set $x (i32.const 6)) (block (local.set $x (i32.const 7)) (local.set $x (i32.const 8)) ) ) (drop (local.get $x)) ) (func $if2 (param $x i32) (if (i32.const 1) (block (local.set $x (i32.const 1)) (drop (local.get $x)) ;; use between phi set and use ) ) (drop (local.get $x)) ) (func $block (param $x i32) (block $out (br_if $out (i32.const 2)) (local.set $x (i32.const 1)) ) (drop (local.get $x)) ) (func $block2 (param $x i32) (block $out (local.set $x (i32.const 1)) (drop (local.get $x)) (br_if $out (i32.const 2)) (drop (local.get $x)) (if (i32.const 3) (block (local.set $x (i32.const 1)) (drop (local.get $x)) (br $out) ) ) (drop (local.get $x)) (local.set $x (i32.const 4)) (drop (local.get $x)) (if (i32.const 5) (br $out) ) (drop (local.get $x)) (if (i32.const 6) (nop) ) (if (i32.const 7) (nop) (nop) ) ;; finally, switching (block $in (local.set $x (i32.const 8)) (drop (local.get $x)) (br_table $in $out (i32.const 9)) ) (drop (local.get $x)) (block $in2 (local.set $x (i32.const 10)) (drop (local.get $x)) (br_table $out $in2 (i32.const 11)) ) (drop (local.get $x)) ) (drop (local.get $x)) ) (func $loop (param $x i32) (drop (local.get $x)) (loop $moar (drop (local.get $x)) (local.set $x (i32.const 1)) (br_if $moar (i32.const 2)) ) (drop (local.get $x)) ) (func $loop2 (param $x i32) (drop (local.get $x)) (loop $moar (drop (local.get $x)) (local.set $x (i32.const 1)) (drop (local.get $x)) (local.set $x (i32.const 123)) (drop (local.get $x)) (br_if $moar (i32.const 2)) (drop (local.get $x)) ;; add use in loop before it ends, we should update this to the phi (local.set $x (i32.const 3)) (drop (local.get $x)) ;; another use, but should *not* be phi'd ) (drop (local.get $x)) ) (func $loop2-zeroinit (local $x i32) (drop (local.get $x)) (loop $moar (drop (local.get $x)) (local.set $x (i32.const 1)) (drop (local.get $x)) (local.set $x (i32.const 123)) (drop (local.get $x)) (br_if $moar (i32.const 2)) (drop (local.get $x)) ;; add use in loop before it ends, we should update this to the phi (local.set $x (i32.const 3)) (drop (local.get $x)) ;; another use, but should *not* be phi'd ) (drop (local.get $x)) ) (func $real-loop (param $param i32) (local $loopvar i32) (local $inc i32) (local.set $loopvar (local.get $param) ) (loop $more (block $stop (if (i32.const 1) (br $stop) ) (local.set $inc (i32.add (local.get $loopvar) ;; this var should be written to from before the loop and the inc at the end (i32.const 1) ) ) (local.set $loopvar (local.get $inc) ) (br $more) ) ) (drop (local.get $loopvar)) ) (func $real-loop-outblock (param $param i32) (local $loopvar i32) (local $inc i32) (local.set $loopvar (local.get $param) ) (block $stop (loop $more (if (i32.const 1) (br $stop) ) (local.set $inc (i32.add (local.get $loopvar) ;; this var should be written to from before the loop and the inc at the end (i32.const 1) ) ) (local.set $loopvar (local.get $inc) ) (br $more) ) ) (drop (local.get $loopvar)) ) (func $loop-loop-param (param $param i32) (loop $loop1 (block $out1 (if (local.get $param) (br $out1) ) (local.set $param (i32.const 1)) (br $loop1) ) ) (loop $loop2 (block $out2 (if (local.get $param) (br $out2) ) (local.set $param (i32.const 2)) (br $loop2) ) ) ) (func $loop-loop-param-nomerge (param $param i32) (loop $loop1 (block $out1 (local.set $param (i32.const 1)) (if (local.get $param) (br $out1) ) (br $loop1) ) ) (loop $loop2 (block $out2 (if (local.get $param) (br $out2) ) (local.set $param (i32.const 2)) (br $loop2) ) ) ) (func $loop-nesting (param $x i32) (block $out (loop $loop1 (if (local.get $x) (br $out) ) (loop $loop2 (if (local.get $x) (br $out) ) (local.set $x (i32.const 1)) (br $loop2) ) (local.set $x (i32.const 2)) (br $loop1) ) ) (drop (local.get $x)) ;; can receive from either set, or input param ) (func $loop-nesting-2 (param $x i32) (block $out (loop $loop1 (if (local.get $x) (br $out) ) (loop $loop2 (if (local.get $x) (br $out) ) (local.set $x (i32.const 1)) (br_if $loop2 (i32.const 3)) ;; add fallthrough ) (local.set $x (i32.const 2)) (br $loop1) ) ) (drop (local.get $x)) ;; can receive from either set, or input param ) (func $func_6 (result i32) (local $result i32) (local $zero i32) (loop $label$1 (if (i32.eqz (global.get $global$0) ) (return (local.get $result) ;; we eventually reach here ) ) (global.set $global$0 (i32.const 0) ;; tell next iteration to return ) (local.set $result (i32.const 1) ;; set the return value to 1, temporarily ) (br_if $label$1 (i32.const 0) ;; don't do anything here ) (local.set $result (local.get $zero) ;; set it to zero instead ) (br $label$1) ;; back to the top, where we will return the zero ) ) (func $ssa-merge-tricky (result i32) (local $var$0 i32) (local $var$1 i32) (local.set $var$1 (local.tee $var$0 (i32.const 0) ;; both vars start out identical ) ) (loop $label$1 (if (i32.eqz (global.get $global$0) ) (return (i32.const 12345) ) ) (global.set $global$0 (i32.const 0) ) (if (i32.eqz (local.get $var$0) ;; check $0 here. this will get a phi var ) (br_if $label$1 (i32.eqz (local.tee $var$0 ;; set $0 to 1. here the two diverge. for the phi, we'll get a set here and above (i32.const 1) ) ) ) ) (br_if $label$1 (i32.eqz ;; indeed equal, enter loop again, and then hang prevention kicks in (local.tee $var$1 ;; set them all to 0 (local.tee $var$0 (local.get $var$1) ;; this must get $1, not the phis, as even though the sets appear in both sources, we only execute 1. ) ) ) ) ) (i32.const -54) ) )