| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. |
| |
| ;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate --fuzz-exec -all -S -o - \ |
| ;; RUN: | filecheck %s |
| |
| (module |
| ;; CHECK: (global $g (mut i32) (i32.const 10)) |
| (global $g (mut i32) (i32.const 10)) |
| |
| ;; CHECK: (func $loop (type $1) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (local.set $temp |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $loop |
| (local $temp i32) |
| ;; We should not try to precompute this loop. If we attempted to replace it |
| ;; with its children, we'd need to handle the effects of chidren properly, |
| ;; which we do not do in this pass. |
| (loop |
| (local.set $temp |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $local.set (type $1) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (local.set $temp |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $temp |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $local.set |
| (local $temp i32) |
| ;; We should not try to precompute a set or tee. |
| (local.set $temp |
| (i32.const 10) |
| ) |
| (drop |
| (local.tee $temp |
| (i32.const 20) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $global.set (type $1) |
| ;; CHECK-NEXT: (global.set $g |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $global.set |
| ;; We should not try to precompute a global set. |
| (global.set $g |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $binary-tee (type $0) (result i32) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $temp |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| (func $binary-tee (result i32) |
| (local $temp i32) |
| ;; We can precompute this and remove the add, but must keep the tee. |
| (i32.add |
| (local.tee $temp |
| (i32.const 10) |
| ) |
| (local.get $temp) |
| ) |
| ) |
| |
| ;; CHECK: (func $binary-tee-2 (type $0) (result i32) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $temp |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| (func $binary-tee-2 (result i32) |
| (local $temp i32) |
| ;; A tee on the other side. |
| (i32.add |
| (local.get $temp) |
| (local.tee $temp |
| (i32.const 10) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $binary-both (type $0) (result i32) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $temp |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (local.tee $temp |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 30) |
| ;; CHECK-NEXT: ) |
| (func $binary-both (result i32) |
| (local $temp i32) |
| ;; Now we must keep both tees. |
| (i32.add |
| (local.tee $temp |
| (i32.const 10) |
| ) |
| (local.tee $temp |
| (i32.const 20) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $nested-global (type $0) (result i32) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result i32) |
| ;; CHECK-NEXT: (local.set $temp |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result i32) |
| ;; CHECK-NEXT: (global.set $g |
| ;; CHECK-NEXT: (i32.const 30) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 40) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 60) |
| ;; CHECK-NEXT: ) |
| (func $nested-global (result i32) |
| (local $temp i32) |
| ;; Nested effects inside arms, and one is a global effect. |
| (i32.add |
| (block (result i32) |
| (local.set $temp |
| (i32.const 10) |
| ) |
| (i32.const 20) |
| ) |
| (block (result i32) |
| (global.set $g |
| (i32.const 30) |
| ) |
| (i32.const 40) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $if (type $0) (result i32) |
| ;; CHECK-NEXT: (i32.const 2) |
| ;; CHECK-NEXT: ) |
| (func $if (result i32) |
| ;; We precompute simple ifs. |
| (if (result i32) |
| (i32.const 1) |
| (then |
| (i32.const 2) |
| ) |
| (else |
| (i32.const 3) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $if-no (type $0) (result i32) |
| ;; CHECK-NEXT: (if (result i32) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: (then |
| ;; CHECK-NEXT: (global.set $g |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 2) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (else |
| ;; CHECK-NEXT: (i32.const 3) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $if-no (result i32) |
| ;; We do not precompute ifs with effects. |
| (if (result i32) |
| (i32.const 1) |
| (then |
| (block (result i32) |
| (global.set $g |
| (i32.const 20) |
| ) |
| (i32.const 2) |
| ) |
| ) |
| (else |
| (i32.const 3) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $try (type $0) (result i32) |
| ;; CHECK-NEXT: (try (result i32) |
| ;; CHECK-NEXT: (do |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (catch_all |
| ;; CHECK-NEXT: (i32.const 2) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $try (result i32) |
| ;; We don't precompute trys. |
| (try (result i32) |
| (do |
| (i32.const 1) |
| ) |
| (catch_all |
| (i32.const 2) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $ordering (type $0) (result i32) |
| ;; CHECK-NEXT: (local $temp i32) |
| ;; CHECK-NEXT: (block $out (result i32) |
| ;; CHECK-NEXT: (select |
| ;; CHECK-NEXT: (block (result i32) |
| ;; CHECK-NEXT: (local.set $temp |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (br $out |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (block (result i32) |
| ;; CHECK-NEXT: (global.set $g |
| ;; CHECK-NEXT: (i32.const 30) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 40) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $ordering (result i32) |
| (local $temp i32) |
| ;; Nested effects inside arms. The br in the middle arm will execute, so we |
| ;; want to precompute the entire select into a br, but we must keep alive the |
| ;; children before and after. While doing so, we must not *reorder* the middle |
| ;; child against them: if we just remove the middle child (and add a br at the |
| ;; end) then we are changing the order of execution, as the global.set would |
| ;; happen, when before it did not. For simplicity, we do not optimize here. |
| (block $out (result i32) |
| (select |
| (block (result i32) |
| (local.set $temp |
| (i32.const 0) |
| ) |
| (i32.const 20) |
| ) |
| (block (result i32) |
| (br $out |
| (i32.const 10) |
| ) |
| (i32.const 20) |
| ) |
| (block (result i32) |
| (global.set $g |
| (i32.const 30) |
| ) |
| (i32.const 40) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |