| (module | |
| (memory 1) | |
| (global $glob (mut i32) (i32.const 1)) | |
| (global $glob-imm i32 (i32.const 1)) | |
| (func $loop1 | |
| (loop $loop | |
| (drop (i32.const 10)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop2 | |
| (loop $loop | |
| (drop (i32.const 10)) | |
| (drop (i32.const 20)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop3 | |
| (loop $loop | |
| (drop (i32.const 10)) | |
| (call $loop2) | |
| (drop (i32.const 20)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop4 | |
| (loop $loop | |
| (drop (i32.load (i32.const 1))) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop3-4 | |
| (loop $loop | |
| (drop (i32.load (i32.const 10))) | |
| (call $loop2) ;; may have global side effects which alter a load! | |
| (drop (i32.load (i32.const 20))) ;; this load must stay put | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop3-4-b (; 4 ;) | |
| (loop $loop | |
| (drop | |
| (i32.load | |
| (i32.const 10) | |
| ) | |
| ) | |
| (drop | |
| (i32.load | |
| (i32.const 20) | |
| ) | |
| ) | |
| (br_if $loop | |
| (i32.const 1) | |
| ) | |
| ) | |
| ) | |
| (func $loop5 | |
| (loop $loop | |
| (i32.store (i32.const 1) (i32.const 2)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop6 | |
| (loop $loop | |
| (i32.store (i32.const 1) (i32.const 2)) | |
| (i32.store (i32.const 2) (i32.const 3)) | |
| ) | |
| ) | |
| (func $loop7 | |
| (loop $loop | |
| (i32.store (i32.const 1) (i32.const 2)) | |
| (i32.store (i32.const 2) (i32.const 3)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop8 | |
| (loop $loop | |
| (i32.store (i32.const 1) (i32.const 2)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop9 | |
| (loop $loop | |
| (drop (i32.load (i32.const 1))) | |
| (i32.store (i32.const 1) (i32.const 2)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop10 | |
| (loop $loop | |
| (drop (i32.load (i32.const 1))) | |
| (drop (i32.load (i32.const 2))) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop11 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (drop (local.get $x)) | |
| (br_if $loop (local.tee $x (i32.const 2))) | |
| ) | |
| ) | |
| (func $loop12 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (drop (local.get $x)) | |
| (br_if $loop (local.tee $y (i32.const 2))) | |
| ) | |
| ) | |
| (func $loop13 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop14 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (br_if $loop (i32.const 1)) | |
| (local.set $y (local.get $x)) ;; not actually in the loop! | |
| ) | |
| ) | |
| (func $loop14-1 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (local.set $y (local.get $x)) ;; in the loop | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop15 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (br_if $loop (i32.const 1)) | |
| (drop (local.get $y)) | |
| ) | |
| ) | |
| (func $loop15-1 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (drop (local.get $y)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop16 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (br_if $loop (i32.const 1)) | |
| (drop (local.get $x)) | |
| ) | |
| ) | |
| (func $loop16-1 | |
| (local $x i32) | |
| (local $y i32) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (drop (local.get $x)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop16-2 | |
| (local $x i32) | |
| (local $y i32) | |
| (local.set $x (i32.const 2)) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (drop (local.get $x)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $loop16-3 | |
| (local $x i32) | |
| (local $y i32) | |
| (local.set $y (i32.const 2)) | |
| (loop $loop | |
| (local.set $x (i32.eqz (local.get $y))) | |
| (call $loop12) | |
| (drop (local.get $x)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $nop | |
| (loop $loop | |
| (nop) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $nested-blocks | |
| (loop $loop | |
| (block | |
| (nop) | |
| ) | |
| (block $x | |
| (nop) | |
| ) | |
| (block $a | |
| (block $b | |
| (block $c | |
| (nop) | |
| ) | |
| ) | |
| ) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $nested-unhoistable-blocks | |
| (loop $loop | |
| (block | |
| (call $nested-unhoistable-blocks) | |
| ) | |
| (block $x | |
| (call $nested-unhoistable-blocks) | |
| ) | |
| (block $a | |
| (block $b | |
| (block $c | |
| (call $nested-unhoistable-blocks) | |
| ) | |
| ) | |
| ) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $conditional | |
| (loop $loop | |
| (if (i32.const 0) | |
| (then | |
| (drop (i32.const 10)) ;; cannot be hoisted - might never be reached | |
| ) | |
| ) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $conditional1 (result i32) | |
| (loop $loop | |
| (if (call $conditional1) | |
| (then | |
| (drop (i32.const 10)) ;; cannot be hoisted - might never be reached | |
| ) | |
| ;; also anyhow the whole if also cannot, due to the call | |
| ) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| (unreachable) | |
| ) | |
| (func $conditional2 | |
| (block $out | |
| (loop $loop | |
| (br_if $out (i32.const 1)) | |
| (drop (i32.const 10)) ;; cannot be hoisted - might never be reached | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| ) | |
| (func $conditional3 | |
| (block $out | |
| (loop $loop | |
| (drop (i32.const 10)) ;; *CAN* be hoisted - will definitely be reached | |
| (br_if $out (i32.const 1)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| ) | |
| (func $after | |
| (loop $loop) | |
| (drop (i32.const 10)) ;; may be part of the loop's basic block, logically, but is not nested in it | |
| ) | |
| (func $loops | |
| (loop $loop2 | |
| (loop $loop1 | |
| (drop (i32.const 10)) | |
| (br_if $loop1 (i32.const 1)) | |
| ) | |
| ) | |
| ) | |
| (func $loops2 | |
| (loop $loop2 | |
| (loop $loop1 | |
| (drop (i32.const 10)) | |
| (br_if $loop2 (i32.const 1)) | |
| ) | |
| ) | |
| ) | |
| (func $fuzz1 (result i64) | |
| (local $var$1 i64) | |
| (loop $label$1 (result i64) ;; multiple loops here require us to be careful not to Nop out stuff before we finalize things | |
| (block $label$2 | |
| (block $label$3 | |
| (drop | |
| (loop $label$4 (result i32) | |
| (local.set $var$1 | |
| (block $label$5 (result i64) | |
| (local.set $var$1 | |
| (i64.const -29585) | |
| ) | |
| (i64.const -70) | |
| ) | |
| ) | |
| (i32.const 1) | |
| ) | |
| ) | |
| (br $label$2) | |
| ) | |
| (unreachable) | |
| ) | |
| (local.get $var$1) | |
| ) | |
| ) | |
| (func $self (result i32) | |
| (local $x i32) | |
| (loop $loop | |
| (local.set $x (i32.add (local.get $x) (i32.const 1))) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| (local.get $x) | |
| ) | |
| (func $nested-set | |
| (local $var$0 i32) | |
| (local $var$1 i64) | |
| (loop $label$1 | |
| (local.set $var$0 | |
| (block $label$3 (result i32) | |
| (local.set $var$1 ;; cannot be moved out (in current position - other opts would help), and invalidates moving out the set below | |
| (i64.const 0) | |
| ) | |
| (local.get $var$0) | |
| ) | |
| ) | |
| (local.set $var$1 | |
| (i64.const 1) | |
| ) | |
| (br_if $label$1 | |
| (i32.const 0) | |
| ) | |
| ) | |
| ) | |
| (func $load-store (param $x i32) | |
| (loop $loop | |
| (drop (i32.load (i32.const 0))) ;; can't move this out, the store might affect it for later iterations | |
| (i32.store (local.get $x) (local.get $x)) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $set-set (param $x i32) (result i32) | |
| (loop $loop | |
| (local.set $x (i32.const 1)) | |
| (br_if $loop (i32.const 2)) | |
| (local.set $x (i32.const 3)) | |
| (br_if $loop (i32.const 4)) | |
| ) | |
| (local.get $x) | |
| ) | |
| (func $copies-no | |
| (local $x i32) | |
| (local $y i32) | |
| (local $z i32) | |
| (local $a i32) | |
| (local $b i32) | |
| (local $c i32) | |
| (loop $loop | |
| (local.set $x (local.get $x)) | |
| (local.set $y (local.get $z)) | |
| (local.set $a (local.tee $b (local.get $c))) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $consts-no | |
| (local $x i32) | |
| (local $a i32) | |
| (local $b i32) | |
| (loop $loop | |
| (local.set $x (i32.const 0)) | |
| (local.set $a (local.tee $b (i32.const 1))) | |
| (br_if $loop (i32.const 1)) | |
| ) | |
| ) | |
| (func $global | |
| (local $x i32) | |
| (loop $loop | |
| ;; Moving this global.get out of the loop is ok. It is mutable, but there | |
| ;; is no possible place where it can be set in the loop. | |
| (local.set $x (global.get $glob)) | |
| (drop (local.get $x)) | |
| (br_if $loop (local.get $x)) | |
| ) | |
| ) | |
| (func $global-call | |
| (local $x i32) | |
| (loop $loop | |
| ;; As above, but now the loop does a call, which might in theory change | |
| ;; mutable global state, so we cannot optimize. | |
| (local.set $x (global.get $glob)) | |
| (call $global) | |
| (drop (local.get $x)) | |
| (br_if $loop (local.get $x)) | |
| ) | |
| ) | |
| (func $global-call-immutable | |
| (local $x i32) | |
| (loop $loop | |
| ;; As above, but now the global is immutable, so the call does not | |
| ;; prevent us from optimizing. | |
| (local.set $x (global.get $glob-imm)) | |
| (call $global) | |
| (drop (local.get $x)) | |
| (br_if $loop (local.get $x)) | |
| ) | |
| ) | |
| ) |