| ;; 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 |
| (memory 10) |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (type $none_=>_i32 (func (result i32))) |
| |
| ;; CHECK: (type $4 (func (param i32))) |
| |
| ;; CHECK: (type $FUNCSIG$iii (func (param i32 i32) (result i32))) |
| |
| ;; CHECK: (type $f64_i32_=>_i64 (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))) |
| (import $_emscripten_autodebug_i32 "env" "_emscripten_autodebug_i32" (param i32 i32) (result i32)) |
| (import $get "env" "get" (result i32)) |
| (import $set "env" "set" (param i32)) |
| ;; CHECK: (type $i32_=>_i32 (func (param i32) (result i32))) |
| |
| ;; CHECK: (type $i32_i32_=>_none (func (param i32 i32))) |
| |
| ;; CHECK: (type $none_=>_f64 (func (result f64))) |
| |
| ;; CHECK: (import "env" "_emscripten_autodebug_i32" (func $_emscripten_autodebug_i32 (param i32 i32) (result i32))) |
| |
| ;; CHECK: (import "env" "get" (func $get (result i32))) |
| |
| ;; CHECK: (import "env" "set" (func $set (param i32))) |
| |
| ;; 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: (drop |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $if-else (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (i32.const 0) |
| (drop |
| (local.get $x) |
| ) |
| (drop |
| (local.get $y) |
| ) |
| ) |
| ) |
| ;; CHECK: (func $if-else-parallel |
| ;; CHECK-NEXT: (local $0 i32) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; 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: (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: ) |
| (func $if-else-parallel (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (i32.const 0) |
| (block $block1 |
| (local.set $x |
| (i32.const 0) |
| ) |
| (drop |
| (local.get $x) |
| ) |
| ) |
| (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: (local.set $0 |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; 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 $if-else-after (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (i32.const 0) |
| (local.set $x |
| (i32.const 0) |
| ) |
| (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: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 2) |
| ;; 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) |
| (drop |
| (i32.const 1) |
| ) |
| (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: (drop |
| ;; 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 $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) |
| (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: (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 $if-through2 (type $2) |
| (local $x i32) |
| (local $y i32) |
| (local.set $x |
| (i32.const 0) |
| ) |
| (if |
| (i32.const 0) |
| (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: (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: ) |
| (func $if-through3 (type $2) |
| (local $x i32) |
| (local $y i32) |
| (local.set $x |
| (i32.const 1) |
| ) |
| (if |
| (i32.const 0) |
| (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: (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: ) |
| (func $if2 (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (local.tee $x |
| (i32.const 1) |
| ) |
| (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: (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: (drop |
| ;; CHECK-NEXT: (local.get $1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $if3 (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (i32.const 0) |
| (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: (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: (drop |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $if4 (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (i32.const 0) |
| (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: (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: (drop |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $if5 (type $2) |
| (local $x i32) |
| (local $y i32) |
| (if |
| (i32.const 0) |
| (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: (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: (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) |
| (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: (if |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 2) |
| ;; 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: (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: (if |
| ;; CHECK-NEXT: (i32.const 3) |
| ;; 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: (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: (if |
| ;; CHECK-NEXT: (i32.const 4) |
| ;; 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: (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: ) |
| (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) |
| (if |
| (i32.const 1) |
| (if |
| (i32.const 2) |
| (block $block3 |
| (local.set $x1 |
| (i32.const 100) |
| ) |
| (local.set $y2 |
| (i32.const 101) |
| ) |
| (drop |
| (local.get $x1) |
| ) |
| (drop |
| (local.get $y2) |
| ) |
| ) |
| (block $block5 |
| (local.set $x1 |
| (i32.const 102) |
| ) |
| (local.set $y3 |
| (i32.const 103) |
| ) |
| (drop |
| (local.get $x1) |
| ) |
| (drop |
| (local.get $y3) |
| ) |
| ) |
| ) |
| (if |
| (i32.const 3) |
| (block $block8 |
| (local.set $x2 |
| (i32.const 104) |
| ) |
| (local.set $y1 |
| (i32.const 105) |
| ) |
| (drop |
| (local.get $x2) |
| ) |
| (drop |
| (local.get $y1) |
| ) |
| ) |
| (block $block10 |
| (local.set $x2 |
| (i32.const 106) |
| ) |
| (local.set $y3 |
| (i32.const 107) |
| ) |
| (drop |
| (local.get $x2) |
| ) |
| (drop |
| (local.get $y3) |
| ) |
| ) |
| ) |
| ) |
| (if |
| (i32.const 4) |
| (block $block13 |
| (local.set $x3 |
| (i32.const 108) |
| ) |
| (local.set $y1 |
| (i32.const 109) |
| ) |
| (drop |
| (local.get $x3) |
| ) |
| (drop |
| (local.get $y1) |
| ) |
| ) |
| (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: (if |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 2) |
| ;; 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: (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: (if |
| ;; CHECK-NEXT: (i32.const 3) |
| ;; 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: (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: (if |
| ;; CHECK-NEXT: (i32.const 4) |
| ;; 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: (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: ) |
| (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) |
| (if |
| (i32.const 1) |
| (if |
| (i32.const 2) |
| (block $block3 |
| (local.set $x1 |
| (i32.const 100) |
| ) |
| (local.set $y2 |
| (i32.const 101) |
| ) |
| (drop |
| (local.get $x1) |
| ) |
| (drop |
| (local.get $y2) |
| ) |
| ) |
| (block $block5 |
| (local.set $x1 |
| (i32.const 102) |
| ) |
| (local.set $y3 |
| (i32.const 103) |
| ) |
| (drop |
| (local.get $x1) |
| ) |
| (drop |
| (local.get $y3) |
| ) |
| ) |
| ) |
| (if |
| (i32.const 3) |
| (block $block8 |
| (local.set $x2 |
| (i32.const 104) |
| ) |
| (local.set $y1 |
| (i32.const 105) |
| ) |
| (drop |
| (local.get $x2) |
| ) |
| (drop |
| (local.get $y1) |
| ) |
| ) |
| (block $block10 |
| (local.set $x2 |
| (i32.const 106) |
| ) |
| (local.set $y3 |
| (i32.const 107) |
| ) |
| (drop |
| (local.get $x2) |
| ) |
| (drop |
| (local.get $y3) |
| ) |
| ) |
| ) |
| ) |
| (if |
| (i32.const 4) |
| (block $block13 |
| (local.set $x3 |
| (i32.const 108) |
| ) |
| (local.set $y1 |
| (i32.const 109) |
| ) |
| (drop |
| (local.get $x3) |
| ) |
| (drop |
| (local.get $y1) |
| ) |
| ) |
| (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: (drop |
| ;; CHECK-NEXT: (local.get $0) |
| ;; 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: (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: (br $while-out$0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (block $block4 |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.eqz |
| ;; CHECK-NEXT: (local.get $2) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (return |
| ;; CHECK-NEXT: (local.get $3) |
| ;; 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: (br $while-out$2) |
| ;; 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: (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: (br $while-out$4) |
| ;; 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) |
| ) |
| (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) |
| ) |
| ) |
| (block $block2 |
| (block $while-out$0 |
| (loop $while-in$1 |
| (if |
| (i32.eqz |
| (i32.and |
| (local.get $i1) |
| (i32.const 3) |
| ) |
| ) |
| (br $while-out$0) |
| ) |
| (block $block4 |
| (if |
| (i32.eqz |
| (local.get $i3) |
| ) |
| (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) |
| ) |
| ) |
| (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) |
| ) |
| ) |
| (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: (block $block1 |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $0 |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (nop) |
| ;; 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) |
| (block $block1 |
| (if |
| (i32.const 0) |
| (nop) |
| ) |
| (local.set $x |
| (i32.const 1) |
| ) |
| ) |
| (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: (local.set $1 |
| ;; CHECK-NEXT: (local.get $0) |
| ;; 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) |
| (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: (local.get $0) |
| ;; CHECK-NEXT: (local.get $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: (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) |
| (local.get $x) |
| (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: (local.get $0) |
| ;; CHECK-NEXT: (local.get $1) |
| ;; 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) |
| (local.get $y) |
| (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: (unreachable) |
| ;; CHECK-NEXT: (local.get $0) |
| ;; 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) |
| (unreachable) |
| (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: (unreachable) |
| ;; CHECK-NEXT: (local.get $0) |
| ;; 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) |
| (unreachable) |
| (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: (local.get $0) |
| ;; 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: (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) |
| (local.get $x) |
| (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: (nop) |
| ;; 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) |
| (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: (local.get $0) |
| ;; CHECK-NEXT: (unreachable) |
| ;; 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) |
| (local.get $0) |
| (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: (unreachable) |
| ;; CHECK-NEXT: (local.get $0) |
| ;; 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) |
| (unreachable) |
| (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: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; 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) |
| (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: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; 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) |
| (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: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; 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: (drop |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; 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) |
| (local.set $y (i32.const 1)) |
| ) |
| (local.set $x (local.get $z)) |
| (if (i32.const 1) |
| (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) |
| (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: (local.set $1 |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (local.set $1 |
| ;; CHECK-NEXT: (local.get $0) |
| ;; 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) |
| (local.set $3 |
| (local.get $1) |
| ) |
| (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: (nop) |
| ;; CHECK-NEXT: (nop) |
| ;; 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) |
| (local.set $1 |
| (local.get $0) |
| ) |
| (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) |
| ) |
| ) |
| ) |