diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/dae-gc-refine-params.wast | 56 | ||||
-rw-r--r-- | test/lit/passes/dae-gc.wast | 161 | ||||
-rw-r--r-- | test/lit/passes/dae_all-features.wast | 112 |
3 files changed, 314 insertions, 15 deletions
diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast index e7059b0e0..767c2d716 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -27,34 +27,36 @@ ;; CHECK: (func $call-various-params-no ;; CHECK-NEXT: (call $various-params-no - ;; CHECK-NEXT: (ref.null ${}) - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (call $get_{}) + ;; CHECK-NEXT: (call $get_{i32}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $various-params-no - ;; CHECK-NEXT: (ref.null ${i32}) - ;; CHECK-NEXT: (ref.null ${f64}) + ;; CHECK-NEXT: (call $get_{i32}) + ;; CHECK-NEXT: (call $get_{f64}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $call-various-params-no (type $none_=>_none) ;; NOMNL-NEXT: (call $various-params-no - ;; NOMNL-NEXT: (ref.null ${}) - ;; NOMNL-NEXT: (ref.null ${i32}) + ;; NOMNL-NEXT: (call $get_{}) + ;; NOMNL-NEXT: (call $get_{i32}) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $various-params-no - ;; NOMNL-NEXT: (ref.null ${i32}) - ;; NOMNL-NEXT: (ref.null ${f64}) + ;; NOMNL-NEXT: (call $get_{i32}) + ;; NOMNL-NEXT: (call $get_{f64}) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $call-various-params-no ;; The first argument gets {} and {i32}; the second {i32} and {f64}; none of - ;; those pairs can be optimized. + ;; those pairs can be optimized. Note that we do not pass in all nulls, as + ;; all nulls are identical and we could do other optimization work due to + ;; that. (call $various-params-no - (ref.null ${}) - (ref.null ${i32}) + (call $get_{}) + (call $get_{i32}) ) (call $various-params-no - (ref.null ${i32}) - (ref.null ${f64}) + (call $get_{i32}) + (call $get_{f64}) ) ) ;; This function is called in ways that do not allow us to alter the types of @@ -81,6 +83,34 @@ (drop (local.get $y)) ) + ;; CHECK: (func $get_{} (result (ref null ${})) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $get_{} (type $none_=>_ref?|${}|) (result (ref null ${})) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + (func $get_{} (result (ref null ${})) + (unreachable) + ) + ;; CHECK: (func $get_{i32} (result (ref null ${i32})) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $get_{i32} (type $none_=>_ref?|${i32}|) (result (ref null ${i32})) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + (func $get_{i32} (result (ref null ${i32})) + (unreachable) + ) + ;; CHECK: (func $get_{f64} (result (ref null ${f64})) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $get_{f64} (type $none_=>_ref?|${f64}|) (result (ref null ${f64})) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + (func $get_{f64} (result (ref null ${f64})) + (unreachable) + ) + ;; CHECK: (func $call-various-params-yes ;; CHECK-NEXT: (call $various-params-yes ;; CHECK-NEXT: (call $get_null_{i32}) diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index bcf177f74..1d12150eb 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -1,6 +1,6 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. -;; RUN: wasm-opt %s -all --dae -S -o - | filecheck %s -;; RUN: wasm-opt %s -all --dae --nominal -S -o - | filecheck %s --check-prefix=NOMNL +;; RUN: foreach %s %t wasm-opt -all --dae -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt -all --dae --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type ${} (struct )) @@ -96,3 +96,160 @@ ) ) ) + +;; Test ref.func and ref.null optimization of constant parameter values. +(module + ;; CHECK: (func $foo (param $0 (ref $none_=>_none)) + ;; CHECK-NEXT: (local $1 (ref null $none_=>_none)) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (ref.func $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $foo (type $ref|none_->_none|_=>_none) (param $0 (ref $none_=>_none)) + ;; NOMNL-NEXT: (local $1 (ref null $none_=>_none)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.func $a) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $foo (param $x (ref func)) (param $y (ref func)) + ;; "Use" the params to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $call-foo + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (ref.func $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (ref.func $c) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $call-foo (type $none_=>_none) + ;; NOMNL-NEXT: (call $foo + ;; NOMNL-NEXT: (ref.func $b) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $foo + ;; NOMNL-NEXT: (ref.func $c) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $call-foo + ;; Call $foo with a constant function in the first param, which we + ;; can optimize, but different ones in the second. + (call $foo + (ref.func $a) + (ref.func $b) + ) + (call $foo + (ref.func $a) + (ref.func $c) + ) + ) + + ;; CHECK: (func $bar (param $0 (ref null $none_=>_none)) + ;; CHECK-NEXT: (local $1 anyref) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $bar (type $ref?|none_->_none|_=>_none) (param $0 (ref null $none_=>_none)) + ;; NOMNL-NEXT: (local $1 anyref) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.null func) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $bar (param $x (ref null any)) (param $y (ref null any)) + ;; "Use" the params to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $call-bar + ;; CHECK-NEXT: (call $bar + ;; CHECK-NEXT: (ref.null $none_=>_none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $bar + ;; CHECK-NEXT: (ref.func $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $call-bar (type $none_=>_none) + ;; NOMNL-NEXT: (call $bar + ;; NOMNL-NEXT: (ref.null $none_=>_none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $bar + ;; NOMNL-NEXT: (ref.func $a) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $call-bar + ;; Call with nulls. Mixing nulls is fine as they all have the same value, and + ;; we can optimize. However, mixing a null with a reference stops us in the + ;; second param. + (call $bar + (ref.null func) + (ref.null func) + ) + (call $bar + (ref.null any) + (ref.func $a) + ) + ) + + ;; Helper functions so we have something to take the reference of. + ;; CHECK: (func $a + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $a (type $none_=>_none) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + (func $a) + ;; CHECK: (func $b + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $b (type $none_=>_none) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + (func $b) + ;; CHECK: (func $c + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $c (type $none_=>_none) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + (func $c) +) diff --git a/test/lit/passes/dae_all-features.wast b/test/lit/passes/dae_all-features.wast index 42a47eb68..41655d849 100644 --- a/test/lit/passes/dae_all-features.wast +++ b/test/lit/passes/dae_all-features.wast @@ -538,3 +538,115 @@ ) ) ) + +;; Arguments that read an immutable global can be optimized, as that is a +;; constant value. +(module + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $i32_=>_none (func (param i32))) + + ;; CHECK: (type $i32_i32_=>_none (func (param i32 i32))) + + ;; CHECK: (global $immut i32 (i32.const 42)) + (global $immut i32 (i32.const 42)) + + ;; CHECK: (global $immut2 i32 (i32.const 43)) + (global $immut2 i32 (i32.const 43)) + + ;; CHECK: (global $mut (mut i32) (i32.const 1337)) + (global $mut (mut i32) (i32.const 1337)) + + ;; CHECK: (func $foo (param $0 i32) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (global.get $immut) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $foo (param $x i32) (param $y i32) + ;; "Use" the params to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $foo-caller + ;; CHECK-NEXT: (global.set $mut + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (global.get $mut) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $mut + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (global.get $mut) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $foo-caller + ;; Note how the mutable param has a different value in each call, which shows + ;; the reason that we cannot optimize in this case. But we can optimize the + ;; immutable param. + (global.set $mut (i32.const 1)) + (call $foo + (global.get $immut) + (global.get $mut) + ) + (global.set $mut (i32.const 2)) + (call $foo + (global.get $immut) + (global.get $mut) + ) + ) + + ;; CHECK: (func $bar (param $x i32) (param $y i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $bar (param $x i32) (param $y i32) + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $bar-caller + ;; CHECK-NEXT: (global.set $mut + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $bar + ;; CHECK-NEXT: (global.get $immut) + ;; CHECK-NEXT: (global.get $immut) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $mut + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $bar + ;; CHECK-NEXT: (global.get $mut) + ;; CHECK-NEXT: (global.get $immut2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $bar-caller + ;; Corner cases of mixing mutable with immutable and mixing two immutables. + (global.set $mut (i32.const 1)) + (call $bar + (global.get $immut) + (global.get $immut) + ) + (global.set $mut (i32.const 2)) + (call $bar + (global.get $mut) + (global.get $immut2) + ) + ) +) |