summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/dae-gc-refine-params.wast56
-rw-r--r--test/lit/passes/dae-gc.wast161
-rw-r--r--test/lit/passes/dae_all-features.wast112
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)
+ )
+ )
+)