summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/lit/passes/gufa-vs-cfp.wast32
-rw-r--r--test/lit/passes/monomorphize.wast12
-rw-r--r--test/lit/passes/optimize-casts.wast3
-rw-r--r--test/lit/passes/optimize-instructions-call_ref-roundtrip.wast17
-rw-r--r--test/lit/passes/optimize-instructions-gc-tnh.wast4
-rw-r--r--test/lit/passes/precompute-gc-immutable.wast30
-rw-r--r--test/lit/passes/remove-unused-module-elements-refs.wast50
-rw-r--r--test/lit/passes/signature-pruning.wast124
-rw-r--r--test/lit/passes/signature-refining.wast156
-rw-r--r--test/lit/passes/signature-refining_gto.wat11
-rw-r--r--test/lit/passes/type-merging-tnh.wast23
-rw-r--r--test/lit/passes/type-refining.wast244
-rw-r--r--test/lit/passes/type-ssa_and_merging.wast18
13 files changed, 409 insertions, 315 deletions
diff --git a/test/lit/passes/gufa-vs-cfp.wast b/test/lit/passes/gufa-vs-cfp.wast
index 4c3d2e25c..73253aaa7 100644
--- a/test/lit/passes/gufa-vs-cfp.wast
+++ b/test/lit/passes/gufa-vs-cfp.wast
@@ -1,5 +1,7 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --nominal --remove-unused-names --gufa -all -S -o - | filecheck %s
+
+;; RUN: foreach %s %t wasm-opt --remove-unused-names --gufa -all -S -o - | filecheck %s
+
;; (remove-unused-names is added to test fallthrough values without a block
;; name getting in the way)
@@ -653,10 +655,10 @@
;; Subtyping: Create a subtype and get a supertype. The get must receive a
;; reference to the subtype and so we can infer the value of the get.
(module
- (type $substruct (struct_subtype i32 f64 $struct))
-
(type $struct (struct i32))
+ (type $substruct (struct_subtype i32 f64 $struct))
+
;; CHECK: (type $none_=>_none (func))
;; CHECK: (func $test (type $none_=>_none)
@@ -785,12 +787,11 @@
;; one value, so we can optimize.
(module
;; CHECK: (type $struct (struct (field i32)))
+ (type $struct (struct i32))
;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct))
(type $substruct (struct_subtype i32 f64 $struct))
- (type $struct (struct i32))
-
;; CHECK: (type $none_=>_i32 (func (result i32)))
;; CHECK: (type $none_=>_none (func))
@@ -2015,16 +2016,14 @@
;; apply to it, preventing optimization.
(module
;; CHECK: (type $A (struct (field (mut i32))))
+ (type $A (struct (mut i32)))
;; CHECK: (type $B (struct_subtype (field (mut i32)) $A))
+ (type $B (struct_subtype (mut i32) $A))
;; CHECK: (type $C (struct_subtype (field (mut i32)) $B))
(type $C (struct_subtype (mut i32) $B))
- (type $A (struct (mut i32)))
-
- (type $B (struct_subtype (mut i32) $A))
-
;; CHECK: (type $none_=>_none (func))
;; CHECK: (type $none_=>_ref|$C| (func (result (ref $C))))
@@ -2668,12 +2667,17 @@
;; Test we handle packed fields properly.
(module
- (type $A_8 (struct (field i8)))
- (type $A_16 (struct (field i16)))
- ;; CHECK: (type $B_16 (struct (field i16)))
- (type $B_16 (struct (field i16)))
+ (rec
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A_8 (struct (field i8)))
+ (type $A_8 (struct (field i8)))
+ ;; CHECK: (type $A_16 (struct (field i16)))
+ (type $A_16 (struct (field i16)))
+ ;; CHECK: (type $B_16 (struct (field i16)))
+ (type $B_16 (struct (field i16)))
+ )
;; CHECK: (import "a" "b" (global $g i32))
(import "a" "b" (global $g i32))
diff --git a/test/lit/passes/monomorphize.wast b/test/lit/passes/monomorphize.wast
index d171291e2..22326fb43 100644
--- a/test/lit/passes/monomorphize.wast
+++ b/test/lit/passes/monomorphize.wast
@@ -3,8 +3,8 @@
;; Test in both "always" mode, which always monomorphizes, and in "careful"
;; mode which does it only when it appears to actually help.
-;; RUN: foreach %s %t wasm-opt --nominal --monomorphize-always -all -S -o - | filecheck %s --check-prefix ALWAYS
-;; RUN: foreach %s %t wasm-opt --nominal --monomorphize -all -S -o - | filecheck %s --check-prefix CAREFUL
+;; RUN: foreach %s %t wasm-opt --monomorphize-always -all -S -o - | filecheck %s --check-prefix ALWAYS
+;; RUN: foreach %s %t wasm-opt --monomorphize -all -S -o - | filecheck %s --check-prefix CAREFUL
(module
;; ALWAYS: (type $A (struct ))
@@ -558,14 +558,14 @@
(module
;; Test that we avoid recursive calls.
- ;; ALWAYS: (type $ref|$A|_=>_none (func (param (ref $A))))
-
;; ALWAYS: (type $A (struct ))
- ;; CAREFUL: (type $ref|$A|_=>_none (func (param (ref $A))))
-
;; CAREFUL: (type $A (struct ))
(type $A (struct_subtype data))
+ ;; ALWAYS: (type $ref|$A|_=>_none (func (param (ref $A))))
+
;; ALWAYS: (type $B (struct_subtype $A))
+ ;; CAREFUL: (type $ref|$A|_=>_none (func (param (ref $A))))
+
;; CAREFUL: (type $B (struct_subtype $A))
(type $B (struct_subtype $A))
diff --git a/test/lit/passes/optimize-casts.wast b/test/lit/passes/optimize-casts.wast
index 6faca88d7..527c2d157 100644
--- a/test/lit/passes/optimize-casts.wast
+++ b/test/lit/passes/optimize-casts.wast
@@ -1,6 +1,5 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
-;; RUN: wasm-opt %s --optimize-casts -all --nominal -S -o - \
-;; RUN: | filecheck %s
+;; RUN: wasm-opt %s --optimize-casts -all -S -o - | filecheck %s
(module
;; CHECK: (type $A (struct ))
diff --git a/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast b/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast
index de4d0da6f..0e59d6df3 100644
--- a/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast
+++ b/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast
@@ -1,7 +1,7 @@
;; 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: wasm-opt %s --optimize-instructions --nominal --roundtrip --all-features -S -o - | filecheck %s
+;; RUN: wasm-opt %s --optimize-instructions --roundtrip --all-features -S -o - | filecheck %s
;; roundtrip to see the effects on heap types in the binary format, specifically
;; regarding nominal heap types
@@ -10,14 +10,17 @@
;; distinct nominally. The three tables will use different ones, and the
;; emitted call_indirects should use the corresponding ones.
- ;; CHECK: (type $v1 (func))
- (type $v1 (func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $v1 (func))
+ (type $v1 (func))
- ;; CHECK: (type $v2 (func))
- (type $v2 (func))
+ ;; CHECK: (type $v2 (func))
+ (type $v2 (func))
- ;; CHECK: (type $v3 (func))
- (type $v3 (func))
+ ;; CHECK: (type $v3 (func))
+ (type $v3 (func))
+ )
;; CHECK: (type $i32_=>_none (func (param i32)))
diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast
index 3c7494bac..11627d90c 100644
--- a/test/lit/passes/optimize-instructions-gc-tnh.wast
+++ b/test/lit/passes/optimize-instructions-gc-tnh.wast
@@ -1,6 +1,6 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
-;; RUN: wasm-opt %s --optimize-instructions --traps-never-happen -all --nominal -S -o - | filecheck %s --check-prefix TNH
-;; RUN: wasm-opt %s --optimize-instructions -all --nominal -S -o - | filecheck %s --check-prefix NO_TNH
+;; RUN: wasm-opt %s --optimize-instructions --traps-never-happen -all -S -o - | filecheck %s --check-prefix TNH
+;; RUN: wasm-opt %s --optimize-instructions -all -S -o - | filecheck %s --check-prefix NO_TNH
(module
;; TNH: (type $struct (struct (field (mut i32))))
diff --git a/test/lit/passes/precompute-gc-immutable.wast b/test/lit/passes/precompute-gc-immutable.wast
index 980276ebb..32e2d5719 100644
--- a/test/lit/passes/precompute-gc-immutable.wast
+++ b/test/lit/passes/precompute-gc-immutable.wast
@@ -1,6 +1,6 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
-;; RUN: foreach %s %t wasm-opt --precompute-propagate -all --nominal -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --precompute-propagate -all -S -o - | filecheck %s
(module
;; CHECK: (type $struct-imm (struct (field i32)))
@@ -410,10 +410,9 @@
;; Create an immutable vtable in an immutable field, which lets us read from
;; it.
- ;; CHECK: (type $object (struct (field (ref $vtable))))
-
;; CHECK: (type $vtable (struct (field funcref)))
(type $vtable (struct funcref))
+ ;; CHECK: (type $object (struct (field (ref $vtable))))
(type $object (struct (ref $vtable)))
;; CHECK: (func $nested-creations (type $none_=>_none)
@@ -458,10 +457,9 @@
(module
;; As above, but make $vtable not immutable, which prevents optimization.
- ;; CHECK: (type $object (struct (field (ref $vtable))))
-
;; CHECK: (type $vtable (struct (field (mut funcref))))
(type $vtable (struct (mut funcref)))
+ ;; CHECK: (type $object (struct (field (ref $vtable))))
(type $object (struct (ref $vtable)))
;; CHECK: (func $nested-creations (type $none_=>_none)
@@ -511,10 +509,9 @@
(module
;; As above, but make $object not immutable, which prevents optimization.
- ;; CHECK: (type $object (struct (field (mut (ref $vtable)))))
-
;; CHECK: (type $vtable (struct (field funcref)))
(type $vtable (struct funcref))
+ ;; CHECK: (type $object (struct (field (mut (ref $vtable)))))
(type $object (struct (mut (ref $vtable))))
;; CHECK: (func $nested-creations (type $none_=>_none)
@@ -739,17 +736,20 @@
;; data that is filled with vtables of different types. On usage, we do a
;; cast of the vtable type.
- ;; CHECK: (type $itable (array structref))
- (type $itable (array (ref null struct)))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $itable (array structref))
+ (type $itable (array (ref null struct)))
- ;; CHECK: (type $object (struct (field (ref $itable))))
- (type $object (struct (ref $itable)))
+ ;; CHECK: (type $object (struct (field (ref $itable))))
+ (type $object (struct (ref $itable)))
- ;; CHECK: (type $vtable-0 (struct (field funcref)))
- (type $vtable-0 (struct funcref))
+ ;; CHECK: (type $vtable-0 (struct (field funcref)))
+ (type $vtable-0 (struct funcref))
- ;; CHECK: (type $vtable-1 (struct (field funcref)))
- (type $vtable-1 (struct funcref))
+ ;; CHECK: (type $vtable-1 (struct (field funcref)))
+ (type $vtable-1 (struct funcref))
+ )
;; CHECK: (global $itable (ref $itable) (array.new_fixed $itable
;; CHECK-NEXT: (struct.new $vtable-0
diff --git a/test/lit/passes/remove-unused-module-elements-refs.wast b/test/lit/passes/remove-unused-module-elements-refs.wast
index 61ccb4daf..61315384d 100644
--- a/test/lit/passes/remove-unused-module-elements-refs.wast
+++ b/test/lit/passes/remove-unused-module-elements-refs.wast
@@ -1,33 +1,39 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --remove-unused-module-elements --closed-world --nominal -all -S -o - | filecheck %s
-;; RUN: foreach %s %t wasm-opt --remove-unused-module-elements --nominal -all -S -o - | filecheck %s --check-prefix OPEN_WORLD
+;; RUN: foreach %s %t wasm-opt --remove-unused-module-elements --closed-world -all -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --remove-unused-module-elements -all -S -o - | filecheck %s --check-prefix OPEN_WORLD
;; Test both open world (default) and closed world. In a closed world we can do
;; more with function refs, as we assume nothing calls them on the outside, so
;; if no calls exist to the right type, the function is not reached.
(module
- ;; CHECK: (type $A-super (func))
- ;; OPEN_WORLD: (type $A-super (func))
- (type $A-super (func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A-super (func))
+ ;; OPEN_WORLD: (rec
+ ;; OPEN_WORLD-NEXT: (type $A-super (func))
+ (type $A-super (func))
- ;; CHECK: (type $A (func_subtype $A-super))
- ;; OPEN_WORLD: (type $A (func_subtype $A-super))
- (type $A (func_subtype $A-super))
+ ;; CHECK: (type $A (func_subtype $A-super))
+ ;; OPEN_WORLD: (type $A (func_subtype $A-super))
+ (type $A (func_subtype $A-super))
- ;; CHECK: (type $A-sub (func_subtype $A))
- ;; OPEN_WORLD: (type $A-sub (func_subtype $A))
- (type $A-sub (func_subtype $A))
+ ;; CHECK: (type $A-sub (func_subtype $A))
+ ;; OPEN_WORLD: (type $A-sub (func_subtype $A))
+ (type $A-sub (func_subtype $A))
- ;; CHECK: (type $B (func))
- ;; OPEN_WORLD: (type $B (func))
- (type $B (func))
+ ;; CHECK: (type $B (func))
+ ;; OPEN_WORLD: (type $B (func))
+ (type $B (func))
+ )
+
+ ;; CHECK: (type $none_=>_none (func))
;; CHECK: (elem declare func $target-A $target-A-sub $target-A-super $target-B)
;; CHECK: (export "foo" (func $foo))
- ;; CHECK: (func $foo (type $A-super)
+ ;; CHECK: (func $foo (type $none_=>_none)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $target-A)
@@ -51,11 +57,13 @@
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; OPEN_WORLD: (type $none_=>_none (func))
+
;; OPEN_WORLD: (elem declare func $target-A $target-A-sub $target-A-super $target-B)
;; OPEN_WORLD: (export "foo" (func $foo))
- ;; OPEN_WORLD: (func $foo (type $A-super)
+ ;; OPEN_WORLD: (func $foo (type $none_=>_none)
;; OPEN_WORLD-NEXT: (local $A (ref null $A))
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (ref.func $target-A)
@@ -1161,11 +1169,13 @@
;; Cycles.
(module
(rec
- ;; CHECK: (type $vtable-func (func (param (ref $vtable))))
- ;; OPEN_WORLD: (type $vtable-func (func (param (ref $vtable))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $vtable-func (func (param (ref $vtable))))
+ ;; OPEN_WORLD: (rec
+ ;; OPEN_WORLD-NEXT: (type $vtable-func (func (param (ref $vtable))))
(type $vtable-func (func (param (ref $vtable))))
- ;; CHECK: (type $vtable (struct (field (ref $vtable-func)) (field (ref $vtable-func))))
- ;; OPEN_WORLD: (type $vtable (struct (field (ref $vtable-func)) (field (ref $vtable-func))))
+ ;; CHECK: (type $vtable (struct (field (ref $vtable-func)) (field (ref $vtable-func))))
+ ;; OPEN_WORLD: (type $vtable (struct (field (ref $vtable-func)) (field (ref $vtable-func))))
(type $vtable (struct_subtype (field (ref $vtable-func)) (field (ref $vtable-func)) data))
)
diff --git a/test/lit/passes/signature-pruning.wast b/test/lit/passes/signature-pruning.wast
index 76a2666ab..55010a250 100644
--- a/test/lit/passes/signature-pruning.wast
+++ b/test/lit/passes/signature-pruning.wast
@@ -1,14 +1,15 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --nominal --signature-pruning --closed-world -all -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --signature-pruning --closed-world -all -S -o - | filecheck %s
(module
- ;; CHECK: (type $sig (func (param i32 f64)))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param i32 f64)))
(type $sig (func_subtype (param i32) (param i64) (param f32) (param f64) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (elem declare func $foo)
@@ -67,13 +68,14 @@
)
(module
- ;; CHECK: (type $sig (func (param i64 f32)))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param i64 f32)))
(type $sig (func_subtype (param i32) (param i64) (param f32) (param f64) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (elem declare func $foo)
@@ -131,13 +133,14 @@
)
(module
- ;; CHECK: (type $sig (func (param i32 i64 f32)))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param i32 i64 f32)))
(type $sig (func_subtype (param i32) (param i64) (param f32) (param f64) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (elem declare func $foo)
@@ -207,13 +210,14 @@
;; As above, but with the effects on a call_ref. Once more, we can only optimize
;; away the very last param.
(module
- ;; CHECK: (type $sig (func (param i32 i64 f32)))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param i32 i64 f32)))
(type $sig (func_subtype (param i32) (param i64) (param f32) (param f64) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (elem declare func $foo)
@@ -277,13 +281,14 @@
)
(module
- ;; CHECK: (type $sig (func))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func))
(type $sig (func_subtype (param i32) (param i64) (param f32) (param f64) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (elem declare func $foo)
@@ -323,13 +328,14 @@
)
(module
- ;; CHECK: (type $sig (func))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func))
(type $sig (func_subtype (param i32) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (func $foo (type $sig)
@@ -437,11 +443,15 @@
)
(module
- ;; CHECK: (type $sig (func))
- (type $sig (func_subtype (param i32) func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $sig2 (func (param i32)))
- ;; CHECK: (type $sig2 (func (param i32)))
- (type $sig2 (func_subtype (param i32) func))
+ ;; CHECK: (type $sig (func))
+ (type $sig (func_subtype (param i32) func))
+
+ (type $sig2 (func_subtype (param i32) func))
+ )
(memory 1 1)
@@ -471,13 +481,14 @@
)
(module
- ;; CHECK: (type $sig (func))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func))
(type $sig (func_subtype (param i32) func))
(memory 1 1)
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (memory $0 1 1)
;; CHECK: (elem declare func $bar $foo)
@@ -600,10 +611,14 @@
;; *not* have the same type, however: the type should be different nominally
;; even though after the pruning they are identical structurally.
(module
- ;; CHECK: (type $sig1 (func))
- (type $sig1 (func_subtype (param i32) func))
- ;; CHECK: (type $sig2 (func))
- (type $sig2 (func_subtype (param f64) func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $sig2 (func))
+
+ ;; CHECK: (type $sig1 (func))
+ (type $sig1 (func_subtype (param i32) func))
+ (type $sig2 (func_subtype (param f64) func))
+ )
;; CHECK: (func $foo1 (type $sig1)
;; CHECK-NEXT: (local $0 i32)
@@ -621,10 +636,14 @@
)
(module
- ;; CHECK: (type $sig-foo (func))
- (type $sig-foo (func_subtype (param i32) func))
- ;; CHECK: (type $sig-bar (func (param i32)))
- (type $sig-bar (func_subtype (param i32) func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $sig-bar (func (param i32)))
+
+ ;; CHECK: (type $sig-foo (func))
+ (type $sig-foo (func_subtype (param i32) func))
+ (type $sig-bar (func_subtype (param i32) func))
+ )
(memory 1 1)
@@ -685,10 +704,14 @@
;; value that we can optimize in the case of $foo (but not $bar, again, as $bar
;; is not always sent a constant value).
(module
- ;; CHECK: (type $sig-foo (func))
- (type $sig-foo (func_subtype (param funcref) func))
- ;; CHECK: (type $sig-bar (func (param funcref)))
- (type $sig-bar (func_subtype (param funcref) func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $sig-bar (func (param funcref)))
+
+ ;; CHECK: (type $sig-foo (func))
+ (type $sig-foo (func_subtype (param funcref) func))
+ (type $sig-bar (func_subtype (param funcref) func))
+ )
(memory 1 1)
@@ -737,10 +760,14 @@
;; As above, but the values are now ref.nulls.
(module
- ;; CHECK: (type $sig-foo (func))
- (type $sig-foo (func_subtype (param anyref) func))
- ;; CHECK: (type $sig-bar (func (param anyref)))
- (type $sig-bar (func_subtype (param anyref) func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $sig-bar (func (param anyref)))
+
+ ;; CHECK: (type $sig-foo (func))
+ (type $sig-foo (func_subtype (param anyref) func))
+ (type $sig-bar (func_subtype (param anyref) func))
+ )
(memory 1 1)
@@ -855,23 +882,20 @@
;; relationship. Atm we do not prune such "cycles" so we do not optimize here.
;; TODO
(module
- ;; CHECK: (type $array.A (array (ref $struct.A)))
-
- ;; CHECK: (type $array.B (array_subtype (ref $struct.B) $array.A))
-
- ;; CHECK: (type $func.A (func (param (ref $array.B)) (result (ref $array.A))))
-
- ;; CHECK: (type $func.B (func_subtype (param (ref $array.A)) (result (ref $array.B)) $func.A))
-
;; CHECK: (type $struct.A (struct (field i32)))
(type $struct.A (struct (field i32)))
+ ;; CHECK: (type $array.A (array (ref $struct.A)))
+
;; CHECK: (type $struct.B (struct_subtype (field i32) (field i64) $struct.A))
(type $struct.B (struct_subtype (field i32) (field i64) $struct.A))
(type $array.A (array (ref $struct.A)))
+ ;; CHECK: (type $array.B (array_subtype (ref $struct.B) $array.A))
(type $array.B (array_subtype (ref $struct.B) $array.A))
+ ;; CHECK: (type $func.A (func (param (ref $array.B)) (result (ref $array.A))))
(type $func.A (func (param (ref $array.B)) (result (ref $array.A))))
+ ;; CHECK: (type $func.B (func_subtype (param (ref $array.A)) (result (ref $array.B)) $func.A))
(type $func.B (func_subtype (param (ref $array.A)) (result (ref $array.B)) $func.A))
;; CHECK: (func $func.A (type $func.A) (param $0 (ref $array.B)) (result (ref $array.A))
diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast
index d8da19a64..dea74451a 100644
--- a/test/lit/passes/signature-refining.wast
+++ b/test/lit/passes/signature-refining.wast
@@ -1,5 +1,5 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --nominal --signature-refining -all -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --signature-refining -all -S -o - | filecheck %s
(module
;; $func is defined with an anyref parameter but always called with a $struct,
@@ -7,13 +7,14 @@
;; heap type's definition as well as the types of the parameters as printed
;; on the function (which are derived from the heap type).
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
(type $struct (struct))
- ;; CHECK: (type $sig (func (param (ref $struct))))
- (type $sig (func_subtype (param anyref) func))
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $sig (func (param (ref $struct))))
+ (type $sig (func_subtype (param anyref) func))
;; CHECK: (func $func (type $sig) (param $x (ref $struct))
;; CHECK-NEXT: (nop)
@@ -36,14 +37,14 @@
(module
;; As above, but the call is via call_ref.
- ;; CHECK: (type $sig (func (param (ref $struct))))
-
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
(type $struct (struct))
- (type $sig (func_subtype (param anyref) func))
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $sig (func (param (ref $struct))))
+ (type $sig (func_subtype (param anyref) func))
;; CHECK: (elem declare func $func)
@@ -72,13 +73,13 @@
;; call uses a nullable $struct, the other a non-nullable i31, so the LUB
;; is a nullable eqref.
- ;; CHECK: (type $sig (func (param eqref)))
-
- ;; CHECK: (type $none_=>_none (func))
-
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
(type $struct (struct))
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param eqref)))
(type $sig (func_subtype (param anyref) func))
;; CHECK: (elem declare func $func)
@@ -118,20 +119,25 @@
;; Multiple functions with the same heap type. Again, the LUB is in the
;; middle, this time the parent $struct and not a subtype.
- ;; CHECK: (type $sig (func (param (ref $struct))))
- (type $sig (func_subtype (param anyref) func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $struct-sub2 (struct_subtype $struct))
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (type $struct-sub1 (struct_subtype $struct))
- ;; CHECK: (type $struct-sub1 (struct_subtype $struct))
- (type $struct-sub1 (struct_subtype $struct))
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $struct-sub2 (struct_subtype $struct))
- (type $struct-sub2 (struct_subtype $struct))
+ ;; CHECK: (type $sig (func (param (ref $struct))))
+ (type $sig (func_subtype (param anyref) func))
- (type $struct (struct))
+ (type $struct (struct))
+
+ (type $struct-sub1 (struct_subtype $struct))
+
+ (type $struct-sub2 (struct_subtype $struct))
+ )
;; CHECK: (func $func-1 (type $sig) (param $x (ref $struct))
;; CHECK-NEXT: (nop)
@@ -167,14 +173,16 @@
;; As above, but now only one of the functions is called. The other is still
;; updated, though, as they share a heap type.
- ;; CHECK: (type $sig (func (param (ref $struct))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
+
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param (ref $struct))))
(type $sig (func_subtype (param anyref) func))
- ;; CHECK: (type $struct (struct ))
(type $struct (struct))
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (func $func-1 (type $sig) (param $x (ref $struct))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
@@ -203,14 +211,16 @@
;; Define a field in the struct of the signature type that will be updated,
;; to check for proper validation after the update.
- ;; CHECK: (type $sig (func (param (ref $struct) (ref $sig))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (ref $sig))))
+
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param (ref $struct) (ref $sig))))
(type $sig (func_subtype (param anyref funcref) func))
- ;; CHECK: (type $struct (struct (field (ref $sig))))
(type $struct (struct_subtype (field (ref $sig)) data))
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (elem declare func $func)
;; CHECK: (func $func (type $sig) (param $x (ref $struct)) (param $f (ref $sig))
@@ -266,14 +276,14 @@
;; An unreachable value does not prevent optimization: we will update the
;; param to be $struct.
- ;; CHECK: (type $sig (func (param (ref $struct))))
-
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
(type $struct (struct))
- (type $sig (func_subtype (param anyref) func))
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $sig (func (param (ref $struct))))
+ (type $sig (func_subtype (param anyref) func))
;; CHECK: (elem declare func $func)
@@ -354,16 +364,19 @@
(module
;; Test multiple fields in multiple types.
- ;; CHECK: (type $struct (struct ))
- (type $struct (struct))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
+ (type $struct (struct))
- ;; CHECK: (type $sig-2 (func (param eqref (ref $struct))))
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $sig-1 (func (param structref anyref)))
- (type $sig-1 (func_subtype (param anyref) (param anyref) func))
- (type $sig-2 (func_subtype (param anyref) (param anyref) func))
+ ;; CHECK: (type $sig-2 (func (param eqref (ref $struct))))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $sig-1 (func (param structref anyref)))
+ (type $sig-1 (func_subtype (param anyref) (param anyref) func))
+ (type $sig-2 (func_subtype (param anyref) (param anyref) func))
+ )
;; CHECK: (elem declare func $func-2)
@@ -463,15 +476,16 @@
;; Pass a null in one call to the function. The null can be updated which
;; allows us to refine (but the new type must be nullable).
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
- ;; CHECK: (type $sig (func (param (ref null $struct))))
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (type $sig (func (param (ref null $struct))))
(type $sig (func_subtype (param anyref) func))
(type $struct (struct))
- ;; CHECK: (type $none_=>_none (func))
-
;; CHECK: (func $func (type $sig) (param $x (ref null $struct))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
@@ -497,23 +511,28 @@
)
(module
- ;; CHECK: (type $struct (struct ))
- (type $struct (struct))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $none_=>_none (func))
- ;; This signature has a single function using it, which returns a more
- ;; refined type, and we can refine to that.
- ;; CHECK: (type $sig-can-refine (func (result (ref $struct))))
- (type $sig-can-refine (func_subtype (result anyref) func))
+ ;; CHECK: (type $sig-unreachable (func (result anyref)))
- ;; Also a single function, but no refinement is possible.
- ;; CHECK: (type $sig-cannot-refine (func (result (ref func))))
- (type $sig-cannot-refine (func_subtype (result (ref func)) func))
+ ;; CHECK: (type $sig-cannot-refine (func (result (ref func))))
- ;; The single function never returns, so no refinement is possible.
- ;; CHECK: (type $sig-unreachable (func (result anyref)))
- (type $sig-unreachable (func_subtype (result anyref) func))
+ ;; CHECK: (type $struct (struct ))
+ (type $struct (struct))
- ;; CHECK: (type $none_=>_none (func))
+ ;; This signature has a single function using it, which returns a more
+ ;; refined type, and we can refine to that.
+ ;; CHECK: (type $sig-can-refine (func (result (ref $struct))))
+ (type $sig-can-refine (func_subtype (result anyref) func))
+
+ ;; Also a single function, but no refinement is possible.
+ (type $sig-cannot-refine (func_subtype (result (ref func)) func))
+
+ ;; The single function never returns, so no refinement is possible.
+ (type $sig-unreachable (func_subtype (result anyref) func))
+ )
;; CHECK: (elem declare func $func-can-refine $func-cannot-refine)
@@ -589,13 +608,13 @@
)
(module
- ;; CHECK: (type $sig (func (result (ref null $struct))))
-
- ;; CHECK: (type $struct (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct ))
(type $struct (struct))
;; This signature has multiple functions using it, and some of them have nulls
;; which should be updated when we refine.
+ ;; CHECK: (type $sig (func (result (ref null $struct))))
(type $sig (func_subtype (result anyref) func))
;; CHECK: (func $func-1 (type $sig) (result (ref null $struct))
@@ -689,11 +708,11 @@
)
(module
- ;; CHECK: (type $ref|${}|_i32_=>_none (func (param (ref ${}) i32)))
-
;; CHECK: (type ${} (struct ))
(type ${} (struct))
+ ;; CHECK: (type $ref|${}|_i32_=>_none (func (param (ref ${}) i32)))
+
;; CHECK: (func $foo (type $ref|${}|_i32_=>_none) (param $ref (ref ${})) (param $i32 i32)
;; CHECK-NEXT: (local $2 eqref)
;; CHECK-NEXT: (local.set $2
@@ -763,9 +782,10 @@
;; skip such optimizations. TODO
(module
(rec
- ;; CHECK: (type $A (func (param (ref null $B)) (result (ref null $A))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (func (param (ref null $B)) (result (ref null $A))))
(type $A (func (param (ref null $B)) (result (ref null $A))))
- ;; CHECK: (type $B (func_subtype (param (ref null $A)) (result (ref null $B)) $A))
+ ;; CHECK: (type $B (func_subtype (param (ref null $A)) (result (ref null $B)) $A))
(type $B (func_subtype (param (ref null $A)) (result (ref null $B)) $A))
)
diff --git a/test/lit/passes/signature-refining_gto.wat b/test/lit/passes/signature-refining_gto.wat
index 8e034ef3e..0d0e4c22c 100644
--- a/test/lit/passes/signature-refining_gto.wat
+++ b/test/lit/passes/signature-refining_gto.wat
@@ -1,20 +1,17 @@
-;; RUN: foreach %s %t wasm-opt --closed-world --nominal --signature-refining --gto --roundtrip -all -S -o - | filecheck %s
-;; RUN: foreach %s %t wasm-opt --closed-world --signature-refining --gto --remove-unused-types --roundtrip -all -S -o - | filecheck %s --check-prefix ISOREC
+;; RUN: wasm-opt %s --closed-world --signature-refining --gto --remove-unused-types --roundtrip -all -S -o - | filecheck %s
;; Check that type $A is not included in the final binary after the signature
-;; refining optimization. For isorecursive types, this requires an additional
-;; --remove-unused-types pass after signature refining.
+;; refining optimization and an additional --remove-unused-types pass.
(module
;; The type $A should not be emitted at all (see below).
;; CHECK-NOT: (type $A
- ;; ISOREC-NOT: (type $A
(type $A (struct (field (mut (ref null $A)))))
- ;; CHECK: (type $ref|none|_=>_none (func (param (ref none))))
-
;; CHECK: (type $funcref_i32_=>_none (func (param funcref i32)))
+ ;; CHECK: (type $ref|none|_=>_none (func (param (ref none))))
+
;; CHECK: (func $struct.get (type $ref|none|_=>_none) (param $0 (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $0)
diff --git a/test/lit/passes/type-merging-tnh.wast b/test/lit/passes/type-merging-tnh.wast
index fefdb00e3..c84e31815 100644
--- a/test/lit/passes/type-merging-tnh.wast
+++ b/test/lit/passes/type-merging-tnh.wast
@@ -1,13 +1,14 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --nominal --closed-world -tnh --type-merging -all -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --closed-world -tnh --type-merging --remove-unused-types -all -S -o - | filecheck %s
;; ref.cast does not inhibit merging if traps never happen.
(module
- ;; CHECK: (type $A (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct ))
(type $A (struct))
(type $B (struct_subtype $A))
- ;; CHECK: (type $ref|$A|_=>_ref|$A| (func (param (ref $A)) (result (ref $A))))
+ ;; CHECK: (type $ref|$A|_=>_ref|$A| (func (param (ref $A)) (result (ref $A))))
;; CHECK: (func $test (type $ref|$A|_=>_ref|$A|) (param $a (ref $A)) (result (ref $A))
;; CHECK-NEXT: (ref.cast $A
@@ -23,13 +24,14 @@
;; Check that a ref.test still inhibits merging with -tnh.
(module
- ;; CHECK: (type $ref|$A|_=>_i32 (func (param (ref $A)) (result i32)))
-
- ;; CHECK: (type $A (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct ))
(type $A (struct))
- ;; CHECK: (type $B (struct_subtype $A))
+ ;; CHECK: (type $B (struct_subtype $A))
(type $B (struct_subtype $A))
+ ;; CHECK: (type $ref|$A|_=>_i32 (func (param (ref $A)) (result i32)))
+
;; CHECK: (func $test (type $ref|$A|_=>_i32) (param $a (ref $A)) (result i32)
;; CHECK-NEXT: (ref.test $B
;; CHECK-NEXT: (local.get $a)
@@ -44,12 +46,13 @@
;; Check that a br_on_cast still inhibits merging with -tnh.
(module
- ;; CHECK: (type $A (struct ))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct ))
(type $A (struct))
- ;; CHECK: (type $B (struct_subtype $A))
+ ;; CHECK: (type $B (struct_subtype $A))
(type $B (struct_subtype $A))
- ;; CHECK: (type $ref|$A|_=>_ref|$B| (func (param (ref $A)) (result (ref $B))))
+ ;; CHECK: (type $ref|$A|_=>_ref|$B| (func (param (ref $A)) (result (ref $B))))
;; CHECK: (func $test (type $ref|$A|_=>_ref|$B|) (param $a (ref $A)) (result (ref $B))
;; CHECK-NEXT: (block $__binaryen_fake_return (result (ref $B))
diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast
index 870e3d7cb..ca9b98590 100644
--- a/test/lit/passes/type-refining.wast
+++ b/test/lit/passes/type-refining.wast
@@ -1,14 +1,15 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --nominal --closed-world --type-refining -all -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --closed-world --type-refining -all -S -o - | filecheck %s
(module
;; A struct with three fields. The first will have no writes, the second one
;; write of the same type, and the last a write of a subtype, which will allow
;; us to specialize that one.
- ;; CHECK: (type $struct (struct (field (mut anyref)) (field (mut (ref i31))) (field (mut (ref i31)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut anyref)) (field (mut (ref i31))) (field (mut (ref i31)))))
(type $struct (struct_subtype (field (mut anyref)) (field (mut (ref i31))) (field (mut anyref)) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 1
@@ -53,10 +54,11 @@
;; must keep the type nullable, unlike in the previous module, due to the
;; default value being null.
- ;; CHECK: (type $struct (struct (field (mut i31ref))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut i31ref))))
(type $struct (struct_subtype (field (mut anyref)) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (drop
@@ -86,16 +88,20 @@
;; that we do so in all three types, not just the parent to which we write
;; (the children have no writes, but must still be updated).
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
- (type $struct (struct_subtype (field (mut structref)) data))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
+ (type $struct (struct_subtype (field (mut structref)) data))
+
+ ;; CHECK: (type $child-B (struct_subtype (field (mut (ref $struct))) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child-A|_ref|$child-B|_=>_none (func (param (ref $struct) (ref $child-A) (ref $child-B))))
+ ;; CHECK: (type $child-A (struct_subtype (field (mut (ref $struct))) $struct))
+ (type $child-A (struct_subtype (field (mut structref)) $struct))
- ;; CHECK: (type $child-A (struct_subtype (field (mut (ref $struct))) $struct))
- (type $child-A (struct_subtype (field (mut structref)) $struct))
+ (type $child-B (struct_subtype (field (mut structref)) $struct))
+ )
- ;; CHECK: (type $child-B (struct_subtype (field (mut (ref $struct))) $struct))
- (type $child-B (struct_subtype (field (mut structref)) $struct))
+ ;; CHECK: (type $ref|$struct|_ref|$child-A|_ref|$child-B|_=>_none (func (param (ref $struct) (ref $child-A) (ref $child-B))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child-A|_ref|$child-B|_=>_none) (param $struct (ref $struct)) (param $child-A (ref $child-A)) (param $child-B (ref $child-B))
;; CHECK-NEXT: (struct.set $struct 0
@@ -123,19 +129,21 @@
;; As above, but all writes are of $child-A, which allows more optimization
;; up to that type.
- ;; CHECK: (type $struct (struct (field (mut (ref $child-A)))))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $child-A)))))
+ (type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $child-A (struct_subtype (field (mut (ref $child-A))) $struct))
- (type $child-A (struct_subtype (field (mut structref)) $struct))
+ ;; CHECK: (type $child-A (struct_subtype (field (mut (ref $child-A))) $struct))
+ (type $child-A (struct_subtype (field (mut structref)) $struct))
- (type $struct (struct_subtype (field (mut structref)) data))
-
- ;; CHECK: (type $ref|$struct|_ref|$child-A|_=>_none (func (param (ref $struct) (ref $child-A))))
+ ;; CHECK: (type $child-B (struct_subtype (field (mut (ref $child-A))) $struct))
+ (type $child-B (struct_subtype (field (mut structref)) $struct))
+ )
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (type $child-B (struct_subtype (field (mut (ref $child-A))) $struct))
- (type $child-B (struct_subtype (field (mut structref)) $struct))
+ ;; CHECK: (type $ref|$struct|_ref|$child-A|_=>_none (func (param (ref $struct) (ref $child-A))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child-A|_=>_none) (param $struct (ref $struct)) (param $child-A (ref $child-A))
;; CHECK-NEXT: (struct.set $struct 0
@@ -175,13 +183,14 @@
;; child prevents specialization even in the parent and we only improve up to
;; $struct but not to $child.
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
(type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) $struct))
(type $child (struct_subtype (field (mut structref)) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (struct.set $struct 0
@@ -208,14 +217,14 @@
(module
;; As above, but both writes are of $child, so we can optimize.
- ;; CHECK: (type $struct (struct (field (mut (ref $child)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $child)))))
+ (type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref $child))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref $child))) $struct))
(type $child (struct_subtype (field (mut structref)) $struct))
- (type $struct (struct_subtype (field (mut structref)) data))
-
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (struct.set $struct 0
@@ -245,13 +254,14 @@
;; info, however, we can't make the parent field more specific than the
;; child's.
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
(type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) $struct))
(type $child (struct_subtype (field (mut structref)) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (drop
@@ -289,13 +299,14 @@
;; imply the fields are mutable, which limits optimization, see the next
;; testcase after this.)
- ;; CHECK: (type $struct (struct (field (ref $struct))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (ref $struct))))
(type $struct (struct_subtype (field structref) data))
- ;; CHECK: (type $child (struct_subtype (field (ref $child)) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (ref $child)) $struct))
(type $child (struct_subtype (field structref) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (drop
@@ -328,13 +339,14 @@
;; different types in this case, and both will become $struct (still an
;; improvement!)
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
(type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) $struct))
(type $child (struct_subtype (field (mut structref)) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (drop
@@ -367,13 +379,14 @@
;; that case there is nothing stopping us from specializing that new field
;; to $child.
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
(type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) (field (mut (ref $child))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref $struct))) (field (mut (ref $child))) $struct))
(type $child (struct_subtype (field (mut structref)) (field (mut structref)) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $work (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (drop
@@ -407,10 +420,11 @@
;; A copy of a field does not prevent optimization (even though it assigns
;; the old type).
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
(type $struct (struct_subtype (field (mut structref)) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
@@ -439,24 +453,27 @@
)
(module
- ;; CHECK: (type $X (struct ))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct (field (ref $Y))))
- ;; CHECK: (type $Y (struct_subtype $X))
- (type $Y (struct_subtype $X))
+ ;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A))
- ;; CHECK: (type $none_=>_none (func))
+ ;; CHECK: (type $X (struct ))
+ (type $X (struct))
- ;; CHECK: (type $A (struct (field (ref $Y))))
+ ;; CHECK: (type $Y (struct_subtype $X))
+ (type $Y (struct_subtype $X))
- ;; CHECK: (type $C (struct_subtype (field (ref $Y)) $A))
- (type $C (struct_subtype (field (ref $X)) $A))
+ (type $A (struct_subtype (field (ref $X)) data))
- ;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A))
- (type $B (struct_subtype (field (ref $X)) $A))
+ ;; CHECK: (type $C (struct_subtype (field (ref $Y)) $A))
+ (type $C (struct_subtype (field (ref $X)) $A))
- (type $A (struct_subtype (field (ref $X)) data))
+ (type $B (struct_subtype (field (ref $X)) $A))
+ )
- (type $X (struct))
+ ;; CHECK: (type $none_=>_none (func))
;; CHECK: (func $foo (type $none_=>_none)
;; CHECK-NEXT: (local $unused (ref null $C))
@@ -490,23 +507,25 @@
;; As above, but remove the struct.new to $B, which means $A, $B, $C all have
;; no writes to them. There are no optimizations to do here.
- ;; CHECK: (type $X (struct ))
- (type $X (struct))
-
- ;; CHECK: (type $none_=>_none (func))
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $X (struct ))
+ (type $X (struct))
- ;; CHECK: (type $A (struct (field (ref $X))))
+ ;; CHECK: (type $Y (struct_subtype $X))
+ (type $Y (struct_subtype $X))
- ;; CHECK: (type $C (struct_subtype (field (ref $X)) $A))
- (type $C (struct_subtype (field (ref $X)) $A))
+ ;; CHECK: (type $A (struct (field (ref $X))))
+ (type $A (struct_subtype (field (ref $X)) data))
- ;; CHECK: (type $B (struct_subtype (field (ref $X)) $A))
- (type $B (struct_subtype (field (ref $X)) $A))
+ ;; CHECK: (type $B (struct_subtype (field (ref $X)) $A))
+ (type $B (struct_subtype (field (ref $X)) $A))
- ;; CHECK: (type $Y (struct_subtype $X))
- (type $Y (struct_subtype $X))
+ ;; CHECK: (type $C (struct_subtype (field (ref $X)) $A))
+ (type $C (struct_subtype (field (ref $X)) $A))
+ )
- (type $A (struct_subtype (field (ref $X)) data))
+ ;; CHECK: (type $none_=>_none (func))
;; CHECK: (func $foo (type $none_=>_none)
;; CHECK-NEXT: (local $unused1 (ref null $C))
@@ -525,17 +544,18 @@
(module
;; CHECK: (type $X (struct ))
(type $X (struct))
+
;; CHECK: (type $none_=>_none (func))
;; CHECK: (type $A (struct (field (ref $X))))
- ;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A))
- (type $B (struct_subtype (field (ref $Y)) $A))
+ ;; CHECK: (type $Y (struct_subtype $X))
+ (type $Y (struct_subtype $X))
(type $A (struct_subtype (field (ref $X)) data))
- ;; CHECK: (type $Y (struct_subtype $X))
- (type $Y (struct_subtype $X))
+ ;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A))
+ (type $B (struct_subtype (field (ref $Y)) $A))
;; CHECK: (func $foo (type $none_=>_none)
;; CHECK-NEXT: (local $unused2 (ref null $B))
@@ -561,10 +581,11 @@
)
(module
- ;; CHECK: (type $struct (struct (field (mut (ref null $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref null $struct)))))
(type $struct (struct_subtype (field (mut (ref null struct))) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $update-null (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
@@ -594,12 +615,13 @@
;; As above, but now the null is in a child. The result should be the same:
;; refine the field to nullable $struct.
- ;; CHECK: (type $struct (struct (field (mut (ref null $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref null $struct)))))
(type $struct (struct_subtype (field (mut (ref null struct))) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref null $struct))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref null $struct))) $struct))
(type $child (struct_subtype (field (mut (ref null struct))) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $update-null (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (struct.set $struct 0
@@ -626,12 +648,13 @@
(module
;; As above, but now the null is in a parent. The result should be the same.
- ;; CHECK: (type $struct (struct (field (mut (ref null $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref null $struct)))))
(type $struct (struct_subtype (field (mut (ref null struct))) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref null $struct))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref null $struct))) $struct))
(type $child (struct_subtype (field (mut (ref null struct))) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $update-null (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (struct.set $struct 0
@@ -656,10 +679,11 @@
)
(module
- ;; CHECK: (type $struct (struct (field (mut nullref))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut nullref))))
(type $struct (struct_subtype (field (mut (ref null struct))) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (drop
@@ -676,10 +700,11 @@
)
(module
- ;; CHECK: (type $struct (struct (field (mut (ref null $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref null $struct)))))
(type $struct (struct_subtype (field (mut (ref null struct))) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (drop
@@ -704,10 +729,11 @@
)
(module
- ;; CHECK: (type $struct (struct (field (mut (ref null $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref null $struct)))))
(type $struct (struct_subtype (field (mut (ref null struct))) data))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (drop
@@ -736,13 +762,14 @@
)
(module
- ;; CHECK: (type $struct (struct (field (mut (ref null $child))) (field (mut (ref null $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref null $child))) (field (mut (ref null $struct)))))
(type $struct (struct_subtype (field (mut (ref null struct))) (field (mut (ref null struct))) data))
- ;; CHECK: (type $child (struct_subtype (field (mut (ref null $child))) (field (mut (ref null $struct))) $struct))
+ ;; CHECK: (type $child (struct_subtype (field (mut (ref null $child))) (field (mut (ref null $struct))) $struct))
(type $child (struct_subtype (field (mut (ref null struct))) (field (mut (ref null struct))) $struct))
- ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
+ ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func (param (ref $struct) (ref $child))))
;; CHECK: (func $update-null (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child))
;; CHECK-NEXT: (drop
@@ -791,27 +818,29 @@
;; Root-Outer[Root-Inner] -> Leaf1-Outer[Leaf1-Inner]
;; -> Leaf2-Outer[Leaf2-Inner]
- ;; CHECK: (type $Root-Inner (struct ))
-
- ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner))
- (type $Leaf2-Inner (struct_subtype $Root-Inner))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $Root-Inner (struct ))
+ (type $Root-Inner (struct))
- ;; CHECK: (type $ref?|$Leaf1-Outer|_=>_none (func (param (ref null $Leaf1-Outer))))
+ ;; CHECK: (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner))
+ (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner))
- ;; CHECK: (type $Root-Outer (struct (field (ref $Leaf2-Inner))))
+ ;; CHECK: (type $Root-Outer (struct (field (ref $Leaf2-Inner))))
- ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
+ ;; CHECK: (type $Leaf1-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
- ;; CHECK: (type $Leaf1-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
- (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer))
+ ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
- (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
+ ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner))
+ (type $Leaf2-Inner (struct_subtype $Root-Inner))
(type $Root-Outer (struct_subtype (field (ref $Root-Inner)) data))
- (type $Root-Inner (struct))
+ (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer))
- (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner))
+ (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
+
+ ;; CHECK: (type $ref?|$Leaf1-Outer|_=>_none (func (param (ref null $Leaf1-Outer))))
;; CHECK: (func $func (type $ref?|$Leaf1-Outer|_=>_none) (param $Leaf1-Outer (ref null $Leaf1-Outer))
;; CHECK-NEXT: (drop
@@ -931,12 +960,13 @@
)
(module
- ;; CHECK: (type $A (struct (field (ref null $A))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct (field (ref null $A))))
(type $A (struct_subtype (field (ref null $A)) data))
- ;; CHECK: (type $B (struct_subtype (field (ref null $B)) $A))
+ ;; CHECK: (type $B (struct_subtype (field (ref null $B)) $A))
(type $B (struct_subtype (field (ref null $A)) $A))
- ;; CHECK: (type $ref?|$B|_ref?|$A|_=>_none (func (param (ref null $B) (ref null $A))))
+ ;; CHECK: (type $ref?|$B|_ref?|$A|_=>_none (func (param (ref null $B) (ref null $A))))
;; CHECK: (func $heap-type (type $ref?|$B|_ref?|$A|_=>_none) (param $b (ref null $B)) (param $A (ref null $A))
;; CHECK-NEXT: (local $a (ref null $A))
@@ -981,10 +1011,11 @@
)
(module
- ;; CHECK: (type $A (struct (field (mut (ref $A)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct (field (mut (ref $A)))))
(type $A (struct_subtype (field (mut (ref null $A))) data))
- ;; CHECK: (type $ref|$A|_ref?|$A|_=>_none (func (param (ref $A) (ref null $A))))
+ ;; CHECK: (type $ref|$A|_ref?|$A|_=>_none (func (param (ref $A) (ref null $A))))
;; CHECK: (func $non-nullability-block (type $ref|$A|_ref?|$A|_=>_none) (param $nn (ref $A)) (param $A (ref null $A))
;; CHECK-NEXT: (struct.set $A 0
@@ -1046,10 +1077,11 @@
)
(module
- ;; CHECK: (type $struct (struct (field (mut (ref $struct)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $struct (struct (field (mut (ref $struct)))))
(type $struct (struct (field (mut (ref null struct)))))
- ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
+ ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))
;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
diff --git a/test/lit/passes/type-ssa_and_merging.wast b/test/lit/passes/type-ssa_and_merging.wast
index 291b37cc2..a642660db 100644
--- a/test/lit/passes/type-ssa_and_merging.wast
+++ b/test/lit/passes/type-ssa_and_merging.wast
@@ -1,25 +1,27 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: foreach %s %t wasm-opt --nominal --closed-world --gufa -Os -all -S -o - | filecheck %s --check-prefix NOP
-;; RUN: foreach %s %t wasm-opt --nominal --closed-world --type-ssa --gufa -Os --type-merging -all -S -o - | filecheck %s --check-prefix YES
+;; RUN: foreach %s %t wasm-opt --closed-world --gufa -Os -all -S -o - | filecheck %s --check-prefix NOP
+;; RUN: foreach %s %t wasm-opt --closed-world --type-ssa --gufa -Os --type-merging -all -S -o - | filecheck %s --check-prefix YES
;; Show that the combination of type-ssa and type-merging can find things that
;; otherwise cannot be optimized. NOP will fail to optimize something that YES
;; can.
(module
- ;; NOP: (type $A (struct (field i32)))
+ ;; NOP: (rec
+ ;; NOP-NEXT: (type $ref|$A|_=>_i32 (func (param (ref $A)) (result i32)))
+
+ ;; NOP: (type $A (struct (field i32)))
;; YES: (type $none_=>_i32 (func (result i32)))
- ;; YES: (type $A (struct ))
+ ;; YES: (rec
+ ;; YES-NEXT: (type $ref|$A|_=>_none (func (param (ref $A))))
+
+ ;; YES: (type $A (struct ))
(type $A (struct_subtype (field (mut i32)) data))
;; NOP: (type $none_=>_i32 (func (result i32)))
- ;; NOP: (type $ref|$A|_=>_i32 (func (param (ref $A)) (result i32)))
-
;; NOP: (import "a" "b" (func $import (result i32)))
- ;; YES: (type $ref|$A|_=>_none (func (param (ref $A))))
-
;; YES: (import "a" "b" (func $import (result i32)))
(import "a" "b" (func $import (result i32)))