;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. ;; RUN: foreach %s %t wasm-opt --coalesce-locals -S -o - | filecheck %s (module ;; CHECK: (type $2 (func)) ;; CHECK: (type $1 (func (result i32))) ;; CHECK: (type $4 (func (param i32))) ;; CHECK: (type $FUNCSIG$iii (func (param i32 i32) (result i32))) ;; CHECK: (type $4 (func (param f64 i32) (result i64))) ;; CHECK: (type $3 (func (param i32 f32))) ;; CHECK: (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) (type $2 (func)) (type $3 (func (param i32 f32))) (type $4 (func (param i32))) ;; CHECK: (type $7 (func (param i32) (result i32))) ;; CHECK: (type $8 (func (param i32 i32))) ;; CHECK: (type $9 (func (result f64))) ;; CHECK: (import "env" "_emscripten_autodebug_i32" (func $_emscripten_autodebug_i32 (param i32 i32) (result i32))) (import "env" "_emscripten_autodebug_i32" (func $_emscripten_autodebug_i32 (param i32 i32) (result i32))) ;; CHECK: (import "env" "get" (func $get (result i32))) (import "env" "get" (func $get (result i32))) ;; CHECK: (import "env" "set" (func $set (param i32))) (import "env" "set" (func $set (param i32))) (memory 10) ;; CHECK: (memory $0 10) ;; CHECK: (func $nothing-to-do ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $nothing-to-do (type $2) (local $x i32) (nop) ) ;; CHECK: (func $merge ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $merge (type $2) (local $x i32) (local $y i32) (nop) ) ;; CHECK: (func $leave-type ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 f32) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $leave-type (type $2) (local $x i32) (local $y f32) (nop) ) ;; CHECK: (func $leave-interfere ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $leave-interfere (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (local.set $y (i32.const 1) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $almost-interfere ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $almost-interfere (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (drop (local.get $x) ) (local.set $y (i32.const 0) ) (drop (local.get $y) ) ) ;; CHECK: (func $redundant-copy ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $redundant-copy (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (local.set $y (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $ineffective-store ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $ineffective-store (type $2) (local $x i32) (local.set $x (i32.const 0) ) (local.set $x (i32.const 0) ) (drop (local.get $x) ) ) ;; CHECK: (func $block ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $block0 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $block (type $2) (local $x i32) (block $block0 (local.set $x (i32.const 0) ) ) (drop (local.get $x) ) ) ;; CHECK: (func $see-both-sides ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $block0 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $see-both-sides (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (block $block0 (local.set $y (i32.const 1) ) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $see-br-and-ignore-dead ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (br $block) ;; 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: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $see-br-and-ignore-dead (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (block $block (br $block) (local.set $y (i32.const 0) ) (drop (local.get $y) ) (local.set $x (i32.const -1) ) ) (drop (local.get $x) ) ) ;; CHECK: (func $see-block-body ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $block) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $see-block-body (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (block $block (local.set $y (i32.const 1) ) (drop (local.get $y) ) (br $block) ) (drop (local.get $x) ) ) ;; CHECK: (func $zero-init ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $zero-init (type $2) (local $x i32) (local $y i32) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $multi ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $multi (type $2) (local $x i32) (local $y i32) (local $z i32) (drop (local.get $y) ) (drop (local.get $z) ) ) ;; CHECK: (func $if-else ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-else (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (drop (local.get $x) ) ) (else (drop (local.get $y) ) ) ) ) ;; CHECK: (func $if-else-parallel ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block3 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-else-parallel (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (block $block1 (local.set $x (i32.const 0) ) (drop (local.get $x) ) ) ) (else (block $block3 (local.set $y (i32.const 1) ) (drop (local.get $y) ) ) ) ) ) ;; CHECK: (func $if-else-after ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-else-after (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (local.set $x (i32.const 0) ) ) (else (local.set $y (i32.const 1) ) ) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $if-else-through ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; 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 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-else-through (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (local.set $y (i32.const 1) ) (if (i32.const 0) (then (drop (i32.const 1) ) ) (else (drop (i32.const 2) ) ) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $if-through ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-through (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (local.set $y (i32.const 1) ) (if (i32.const 0) (then (drop (i32.const 1) ) ) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $if-through2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-through2 (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 0) ) (if (i32.const 0) (then (local.set $y (i32.const 1) ) ) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $if-through3 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-through3 (type $2) (local $x i32) (local $y i32) (local.set $x (i32.const 1) ) (if (i32.const 0) (then (block $block1 (drop (local.get $x) ) (drop (local.get $y) ) ) ) ) ) ;; CHECK: (func $if2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.tee $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if2 (type $2) (local $x i32) (local $y i32) (if (local.tee $x (i32.const 1) ) (then (block $block1 (drop (local.get $x) ) (drop (local.get $y) ) ) ) ) ) ;; CHECK: (func $if3 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if3 (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (block $block1 (local.set $x (i32.const 0) ) (drop (local.get $x) ) ) ) ) (drop (local.get $y) ) ) ;; CHECK: (func $if4 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if4 (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (block $block1 (local.set $x (i32.const 0) ) (drop (local.get $x) ) (local.set $y (i32.const 1) ) ) ) ) (drop (local.get $y) ) ) ;; CHECK: (func $if5 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if5 (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (block $block1 ;; These locals can be coalesced together: $x's live range ends here, ;; and $y's begins right after it, so they do not have an overlap with ;; a different value. (drop (local.get $x) ) (local.set $y (i32.const 1) ) ) ) ) (drop (local.get $y) ) ) ;; CHECK: (func $if5-flip ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if5-flip (type $2) (local $x i32) (local $y i32) (if (i32.const 0) (then (block $block1 ;; As above, but flipping these two instructions causes a conflict. (local.set $y (i32.const 1) ) (drop (local.get $x) ) ) ) ) (drop (local.get $y) ) ) ;; CHECK: (func $loop ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (loop $in ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $in) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $loop (type $2) (local $x i32) (local $y i32) (loop $in (drop (local.get $x) ) (local.set $x (i32.const 0) ) (drop (local.get $y) ) (br $in) ) ) ;; CHECK: (func $interfere-in-dead ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (br $block) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $interfere-in-dead (type $2) (local $x i32) (local $y i32) (block $block (br $block) (drop (local.get $x) ) (drop (local.get $y) ) ) ) ;; CHECK: (func $interfere-in-dead2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $interfere-in-dead2 (type $2) (local $x i32) (local $y i32) (block $block (unreachable) (drop (local.get $x) ) (drop (local.get $y) ) ) ) ;; CHECK: (func $interfere-in-dead3 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (return) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $interfere-in-dead3 (type $2) (local $x i32) (local $y i32) (block $block (return) (drop (local.get $x) ) (drop (local.get $y) ) ) ) ;; CHECK: (func $params (param $0 i32) (param $1 f32) ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $params (type $3) (param $p i32) (param $q f32) (local $x i32) (local $y i32) (local $z i32) (local $w i32) (drop (local.get $y) ) (drop (local.get $z) ) (drop (local.get $w) ) ) ;; CHECK: (func $interfere-in-dead4 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (br_if $block ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $interfere-in-dead4 (type $2) (local $x i32) (local $y i32) (block $block (br_if $block (i32.const 0) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ) ;; CHECK: (func $switch ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $switch$def ;; CHECK-NEXT: (block $switch-case$1 ;; CHECK-NEXT: (block $switch-case$2 ;; CHECK-NEXT: (br_table $switch-case$1 $switch-case$2 $switch-case$1 $switch-case$1 $switch$def ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $switch (type $2) (local $x i32) (local $y i32) (local $z i32) (local $w i32) (block $switch$def (block $switch-case$1 (block $switch-case$2 (br_table $switch-case$1 $switch-case$2 $switch-case$1 $switch-case$1 $switch$def (i32.const 100) ) (drop (local.get $x) ) ) (drop (local.get $y) ) ) (drop (local.get $z) ) ) (drop (local.get $w) ) ) ;; CHECK: (func $greedy-can-be-happy ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block3 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 101) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block5 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 102) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 103) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block8 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 104) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 105) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block10 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 106) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 107) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block13 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 108) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 109) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block15 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 110) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 111) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $greedy-can-be-happy (type $2) (local $x1 i32) (local $x2 i32) (local $x3 i32) (local $y1 i32) (local $y2 i32) (local $y3 i32) (if (i32.const 0) (then (if (i32.const 1) (then (if (i32.const 2) (then (block $block3 (local.set $x1 (i32.const 100) ) (local.set $y2 (i32.const 101) ) (drop (local.get $x1) ) (drop (local.get $y2) ) ) ) (else (block $block5 (local.set $x1 (i32.const 102) ) (local.set $y3 (i32.const 103) ) (drop (local.get $x1) ) (drop (local.get $y3) ) ) ) ) ) (else (if (i32.const 3) (then (block $block8 (local.set $x2 (i32.const 104) ) (local.set $y1 (i32.const 105) ) (drop (local.get $x2) ) (drop (local.get $y1) ) ) ) (else (block $block10 (local.set $x2 (i32.const 106) ) (local.set $y3 (i32.const 107) ) (drop (local.get $x2) ) (drop (local.get $y3) ) ) ) ) ) ) ) (else (if (i32.const 4) (then (block $block13 (local.set $x3 (i32.const 108) ) (local.set $y1 (i32.const 109) ) (drop (local.get $x3) ) (drop (local.get $y1) ) ) ) (else (block $block15 (local.set $x3 (i32.const 110) ) (local.set $y2 (i32.const 111) ) (drop (local.get $x3) ) (drop (local.get $y2) ) ) ) ) ) ) ) ;; CHECK: (func $greedy-can-be-sad ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block3 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 101) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block5 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 102) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 103) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block8 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 104) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 105) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block10 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 106) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 107) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block13 ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 108) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 109) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (block $block15 ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 110) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 111) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $greedy-can-be-sad (type $2) (local $x1 i32) (local $y1 i32) (local $x2 i32) (local $y2 i32) (local $x3 i32) (local $y3 i32) (if (i32.const 0) (then (if (i32.const 1) (then (if (i32.const 2) (then (block $block3 (local.set $x1 (i32.const 100) ) (local.set $y2 (i32.const 101) ) (drop (local.get $x1) ) (drop (local.get $y2) ) ) ) (else (block $block5 (local.set $x1 (i32.const 102) ) (local.set $y3 (i32.const 103) ) (drop (local.get $x1) ) (drop (local.get $y3) ) ) ) ) ) (else (if (i32.const 3) (then (block $block8 (local.set $x2 (i32.const 104) ) (local.set $y1 (i32.const 105) ) (drop (local.get $x2) ) (drop (local.get $y1) ) ) ) (else (block $block10 (local.set $x2 (i32.const 106) ) (local.set $y3 (i32.const 107) ) (drop (local.get $x2) ) (drop (local.get $y3) ) ) ) ) ) ) ) (else (if (i32.const 4) (then (block $block13 (local.set $x3 (i32.const 108) ) (local.set $y1 (i32.const 109) ) (drop (local.get $x3) ) (drop (local.get $y1) ) ) ) (else (block $block15 (local.set $x3 (i32.const 110) ) (local.set $y2 (i32.const 111) ) (drop (local.get $x3) ) (drop (local.get $y2) ) ) ) ) ) ) ) ;; CHECK: (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32) ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.ge_s ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: (i32.const 4096) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eq ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block2 ;; CHECK-NEXT: (block $while-out$0 ;; CHECK-NEXT: (loop $while-in$1 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $while-out$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $block4 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.store8 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.load8_s ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $while-in$1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $while-out$2 ;; CHECK-NEXT: (loop $while-in$3 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (i32.ge_s ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $while-out$2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $block7 ;; CHECK-NEXT: (i32.store ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $while-in$3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $while-out$4 ;; CHECK-NEXT: (loop $while-in$5 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (i32.gt_s ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $while-out$4) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $block9 ;; CHECK-NEXT: (i32.store8 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.load8_s ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.sub ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $while-in$5) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $_memcpy (type $FUNCSIG$iiii) (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32) (local $i4 i32) (if (i32.ge_s (local.get $i3) (i32.const 4096) ) (then (drop (local.get $i1) ) ) ) (local.set $i4 (local.get $i1) ) (if (i32.eq (i32.and (local.get $i1) (i32.const 3) ) (i32.and (local.get $i2) (i32.const 3) ) ) (then (block $block2 (block $while-out$0 (loop $while-in$1 (if (i32.eqz (i32.and (local.get $i1) (i32.const 3) ) ) (then (br $while-out$0) ) ) (block $block4 (if (i32.eqz (local.get $i3) ) (then (return (local.get $i4) ) ) ) (i32.store8 (local.get $i1) (i32.load8_s (local.get $i2) ) ) (local.set $i1 (i32.add (local.get $i1) (i32.const 1) ) ) (local.set $i2 (i32.add (local.get $i2) (i32.const 1) ) ) (local.set $i3 (i32.sub (local.get $i3) (i32.const 1) ) ) ) (br $while-in$1) ) ) (block $while-out$2 (loop $while-in$3 (if (i32.eqz (i32.ge_s (local.get $i3) (i32.const 4) ) ) (then (br $while-out$2) ) ) (block $block7 (i32.store (local.get $i1) (i32.load (local.get $i2) ) ) (local.set $i1 (i32.add (local.get $i1) (i32.const 4) ) ) (local.set $i2 (i32.add (local.get $i2) (i32.const 4) ) ) (local.set $i3 (i32.sub (local.get $i3) (i32.const 4) ) ) ) (br $while-in$3) ) ) ) ) ) (block $while-out$4 (loop $while-in$5 (if (i32.eqz (i32.gt_s (local.get $i3) (i32.const 0) ) ) (then (br $while-out$4) ) ) (block $block9 (i32.store8 (local.get $i1) (i32.load8_s (local.get $i2) ) ) (local.set $i1 (i32.add (local.get $i1) (i32.const 1) ) ) (local.set $i2 (i32.add (local.get $i2) (i32.const 1) ) ) (local.set $i3 (i32.sub (local.get $i3) (i32.const 1) ) ) ) (br $while-in$5) ) ) (return (local.get $i4) ) ) ;; CHECK: (func $this-is-effective-i-tell-you (param $0 i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const -1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $block1 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $this-is-effective-i-tell-you (type $4) (param $x i32) (if (i32.const -1) (then (block $block1 (if (i32.const 0) (then (nop) ) ) (local.set $x (i32.const 1) ) ) ) (else (nop) ) ) (drop (local.get $x) ) ) ;; CHECK: (func $prefer-remove-copies1 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $prefer-remove-copies1 (type $2) (local $y i32) (local $z i32) (local $x i32) (local.set $x (i32.const 0) ) (local.set $y (local.get $x) ) (local.set $z (i32.const 1) ) (drop (local.get $y) ) (drop (local.get $z) ) ) ;; CHECK: (func $prefer-remove-copies2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $prefer-remove-copies2 (type $2) (local $y i32) (local $z i32) (local $x i32) (local.set $x (i32.const 0) ) (local.set $z (local.get $x) ) (local.set $y (i32.const 1) ) (drop (local.get $y) ) (drop (local.get $z) ) ) ;; CHECK: (func $in-unreachable ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $x ;; CHECK-NEXT: (return) ;; 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: ) ;; CHECK-NEXT: (block $y ;; CHECK-NEXT: (unreachable) ;; 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: ) ;; CHECK-NEXT: (block $z ;; CHECK-NEXT: (br $z) ;; 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: ) ;; CHECK-NEXT: (block $z14 ;; CHECK-NEXT: (br_table $z14 $z14 ;; CHECK-NEXT: (i32.const 100) ;; 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: ) ;; CHECK-NEXT: ) (func $in-unreachable (local $a i32) (block $x (return) (local.set $a (i32.const 1)) (drop (local.get $a)) (local.set $a (local.get $a)) ) (block $y (unreachable) (local.set $a (i32.const 1)) (drop (local.get $a)) (local.set $a (local.get $a)) ) (block $z (br $z) (local.set $a (i32.const 1)) (drop (local.get $a)) (local.set $a (local.get $a)) ) (block $z (br_table $z $z (i32.const 100) ) (local.set $a (i32.const 1)) (drop (local.get $a)) (local.set $a (local.get $a)) ) ) ;; CHECK: (func $nop-in-unreachable ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (i32.store ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $nop-in-unreachable (local $x i32) (block (unreachable) (i32.store (local.get $x) (local.tee $x (i32.const 0)) ) ) ) ;; CHECK: (func $loop-backedge ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $out ;; CHECK-NEXT: (loop $while-in7 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $set ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (call $get) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br_if $out ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (br $while-in7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $loop-backedge (local $0 i32) ;; loop phi (local $1 i32) ;; value for next loop iteration (local $2 i32) ;; a local that might be merged with with $1, perhaps making us prefer it to removing a backedge copy (local.set $0 (i32.const 2) ) (block $out (loop $while-in7 (local.set $2 (i32.const 0)) ;; 2 interferes with 0 (call $set (local.get $2)) (local.set $1 (i32.add (local.get $0) (i32.const 1) ) ) (if (call $get) (then (local.set $2 (local.get $1)) ;; copy for 1/2 ) ) (br_if $out (local.get $2)) (local.set $1 (i32.const 100)) (local.set $0 (local.get $1)) ;; copy for 1/0, with extra weight should win the tie (br $while-in7) ) ) ) ;; CHECK: (func $if-copy1 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (loop $top ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $top) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-copy1 (local $x i32) (local $y i32) (loop $top (local.set $x (if (result i32) (i32.const 1) (then (local.get $x) ) (else (local.get $y) ) ) ) (drop (local.get $x)) (drop (local.get $y)) (br $top) ) ) ;; CHECK: (func $if-copy2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (loop $top ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $top) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-copy2 (local $x i32) (local $y i32) (loop $top (local.set $x (if (result i32) (i32.const 1) (then (local.get $y) ) (else (local.get $x) ) ) ) (drop (local.get $x)) (drop (local.get $y)) (br $top) ) ) ;; CHECK: (func $if-copy3 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (loop $top ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $top) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-copy3 (local $x i32) (local $y i32) (loop $top (local.set $x (if (result i32) (i32.const 1) (then (unreachable) ) (else (local.get $x) ) ) ) (drop (local.get $x)) (drop (local.get $y)) (br $top) ) ) ;; CHECK: (func $if-copy4 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (loop $top ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $top) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-copy4 (local $x i32) (local $y i32) (loop $top (local.set $x (if (result i32) (i32.const 1) (then (unreachable) ) (else (local.get $y) ) ) ) (drop (local.get $x)) (drop (local.get $y)) (br $top) ) ) ;; CHECK: (func $if-copy-tee ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (loop $top ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.tee $0 ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $top) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $if-copy-tee (local $x i32) (local $y i32) (loop $top (drop (local.tee $x (if (result i32) (i32.const 1) (then (local.get $x) ) (else (i32.const 2) ) ) ) ) (drop (local.get $x)) (drop (local.get $y)) (br $top) ) ) ;; CHECK: (func $tee_br (param $0 i32) (result i32) ;; CHECK-NEXT: (block $b ;; CHECK-NEXT: (return ;; CHECK-NEXT: (br $b) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) (func $tee_br (param $x i32) (result i32) (block $b (return (local.tee $x (br $b) ) ) ) (i32.const 1) ) ;; CHECK: (func $unused-tee-with-child-if-no-else (param $0 i32) ;; CHECK-NEXT: (loop $label$0 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (if ;; CHECK-NEXT: (br $label$0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $unused-tee-with-child-if-no-else (param $0 i32) (loop $label$0 (drop (local.tee $0 (if (br $label$0) (then (nop) ) ) ) ) ) ) ;; CHECK: (func $tee_if_with_unreachable_else (param $0 f64) (param $1 i32) (result i64) ;; CHECK-NEXT: (call $tee_if_with_unreachable_else ;; CHECK-NEXT: (local.tee $0 ;; CHECK-NEXT: (if (result f64) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.lt ;; CHECK-NEXT: (f64.const -128) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $tee_if_with_unreachable_else (param $0 f64) (param $1 i32) (result i64) (call $tee_if_with_unreachable_else (local.tee $0 (if (result f64) (local.get $1) (then (local.get $0) ) (else (unreachable) ) ) ) (f64.lt (f64.const -128) (local.get $0) ) ) ) ;; CHECK: (func $tee_if_with_unreachable_true (param $0 f64) (param $1 i32) (result i64) ;; CHECK-NEXT: (call $tee_if_with_unreachable_else ;; CHECK-NEXT: (local.tee $0 ;; CHECK-NEXT: (if (result f64) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.lt ;; CHECK-NEXT: (f64.const -128) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $tee_if_with_unreachable_true (param $0 f64) (param $1 i32) (result i64) (call $tee_if_with_unreachable_else (local.tee $0 (if (result f64) (local.get $1) (then (unreachable) ) (else (local.get $0) ) ) ) (f64.lt (f64.const -128) (local.get $0) ) ) ) ;; CHECK: (func $pick ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (nop) ;; 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: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $pick (local $x i32) (local $y i32) (local.set $x (local.get $y)) (if (i32.const 1) (then (local.set $x (i32.const 1)) ) ) (local.set $x (local.get $y)) (local.set $x (local.get $y)) ) ;; CHECK: (func $pick-2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (nop) ;; 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: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $pick-2 (local $x i32) (local $y i32) (local.set $y (local.get $x)) (if (i32.const 1) (then (local.set $y (i32.const 1)) ) ) (local.set $y (local.get $x)) (local.set $y (local.get $x)) ) ;; CHECK: (func $many ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; 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: ) ;; CHECK-NEXT: (nop) ;; 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: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; 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: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $many (local $x i32) (local $y i32) (local $z i32) (local $w i32) (local.set $y (local.get $x)) (local.set $z (local.get $y)) (local.set $w (local.get $z)) (local.set $x (local.get $z)) (if (i32.const 1) (then (local.set $y (i32.const 1)) ) ) (local.set $x (local.get $z)) (if (i32.const 1) (then (local.set $y (i32.const 1)) ) ) (local.set $y (local.get $x)) (local.set $z (local.get $y)) (local.set $w (local.get $z)) (local.set $z (i32.const 2)) (local.set $x (local.get $z)) (if (i32.const 1) (then (local.set $y (i32.const 1)) ) ) (local.set $y (local.get $x)) (local.set $z (local.get $y)) (local.set $w (local.get $z)) (local.set $z (i32.const 2)) (local.set $x (local.get $w)) ) ;; CHECK: (func $loop-copies (param $0 i32) (param $1 i32) ;; CHECK-NEXT: (loop $loop ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br_if $loop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $loop-copies (param $x i32) (param $y i32) (loop $loop (local.set $x (local.get $y)) (local.set $y (local.get $x)) (br_if $loop (local.get $x)) ) ) ;; CHECK: (func $proper-type (result f64) ;; CHECK-NEXT: (local $0 f64) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (select ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $proper-type (result f64) (local $var$0 i32) (local $var$2 f64) (local.set $var$0 (select (i32.const 0) (i32.const 1) (local.get $var$0) ) ) (local.tee $var$2 ;; the locals will be reordered, this should be the f64 (local.get $var$2) ) ) ;; CHECK: (func $reuse-param (param $0 i32) (param $1 i32) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.tee $0 ;; CHECK-NEXT: (i32.xor ;; CHECK-NEXT: (i32.shr_s ;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.shr_s ;; CHECK-NEXT: (i32.shl ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $reuse-param (param $x i32) (param $y i32) (result i32) (local $temp i32) (i32.add (local.tee $temp (i32.xor (i32.shr_s (i32.shl (local.get $x) ;; $x and $temp do not interfere (i32.const 16) ) (i32.const 16) ) (i32.shr_s (i32.shl (local.get $y) (i32.const 16) ) (i32.const 16) ) ) ) (local.get $temp) ) ) ;; CHECK: (func $copies-do-not-interfere (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $copies-do-not-interfere (result i32) (local $0 i32) (local $1 i32) (local.set $0 (i32.const 100) ) ;; The two locals are copies, and so they do not interfere, even though ;; their live ranges overlap and there is a set of one of them in that ;; overlap. We can coalesce them together to a single local. (local.set $1 (local.get $0) ) (drop (local.get $0) ) (local.get $1) ) ;; CHECK: (func $tee-copies-do-not-interfere (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $tee-copies-do-not-interfere (result i32) (local $0 i32) (local $1 i32) ;; Similar to the above, but now the copying is done using a tee. (local.set $1 (local.tee $0 (i32.const 100) ) ) (drop (local.get $0) ) (local.get $1) ) ;; CHECK: (func $multiple-tee-copies-do-not-interfere (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $multiple-tee-copies-do-not-interfere (result i32) (local $0 i32) (local $1 i32) (local $2 i32) ;; Similar to the above, but a chain of 3 items. (local.set $2 (local.tee $1 (local.tee $0 (i32.const 100) ) ) ) (drop (local.get $0) ) (drop (local.get $1) ) (local.get $2) ) ;; CHECK: (func $copies-and-then-interfere (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 123) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $copies-and-then-interfere (result i32) (local $0 i32) (local $1 i32) (local.set $0 (i32.const 100) ) (local.set $1 (local.get $0) ) (drop (local.get $0) ) (drop (local.get $1) ) ;; The copy before this set should not confuse us - this set causes a ;; divergence on the overlapping live ranges, and we cannot coalesce these ;; two locals. (local.set $1 (i32.const 123) ) (drop (local.get $0) ) (local.get $1) ) ;; CHECK: (func $copies-and-then-set-without-interfering (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 123) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $copies-and-then-set-without-interfering (result i32) (local $0 i32) (local $1 i32) (local.set $0 (i32.const 100) ) (local.set $1 (local.get $0) ) (drop (local.get $0) ) (drop (local.get $1) ) ;; Similar to the above, but now $0's live range has ended (there is no get ;; of it at the point of this set), and so there is no interference, and ;; these locals can be coalesced. (local.set $1 (i32.const 123) ) (local.get $1) ) ;; CHECK: (func $copy-third-party (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $copy-third-party (result i32) (local $0 i32) (local $1 i32) (local $2 i32) ;; $2 begins with a value, which is copied to $0 and $1. None of these ;; interfere and they can all be coalesced. (local.set $2 (i32.const 100) ) (local.set $1 (local.get $2) ) (local.set $0 (local.get $2) ) (drop (local.get $0) ) (drop (local.get $1) ) (local.get $2) ) ;; CHECK: (func $ineffective-set (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) (func $ineffective-set (result i32) (local $0 i32) (local $1 i32) (local $2 i32) (local.set $0 ;; This set of $2 is ineffective in that there are no gets of $2, but the ;; value does flow through to the outer set, and we must notice that. In ;; particular, we must see that $0 and $1 conflict, and cannot be coalesced ;; together ($1 is alive from the zero init to the very end, and so $0's ;; set means it diverges). (local.tee $2 (i32.const 100) ) ) (drop (local.get $0) ) (local.get $1) ) ;; CHECK: (func $inter-block-copy (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) (func $inter-block-copy (result i32) (local $0 i32) (local $1 i32) (local $2 i32) (local $3 i32) (local.set $0 (i32.const 100) ) (local.set $1 (local.get $0) ) (local.set $2 (local.get $0) ) ;; At this point $1 is equal to $2, as they are both copies of $0. Then the ;; if assigns one of them to $3, which means that $3 is also equal to them ;; all. However, we only analyze copied values *inside* blocks, which means ;; that in each of the if arms we see that $3 is assigned either the value ;; of $1 or $2, but we don't know that those values are both equal to $0. As ;; a result, we will infer that $3 interfers with $0, as their live ranges ;; overlap and $3 is assigned a value that looks different than $0. This ;; will prevent $3 being coalesced with all the others. (However, see the ;; next testcase for more on this.) (if (local.get $0) (then (local.set $3 (local.get $1) ) ) (else (local.set $3 (local.get $2) ) ) ) (drop (local.get $0) ) (drop (local.get $1) ) (drop (local.get $2) ) (local.get $3) ) ;; CHECK: (func $inter-block-copy-second-pass (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 100) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) (func $inter-block-copy-second-pass (result i32) (local $0 i32) (local $1 i32) ;; This function contains the output of the previous testcase ;; $inter-block-copy, and shows what running a second pass results in. After ;; the first pass we have coalesced the original $0, $1, and $2 into a single ;; local ($0), and renamed the original $3 into $1. At this point the ;; algorithm can see that $0 and $1 do not interfere: there are no copies in ;; the middle, and in both if arms when we assign a value to $1 it is the ;; value already in $0, and there is no other assignment of either one that ;; appears in their overlapping live ranges, so they will be coalesced into ;; a single local. (local.set $0 (i32.const 100) ) (nop) (nop) (if (local.get $0) (then (local.set $1 (local.get $0) ) ) (else (local.set $1 (local.get $0) ) ) ) (drop (local.get $0) ) (drop (local.get $0) ) (drop (local.get $0) ) (local.get $1) ) ;; CHECK: (func $equal-constants-zeroinit ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $equal-constants-zeroinit (local $x i32) (local $y i32) ;; $x and $y both have the zero init value, which is identical, and they do ;; not interfere. (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $equal-constants ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $equal-constants (local $x i32) (local $y i32) ;; $x is written the same value as $y, so they do not interfere. (local.set $x (i32.const 0) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $different-constants ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $different-constants (local $x i32) (local $y i32) ;; $x is written a different value, so they do interfere. (local.set $x (i32.const 1) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $equal-constants-nonzero ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $equal-constants-nonzero (local $x i32) (local $y i32) (local.set $x (i32.const 42) ) (local.set $y (i32.const 42) ) (drop (local.get $x) ) (drop (local.get $y) ) ) ;; CHECK: (func $different-constants-nonzero ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $different-constants-nonzero (local $x i32) (local $y i32) (local.set $x (i32.const 42) ) (local.set $y (i32.const 1337) ) (drop (local.get $x) ) (drop (local.get $y) ) ) )