diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2021-10-14 14:11:59 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-14 21:11:59 +0000 |
commit | bf665976b1526ca7cf11bacf5745563dfe193206 (patch) | |
tree | a6bb2cf0fa5d1972fe55f872418665778e00dde5 /test | |
parent | d592bad2b8fa777dab9682d2d2e47f9957c8051d (diff) | |
download | binaryen-bf665976b1526ca7cf11bacf5745563dfe193206.tar.gz binaryen-bf665976b1526ca7cf11bacf5745563dfe193206.tar.bz2 binaryen-bf665976b1526ca7cf11bacf5745563dfe193206.zip |
Switch from "extends" to M4 nominal syntax (#4248)
Switch from "extends" to M4 nominal syntax
Change all test inputs from using the old (extends $super) syntax to using the
new *_subtype syntax for their inputs and also update the printer to emit the
new syntax. Add a new test explicitly testing the old notation to make sure it
keeps working until we remove support for it.
Diffstat (limited to 'test')
28 files changed, 2254 insertions, 221 deletions
diff --git a/test/lit/binary/heap-types.wast b/test/lit/binary/heap-types.wast index f455d7376..98ece30bf 100644 --- a/test/lit/binary/heap-types.wast +++ b/test/lit/binary/heap-types.wast @@ -10,9 +10,9 @@ (module ;; CHECK: (type $struct.A (struct (field i32))) - ;; NOMNL: (type $struct.A (struct (field i32))) + ;; NOMNL: (type $struct.A (struct_subtype (field i32) data)) (type $struct.A (struct i32)) - ;; NOMNL: (type $struct.B (struct (field i32))) + ;; NOMNL: (type $struct.B (struct_subtype (field i32) data)) (type $struct.B (struct i32)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -37,9 +37,9 @@ (module ;; CHECK: (type $struct.A (struct (field i32))) - ;; NOMNL: (type $struct.A (struct (field i32))) + ;; NOMNL: (type $struct.A (struct_subtype (field i32) data)) (type $struct.A (struct i32)) - ;; NOMNL: (type $struct.B (struct (field i32))) + ;; NOMNL: (type $struct.B (struct_subtype (field i32) data)) (type $struct.B (struct i32)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -64,7 +64,7 @@ (module ;; CHECK: (type $struct.A (struct (field i32))) - ;; NOMNL: (type $struct.A (struct (field i32))) + ;; NOMNL: (type $struct.A (struct_subtype (field i32) data)) (type $struct.A (struct i32)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -85,7 +85,7 @@ (module ;; CHECK: (type $vector (array (mut f64))) - ;; NOMNL: (type $vector (array (mut f64))) + ;; NOMNL: (type $vector (array_subtype (mut f64) data)) (type $vector (array (mut f64))) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -115,7 +115,7 @@ (module ;; CHECK: (type $vector (array (mut f64))) - ;; NOMNL: (type $vector (array (mut f64))) + ;; NOMNL: (type $vector (array_subtype (mut f64) data)) (type $vector (array (mut f64))) ;; CHECK: (func $test ;; CHECK-NEXT: (drop diff --git a/test/lit/forward-declared-types.wast b/test/lit/forward-declared-types.wast index f7d3592cc..c20cc3a1e 100644 --- a/test/lit/forward-declared-types.wast +++ b/test/lit/forward-declared-types.wast @@ -2,17 +2,21 @@ ;; Test that types can be used before they are defined ;; RUN: wasm-opt %s -all -S -o - | filecheck %s -;; RUN: wasm-opt %s -all --nominal -S -o - | filecheck %s +;; RUN: wasm-opt %s -all --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $func (func)) ;; CHECK: (type $struct (struct (field (ref $array)) (field (ref null $func)))) + ;; NOMNL: (type $func (func_subtype func)) + + ;; NOMNL: (type $struct (struct_subtype (field (ref $array)) (field (ref null $func)) data)) (type $struct (struct (field (ref $array)) (field (ref null $func)) )) ;; CHECK: (type $array (array (rtt 2 $func))) + ;; NOMNL: (type $array (array_subtype (rtt 2 $func) data)) (type $array (array (field (rtt 2 $func)))) (type $func (func)) diff --git a/test/lit/gc-eh.wast b/test/lit/gc-eh.wast index 07e2f18b7..7a69f01ab 100644 --- a/test/lit/gc-eh.wast +++ b/test/lit/gc-eh.wast @@ -3,15 +3,17 @@ ;; Check that pops of GC types work correctly. ;; RUN: wasm-opt -all %s -S -o - | filecheck %s -;; RUN: wasm-opt -all --nominal %s -S -o - | filecheck %s +;; RUN: wasm-opt -all --nominal %s -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $A (struct (field (mut i32)))) + ;; NOMNL: (type $A (struct_subtype (field (mut i32)) data)) (type $A (struct (field (mut i32)) )) ;; CHECK: (tag $tagA (param (ref $A))) + ;; NOMNL: (tag $tagA (param (ref $A))) (tag $tagA (param (ref $A))) ;; CHECK: (func $foo (result (ref null $A)) @@ -27,6 +29,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.null $A) ;; CHECK-NEXT: ) + ;; NOMNL: (func $foo (result (ref null $A)) + ;; NOMNL-NEXT: (try $try + ;; NOMNL-NEXT: (do + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (catch $tagA + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (pop (ref $A)) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: ) (func $foo (result (ref null $A)) (try (do diff --git a/test/lit/gc-read-write-effects.wast b/test/lit/gc-read-write-effects.wast index d22702b79..62ec481b1 100644 --- a/test/lit/gc-read-write-effects.wast +++ b/test/lit/gc-read-write-effects.wast @@ -4,10 +4,11 @@ ;; struct field. ;; RUN: wasm-opt -all --simplify-locals %s -S -o - | filecheck %s -;; RUN: wasm-opt -all --simplify-locals %s --nominal -S -o - | filecheck %s +;; RUN: wasm-opt -all --simplify-locals %s --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $A (struct (field (mut i32)))) + ;; NOMNL: (type $A (struct_subtype (field (mut i32)) data)) (type $A (struct (field (mut i32)) )) @@ -36,6 +37,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) + ;; NOMNL: (func $test (param $x (ref null $A)) (result i32) + ;; NOMNL-NEXT: (local $y i32) + ;; NOMNL-NEXT: (local.set $y + ;; NOMNL-NEXT: (struct.get $A 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.set $A 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (i32.const 10) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: ) (func $test (export "test") (param $x (ref null $A)) (result i32) (local $y i32) (local.set $y diff --git a/test/lit/lub-bug-3843.wast b/test/lit/lub-bug-3843.wast index 67bcecb39..409526a78 100644 --- a/test/lit/lub-bug-3843.wast +++ b/test/lit/lub-bug-3843.wast @@ -8,19 +8,19 @@ (module ;; CHECK: (type $A (struct (field (ref null $C)))) - ;; NOMNL: (type $A (struct (field (ref null $C)))) + ;; NOMNL: (type $A (struct_subtype (field (ref null $C)) data)) (type $A (struct (field (ref null $C)))) ;; CHECK: (type $B (struct (field (ref null $D)))) - ;; NOMNL: (type $B (struct (field (ref null $D))) (extends $A)) - (type $B (struct (field (ref null $D))) (extends $A)) + ;; NOMNL: (type $B (struct_subtype (field (ref null $D)) $A)) + (type $B (struct_subtype (field (ref null $D)) $A)) ;; CHECK: (type $D (struct (field (mut (ref $A))) (field (mut (ref $A))))) - ;; NOMNL: (type $D (struct (field (mut (ref $A))) (field (mut (ref $A)))) (extends $C)) - (type $D (struct (field (mut (ref $A))) (field (mut (ref $A)))) (extends $C)) + ;; NOMNL: (type $D (struct_subtype (field (mut (ref $A))) (field (mut (ref $A))) $C)) + (type $D (struct_subtype (field (mut (ref $A))) (field (mut (ref $A))) $C)) ;; CHECK: (type $C (struct (field (mut (ref $A))))) - ;; NOMNL: (type $C (struct (field (mut (ref $A))))) + ;; NOMNL: (type $C (struct_subtype (field (mut (ref $A))) data)) (type $C (struct (field (mut (ref $A))))) diff --git a/test/lit/nominal-chain.wast b/test/lit/nominal-chain.wast index 7b9c96d9c..2c90ee6ec 100644 --- a/test/lit/nominal-chain.wast +++ b/test/lit/nominal-chain.wast @@ -7,19 +7,19 @@ ;; types. (module - ;; CHECK: (type $leaf (struct (field i32) (field i64) (field f32) (field f64)) (extends $twig)) - (type $leaf (struct i32 i64 f32 f64) (extends $twig)) + ;; CHECK: (type $leaf (struct_subtype (field i32) (field i64) (field f32) (field f64) $twig)) + (type $leaf (struct_subtype i32 i64 f32 f64 $twig)) - ;; CHECK: (type $root (struct )) + ;; CHECK: (type $root (struct_subtype data)) - ;; CHECK: (type $twig (struct (field i32) (field i64) (field f32)) (extends $branch)) - (type $twig (struct i32 i64 f32) (extends $branch)) + ;; CHECK: (type $twig (struct_subtype (field i32) (field i64) (field f32) $branch)) + (type $twig (struct_subtype i32 i64 f32 $branch)) - ;; CHECK: (type $branch (struct (field i32) (field i64)) (extends $trunk)) - (type $branch (struct i32 i64) (extends $trunk)) + ;; CHECK: (type $branch (struct_subtype (field i32) (field i64) $trunk)) + (type $branch (struct_subtype i32 i64 $trunk)) - ;; CHECK: (type $trunk (struct (field i32)) (extends $root)) - (type $trunk (struct i32) (extends $root)) + ;; CHECK: (type $trunk (struct_subtype (field i32) $root)) + (type $trunk (struct_subtype i32 $root)) (type $root (struct)) diff --git a/test/lit/nominal-func.wast b/test/lit/nominal-func.wast index b5f266db3..08acae21d 100644 --- a/test/lit/nominal-func.wast +++ b/test/lit/nominal-func.wast @@ -6,7 +6,7 @@ ;; This will be the "canonical" function type rather than $foo_t (type $bad_t (func)) - ;; CHECK: (type $foo_t (func)) + ;; CHECK: (type $foo_t (func_subtype func)) (type $foo_t (func)) ;; CHECK: (func $foo diff --git a/test/lit/nominal-good.wast b/test/lit/nominal-good.wast index 4110fb96b..dc9f81548 100644 --- a/test/lit/nominal-good.wast +++ b/test/lit/nominal-good.wast @@ -6,21 +6,21 @@ (module - ;; NOMINAL: (type $super-struct (struct (field i32))) + ;; NOMINAL: (type $super-struct (struct_subtype (field i32) data)) ;; EQUIREC: (type $super-struct (struct (field i32))) (type $super-struct (struct i32)) - ;; NOMINAL: (type $sub-struct (struct (field i32) (field i64)) (extends $super-struct)) + ;; NOMINAL: (type $sub-struct (struct_subtype (field i32) (field i64) $super-struct)) ;; EQUIREC: (type $sub-struct (struct (field i32) (field i64))) - (type $sub-struct (struct i32 i64) (extends $super-struct)) + (type $sub-struct (struct_subtype i32 i64 $super-struct)) - ;; NOMINAL: (type $super-array (array (ref $super-struct))) + ;; NOMINAL: (type $super-array (array_subtype (ref $super-struct) data)) ;; EQUIREC: (type $super-array (array (ref $super-struct))) (type $super-array (array (ref $super-struct))) - ;; NOMINAL: (type $sub-array (array (ref $sub-struct)) (extends $super-array)) + ;; NOMINAL: (type $sub-array (array_subtype (ref $sub-struct) $super-array)) ;; EQUIREC: (type $sub-array (array (ref $sub-struct))) - (type $sub-array (array (ref $sub-struct)) (extends $super-array)) + (type $sub-array (array_subtype (ref $sub-struct) $super-array)) ;; TODO: signature types as well, once functions store their HeapTypes. diff --git a/test/lit/nominal-named-field.wast b/test/lit/nominal-named-field.wast index 5dd33d99e..3b827e11b 100644 --- a/test/lit/nominal-named-field.wast +++ b/test/lit/nominal-named-field.wast @@ -6,7 +6,7 @@ ;; RUN: wasm-opt %s -all --nominal --roundtrip -S -o - | filecheck %s (module - ;; CHECK: (type $struct (struct (field (mut i32)) (field f32) (field $named f64))) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) (field f32) (field $named f64) data)) (type $struct (struct (field (mut i32)) (field f32) diff --git a/test/lit/parse-nominal-types-extends.wast b/test/lit/parse-nominal-types-extends.wast new file mode 100644 index 000000000..2077bd90f --- /dev/null +++ b/test/lit/parse-nominal-types-extends.wast @@ -0,0 +1,67 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; Test that new-style nominal types are parsed correctly. +;; TODO: Remove --nominal below once nominal types are parsed as nominal by default. + +;; RUN: foreach %s %t wasm-opt --nominal -all -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --nominal -all --roundtrip -S -o - | filecheck %s + +;; void function type +(module + ;; CHECK: (type $sub (func_subtype $super)) + (type $sub (func) (extends $super)) + + ;; CHECK: (type $super (func_subtype func)) + (type $super (func)) + + ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + (global $g (ref null $super) (ref.null $sub)) +) + +;; function type with params and results +(module + ;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super)) + (type $sub (func (param i32) (result i32)) (extends $super)) + + ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) + (type $super (func (param i32) (result i32))) + + ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + (global $g (ref null $super) (ref.null $sub)) +) + +;; empty struct type +(module + ;; CHECK: (type $sub (struct_subtype $super)) + (type $sub (struct) (extends $super)) + + ;; CHECK: (type $super (struct_subtype data)) + (type $super (struct)) + + ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + (global $g (ref null $super) (ref.null $sub)) +) + +;; struct type with fields +(module + ;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super)) + (type $sub (struct i32 (field i64)) (extends $super)) + + ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) + (type $super (struct (field i32) i64)) + + ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + (global $g (ref null $super) (ref.null $sub)) +) + +;; array type +(module + ;; CHECK: (type $sub (array_subtype i8 $super)) + (type $sub (array i8) (extends $super)) + + ;; CHECK: (type $super (array_subtype i8 data)) + (type $super (array i8)) + + ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + (global $g (ref null $super) (ref.null $sub)) +) diff --git a/test/lit/parse-nominal-types.wast b/test/lit/parse-nominal-types.wast index c3981478d..fb4a0cf53 100644 --- a/test/lit/parse-nominal-types.wast +++ b/test/lit/parse-nominal-types.wast @@ -8,10 +8,10 @@ ;; void function type (module - ;; CHECK: (type $sub (func) (extends $super)) + ;; CHECK: (type $sub (func_subtype $super)) (type $sub (func_subtype $super)) - ;; CHECK: (type $super (func)) + ;; CHECK: (type $super (func_subtype func)) (type $super (func_subtype func)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -20,10 +20,10 @@ ;; function type with params and results (module - ;; CHECK: (type $sub (func (param i32) (result i32)) (extends $super)) + ;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super)) (type $sub (func_subtype (param i32) (result i32) $super)) - ;; CHECK: (type $super (func (param i32) (result i32))) + ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) (type $super (func_subtype (param i32) (result i32) func)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -32,10 +32,10 @@ ;; empty struct type (module - ;; CHECK: (type $sub (struct ) (extends $super)) + ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct_subtype $super)) - ;; CHECK: (type $super (struct )) + ;; CHECK: (type $super (struct_subtype data)) (type $super (struct_subtype data)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -44,10 +44,10 @@ ;; struct type with fields (module - ;; CHECK: (type $sub (struct (field i32) (field i64)) (extends $super)) + ;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super)) (type $sub (struct_subtype i32 (field i64) $super)) - ;; CHECK: (type $super (struct (field i32) (field i64))) + ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) (type $super (struct_subtype (field i32) i64 data)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -56,10 +56,10 @@ ;; array type (module - ;; CHECK: (type $sub (array i8) (extends $super)) + ;; CHECK: (type $sub (array_subtype i8 $super)) (type $sub (array_subtype i8 $super)) - ;; CHECK: (type $super (array i8)) + ;; CHECK: (type $super (array_subtype i8 data)) (type $super (array_subtype i8 data)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index db6e108bf..99fd9d209 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -4,9 +4,9 @@ ;; name getting in the way) (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $impossible-get ;; CHECK-NEXT: (drop @@ -31,9 +31,9 @@ ) (module - ;; CHECK: (type $struct (struct (field i64))) + ;; CHECK: (type $struct (struct_subtype (field i64) data)) (type $struct (struct i64)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -74,9 +74,9 @@ ) (module - ;; CHECK: (type $struct (struct (field f32))) + ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -114,9 +114,9 @@ ) (module - ;; CHECK: (type $struct (struct (field f32))) + ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (type $f32_=>_none (func (param f32))) + ;; CHECK: (type $f32_=>_none (func_subtype (param f32) func)) ;; CHECK: (func $test (param $f f32) ;; CHECK-NEXT: (drop @@ -150,9 +150,9 @@ ;; Create in one function, get in another. The 10 should be forwarded to the ;; get. (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -194,9 +194,9 @@ ;; As before, but with the order of functions reversed to check for any ordering ;; issues. (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $get @@ -240,9 +240,9 @@ ;; Different values assigned in the same function, in different struct.news, ;; so we cannot optimize the struct.get away. (module - ;; CHECK: (type $struct (struct (field f32))) + ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -286,9 +286,9 @@ ;; Different values assigned in different functions, and one is a struct.set. (module - ;; CHECK: (type $struct (struct (field (mut f32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -337,9 +337,9 @@ ;; As the last testcase, but the values happen to coincide, so we can optimize ;; the get into a constant. (module - ;; CHECK: (type $struct (struct (field (mut f32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -392,11 +392,11 @@ ;; Check that we look into the fallthrough value that is assigned. (module - ;; CHECK: (type $struct (struct (field (mut f32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $i32_=>_none (func (param i32))) + ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -465,9 +465,9 @@ ;; Test a function reference instead of a number. (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct (field funcref))) + ;; CHECK: (type $struct (struct_subtype (field funcref) data)) (type $struct (struct funcref)) ;; CHECK: (elem declare func $test) @@ -507,7 +507,7 @@ ;; Test for unreachable creations, sets, and gets. (module (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -555,12 +555,12 @@ ;; subtype, the get must trap anyhow (the reference it receives can ;; only be null in this closed world). (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $substruct (struct (field i32)) (extends $struct)) - (type $substruct (struct i32) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field i32) $struct)) + (type $substruct (struct_subtype i32 $struct)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -602,12 +602,12 @@ ;; will optimize the result to the only possible value. (In practice, though, ;; it will trap anyhow.) (module - ;; CHECK: (type $struct (struct (field (mut i32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $substruct (struct (field (mut i32))) (extends $struct)) - (type $substruct (struct (mut i32)) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) $struct)) + (type $substruct (struct_subtype (mut i32) $struct)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -658,12 +658,12 @@ ;; reference to the subtype (we never create a supertype) and so we ;; can optimize. (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $substruct (struct (field i32) (field f64)) (extends $struct)) - (type $substruct (struct i32 f64) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) + (type $substruct (struct_subtype i32 f64 $struct)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $create @@ -708,12 +708,12 @@ ;; Subtyping: Create both a subtype and a supertype, with identical constants ;; for the shared field, and get the supertype. (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $substruct (struct (field i32) (field f64)) (extends $struct)) - (type $substruct (struct i32 f64) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) + (type $substruct (struct_subtype i32 f64 $struct)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -770,12 +770,12 @@ ;; for the shared field, preventing optimization, as a get of the ;; supertype may receive an instance of the subtype. (module - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $substruct (struct (field i32) (field f64)) (extends $struct)) - (type $substruct (struct i32 f64) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) + (type $substruct (struct_subtype i32 f64 $struct)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -828,12 +828,12 @@ ;; shared between the types, but we only create the substruct with ;; one value, so we can optimize. (module - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $substruct (struct (field i32) (field f64)) (extends $struct)) - (type $substruct (struct i32 f64) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) + (type $substruct (struct_subtype i32 f64 $struct)) - ;; CHECK: (type $struct (struct (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $create @@ -889,13 +889,13 @@ ;; As above, but add a set of $struct. The set prevents the optimization. (module - ;; CHECK: (type $struct (struct (field (mut i32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $substruct (struct (field (mut i32)) (field f64)) (extends $struct)) - (type $substruct (struct (mut i32) f64) (extends $struct)) + ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) (field f64) $struct)) + (type $substruct (struct_subtype (mut i32) f64 $struct)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -954,15 +954,15 @@ ;; Multi-level subtyping, check that we propagate not just to the immediate ;; supertype but all the way as needed. (module - ;; CHECK: (type $struct3 (struct (field i32) (field f64) (field anyref)) (extends $struct2)) - (type $struct3 (struct i32 f64 anyref) (extends $struct2)) + ;; CHECK: (type $struct3 (struct_subtype (field i32) (field f64) (field anyref) $struct2)) + (type $struct3 (struct_subtype i32 f64 anyref $struct2)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct2 (struct (field i32) (field f64)) (extends $struct1)) - (type $struct2 (struct i32 f64) (extends $struct1)) + ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1)) + (type $struct2 (struct_subtype i32 f64 $struct1)) - ;; CHECK: (type $struct1 (struct (field i32))) + ;; CHECK: (type $struct1 (struct_subtype (field i32) data)) (type $struct1 (struct i32)) ;; CHECK: (func $create @@ -1089,18 +1089,18 @@ ;; different values in the sub-most type. Create the top and bottom types, but ;; not the middle one. (module - ;; CHECK: (type $struct3 (struct (field i32) (field i32) (field f64) (field f64) (field anyref) (field anyref)) (extends $struct2)) - (type $struct3 (struct i32 i32 f64 f64 anyref anyref) (extends $struct2)) + ;; CHECK: (type $struct3 (struct_subtype (field i32) (field i32) (field f64) (field f64) (field anyref) (field anyref) $struct2)) + (type $struct3 (struct_subtype i32 i32 f64 f64 anyref anyref $struct2)) - ;; CHECK: (type $struct1 (struct (field i32) (field i32))) + ;; CHECK: (type $struct1 (struct_subtype (field i32) (field i32) data)) (type $struct1 (struct i32 i32)) - ;; CHECK: (type $struct2 (struct (field i32) (field i32) (field f64) (field f64)) (extends $struct1)) - (type $struct2 (struct i32 i32 f64 f64) (extends $struct1)) + ;; CHECK: (type $struct2 (struct_subtype (field i32) (field i32) (field f64) (field f64) $struct1)) + (type $struct2 (struct_subtype i32 i32 f64 f64 $struct1)) - ;; CHECK: (type $anyref_=>_none (func (param anyref))) + ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create (param $any anyref) ;; CHECK-NEXT: (drop @@ -1323,14 +1323,14 @@ ;; Multi-level subtyping with a different value in the middle of the chain. We ;; can only optimize $struct3. (module - ;; CHECK: (type $struct1 (struct (field (mut i32)))) + ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) (type $struct1 (struct (mut i32))) - ;; CHECK: (type $struct2 (struct (field (mut i32)) (field f64)) (extends $struct1)) - (type $struct2 (struct (mut i32) f64) (extends $struct1)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) + (type $struct2 (struct_subtype (mut i32) f64 $struct1)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct3 (struct (field (mut i32)) (field f64) (field anyref)) (extends $struct2)) - (type $struct3 (struct (mut i32) f64 anyref) (extends $struct2)) + ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) + (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -1423,16 +1423,16 @@ ;; As above, but add not just a new of the middle class with a different value ;; but also a set. That prevents all optimizations. (module - ;; CHECK: (type $struct2 (struct (field (mut i32)) (field f64)) (extends $struct1)) - (type $struct2 (struct (mut i32) f64) (extends $struct1)) + ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) + (type $struct2 (struct_subtype (mut i32) f64 $struct1)) - ;; CHECK: (type $struct1 (struct (field (mut i32)))) + ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) (type $struct1 (struct (mut i32))) - ;; CHECK: (type $struct3 (struct (field (mut i32)) (field f64) (field anyref)) (extends $struct2)) - (type $struct3 (struct (mut i32) f64 anyref) (extends $struct2)) + ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) + (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -1529,10 +1529,10 @@ ;; Test for a struct with multiple fields, some of which are constant and hence ;; optimizable, and some not. Also test that some have the same type. (module - ;; CHECK: (type $struct (struct (field i32) (field f64) (field i32) (field f64) (field i32))) + ;; CHECK: (type $struct (struct_subtype (field i32) (field f64) (field i32) (field f64) (field i32) data)) (type $struct (struct i32 f64 i32 f64 i32)) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -1653,20 +1653,20 @@ ;; sets, and the final subtype C has a create and a get. The set to A should ;; apply to it, preventing optimization. (module - ;; CHECK: (type $C (struct (field (mut i32))) (extends $B)) - (type $C (struct (mut i32)) (extends $B)) + ;; CHECK: (type $C (struct_subtype (field (mut i32)) $B)) + (type $C (struct_subtype (mut i32) $B)) - ;; CHECK: (type $A (struct (field (mut i32)))) + ;; CHECK: (type $A (struct_subtype (field (mut i32)) data)) (type $A (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $ref|$A|_=>_none (func (param (ref $A)))) + ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) - ;; CHECK: (type $ref|$C|_=>_none (func (param (ref $C)))) + ;; CHECK: (type $ref|$C|_=>_none (func_subtype (param (ref $C)) func)) - ;; CHECK: (type $B (struct (field (mut i32))) (extends $A)) - (type $B (struct (mut i32)) (extends $A)) + ;; CHECK: (type $B (struct_subtype (field (mut i32)) $A)) + (type $B (struct_subtype (mut i32) $A)) ;; CHECK: (func $create ;; CHECK-NEXT: (drop @@ -1715,10 +1715,10 @@ ;; Copies of a field to itself can be ignored. As a result, we can optimize both ;; of the gets here. (module - ;; CHECK: (type $struct (struct (field (mut i32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop @@ -1773,11 +1773,11 @@ ;; Test of a near-copy, of a similar looking field (same index, and same field ;; type) but in a different struct. (module - ;; CHECK: (type $struct (struct (field (mut f32)) (field (mut i32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) (field (mut i32)) data)) (type $struct (struct (mut f32) (mut i32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $other (struct (field (mut f64)) (field (mut i32)))) + ;; CHECK: (type $other (struct_subtype (field (mut f64)) (field (mut i32)) data)) (type $other (struct (mut f64) (mut i32))) ;; CHECK: (func $test @@ -1824,10 +1824,10 @@ ;; Test of a near-copy, of a different index. (module - ;; CHECK: (type $struct (struct (field (mut i32)) (field (mut i32)))) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) (field (mut i32)) data)) (type $struct (struct (mut i32) (mut i32))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast index f4d4ab056..7c986bd4e 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -4,24 +4,24 @@ (module ;; CHECK: (type ${i32} (struct (field i32))) - ;; NOMNL: (type ${i32} (struct (field i32)) (extends ${})) - (type ${i32} (struct (field i32)) (extends ${})) + ;; NOMNL: (type ${i32} (struct_subtype (field i32) ${})) + (type ${i32} (struct_subtype (field i32) ${})) ;; CHECK: (type ${} (struct )) - ;; NOMNL: (type ${} (struct )) + ;; NOMNL: (type ${} (struct_subtype data)) (type ${} (struct)) ;; CHECK: (type ${i32_i64} (struct (field i32) (field i64))) - ;; NOMNL: (type ${i32_i64} (struct (field i32) (field i64)) (extends ${i32})) - (type ${i32_i64} (struct (field i32) (field i64)) (extends ${i32})) + ;; NOMNL: (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) + (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) ;; CHECK: (type ${f64} (struct (field f64))) - ;; NOMNL: (type ${f64} (struct (field f64)) (extends ${})) - (type ${f64} (struct (field f64)) (extends ${})) + ;; NOMNL: (type ${f64} (struct_subtype (field f64) ${})) + (type ${f64} (struct_subtype (field f64) ${})) ;; CHECK: (type ${i32_f32} (struct (field i32) (field f32))) - ;; NOMNL: (type ${i32_f32} (struct (field i32) (field f32)) (extends ${i32})) - (type ${i32_f32} (struct (field i32) (field f32)) (extends ${i32})) + ;; NOMNL: (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) + (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) ;; CHECK: (func $call-various-params-no ;; CHECK-NEXT: (call $various-params-no diff --git a/test/lit/passes/dae-gc-refine-return.wast b/test/lit/passes/dae-gc-refine-return.wast index 73f1d040f..60b340cdc 100644 --- a/test/lit/passes/dae-gc-refine-return.wast +++ b/test/lit/passes/dae-gc-refine-return.wast @@ -4,23 +4,23 @@ (module ;; CHECK: (type $return_{} (func (result (ref ${})))) - ;; NOMNL: (type $return_{} (func (result (ref ${})))) + ;; NOMNL: (type $return_{} (func_subtype (result (ref ${})) func)) (type $return_{} (func (result (ref ${})))) ;; CHECK: (type ${i32_f32} (struct (field i32) (field f32))) - ;; NOMNL: (type ${i32_f32} (struct (field i32) (field f32)) (extends ${i32})) - (type ${i32_f32} (struct (field i32) (field f32)) (extends ${i32})) + ;; NOMNL: (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) + (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) ;; CHECK: (type ${i32_i64} (struct (field i32) (field i64))) - ;; NOMNL: (type ${i32_i64} (struct (field i32) (field i64)) (extends ${i32})) - (type ${i32_i64} (struct (field i32) (field i64)) (extends ${i32})) + ;; NOMNL: (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) + (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) ;; CHECK: (type ${i32} (struct (field i32))) - ;; NOMNL: (type ${i32} (struct (field i32)) (extends ${})) - (type ${i32} (struct (field i32)) (extends ${})) + ;; NOMNL: (type ${i32} (struct_subtype (field i32) ${})) + (type ${i32} (struct_subtype (field i32) ${})) ;; CHECK: (type ${} (struct )) - ;; NOMNL: (type ${} (struct )) + ;; NOMNL: (type ${} (struct_subtype data)) (type ${} (struct)) (table 1 1 funcref) diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index 899087e7f..3cc1c8653 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -1,14 +1,18 @@ ;; 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 +;; RUN: wasm-opt %s -all --dae --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type ${} (struct )) + ;; NOMNL: (type ${} (struct_subtype data)) (type ${} (struct)) ;; CHECK: (func $foo ;; CHECK-NEXT: (call $bar) ;; CHECK-NEXT: ) + ;; NOMNL: (func $foo + ;; NOMNL-NEXT: (call $bar) + ;; NOMNL-NEXT: ) (func $foo (call $bar (i31.new @@ -31,6 +35,21 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $bar + ;; NOMNL-NEXT: (local $0 (ref null i31)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.tee $0 + ;; NOMNL-NEXT: (i31.new + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.tee $0 + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $bar (param $0 i31ref) (drop ;; after the parameter is removed, we create a nullable local to replace it, @@ -55,6 +74,9 @@ ;; CHECK: (func $get-rtt (param $0 (rtt ${})) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) + ;; NOMNL: (func $get-rtt (param $0 (rtt ${})) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) (func $get-rtt (param $0 (rtt ${})) (nop) ) @@ -63,6 +85,11 @@ ;; CHECK-NEXT: (rtt.canon ${}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $send-rtt + ;; NOMNL-NEXT: (call $get-rtt + ;; NOMNL-NEXT: (rtt.canon ${}) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $send-rtt (call $get-rtt (rtt.canon ${}) diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast index 83b9f4bf5..8610e0760 100644 --- a/test/lit/passes/gto-mutability.wast +++ b/test/lit/passes/gto-mutability.wast @@ -7,13 +7,13 @@ ;; The struct here has three fields, and the second of them has no struct.set ;; which means we can make it immutable. - ;; CHECK: (type $struct (struct (field (mut funcref)) (field funcref) (field (mut funcref)))) + ;; CHECK: (type $struct (struct_subtype (field (mut funcref)) (field funcref) (field (mut funcref)) data)) (type $struct (struct (field (mut funcref)) (field (mut funcref)) (field (mut funcref)))) ;; Test that we update tag types properly. - ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct)))) + ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func)) - ;; CHECK: (type $none_=>_ref?|$struct| (func (result (ref null $struct)))) + ;; CHECK: (type $none_=>_ref?|$struct| (func_subtype (result (ref null $struct)) func)) ;; CHECK: (tag $tag (param (ref $struct))) (tag $tag (param (ref $struct))) @@ -120,12 +120,12 @@ ;; Test recursion between structs where we only modify one. Specifically $B ;; has no writes to either of its fields. - ;; CHECK: (type $A (struct (field (mut (ref null $B))) (field (mut i32)))) + ;; CHECK: (type $A (struct_subtype (field (mut (ref null $B))) (field (mut i32)) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) - ;; CHECK: (type $B (struct (field (ref null $A)) (field f64))) + ;; CHECK: (type $B (struct_subtype (field (ref null $A)) (field f64) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) - ;; CHECK: (type $ref|$A|_=>_none (func (param (ref $A)))) + ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) ;; CHECK: (func $func (param $x (ref $A)) ;; CHECK-NEXT: (struct.set $A 0 @@ -152,13 +152,13 @@ (module ;; As before, but flipped so that $A's fields can become immutable. - ;; CHECK: (type $B (struct (field (mut (ref null $A))) (field (mut f64)))) + ;; CHECK: (type $B (struct_subtype (field (mut (ref null $A))) (field (mut f64)) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) - ;; CHECK: (type $A (struct (field (ref null $B)) (field i32))) + ;; CHECK: (type $A (struct_subtype (field (ref null $B)) (field i32) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) - ;; CHECK: (type $ref|$B|_=>_none (func (param (ref $B)))) + ;; CHECK: (type $ref|$B|_=>_none (func_subtype (param (ref $B)) func)) ;; CHECK: (func $func (param $x (ref $B)) ;; CHECK-NEXT: (struct.set $B 0 @@ -185,13 +185,13 @@ (module ;; As before, but now one field in each can become immutable. - ;; CHECK: (type $B (struct (field (ref null $A)) (field (mut f64)))) + ;; CHECK: (type $B (struct_subtype (field (ref null $A)) (field (mut f64)) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) - ;; CHECK: (type $A (struct (field (mut (ref null $B))) (field i32))) + ;; CHECK: (type $A (struct_subtype (field (mut (ref null $B))) (field i32) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) - ;; CHECK: (type $ref|$A|_ref|$B|_=>_none (func (param (ref $A) (ref $B)))) + ;; CHECK: (type $ref|$A|_ref|$B|_=>_none (func_subtype (param (ref $A) (ref $B)) func)) ;; CHECK: (func $func (param $x (ref $A)) (param $y (ref $B)) ;; CHECK-NEXT: (struct.set $A 0 @@ -220,10 +220,10 @@ ;; Field #1 is mutable and can become so. ;; Field #2 is mutable and must remain so. - ;; CHECK: (type $struct (struct (field i32) (field i32) (field (mut i32)))) + ;; CHECK: (type $struct (struct_subtype (field i32) (field i32) (field (mut i32)) data)) (type $struct (struct (field i32) (field (mut i32)) (field (mut i32)))) - ;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct)))) + ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func)) ;; CHECK: (func $func (param $x (ref $struct)) ;; CHECK-NEXT: (struct.set $struct 2 @@ -243,12 +243,12 @@ ;; Subtyping. Without a write in either supertype or subtype, we can ;; optimize the field to be immutable. - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $super (struct (field i32))) + ;; CHECK: (type $super (struct_subtype (field i32) data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $sub (struct (field i32)) (extends $super)) - (type $sub (struct (field (mut i32))) (extends $super)) + ;; CHECK: (type $sub (struct_subtype (field i32) $super)) + (type $sub (struct_subtype (field (mut i32)) $super)) ;; CHECK: (func $func ;; CHECK-NEXT: (drop @@ -280,12 +280,12 @@ (module ;; As above, but add a write in the super, which prevents optimization. - ;; CHECK: (type $super (struct (field (mut i32)))) + ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $ref|$super|_=>_none (func (param (ref $super)))) + ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) func)) - ;; CHECK: (type $sub (struct (field (mut i32))) (extends $super)) - (type $sub (struct (field (mut i32))) (extends $super)) + ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) + (type $sub (struct_subtype (field (mut i32)) $super)) ;; CHECK: (func $func (param $x (ref $super)) ;; CHECK-NEXT: (drop @@ -325,13 +325,13 @@ (module ;; As above, but add a write in the sub, which prevents optimization. - ;; CHECK: (type $sub (struct (field (mut i32))) (extends $super)) + ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) - ;; CHECK: (type $ref|$sub|_=>_none (func (param (ref $sub)))) + ;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func)) - ;; CHECK: (type $super (struct (field (mut i32)))) + ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) (type $super (struct (field (mut i32)))) - (type $sub (struct (field (mut i32))) (extends $super)) + (type $sub (struct_subtype (field (mut i32)) $super)) ;; CHECK: (func $func (param $x (ref $sub)) ;; CHECK-NEXT: (struct.set $sub 0 diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast index 90ac8a418..0d79cca5b 100644 --- a/test/lit/passes/heap2local.wast +++ b/test/lit/passes/heap2local.wast @@ -2,10 +2,11 @@ ;; (remove-unused-names allows the pass to see that blocks flow values) ;; RUN: wasm-opt %s -all --remove-unused-names --heap2local -S -o - | filecheck %s -;; RUN: wasm-opt %s -all --remove-unused-names --heap2local --nominal -S -o - | filecheck %s +;; RUN: wasm-opt %s -all --remove-unused-names --heap2local --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $struct.A (struct (field (mut i32)) (field (mut f64)))) + ;; NOMNL: (type $struct.A (struct_subtype (field (mut i32)) (field (mut f64)) data)) (type $struct.A (struct (field (mut i32)) (field (mut f64)))) ;; CHECK: (type $struct.recursive (struct (field (mut (ref null $struct.recursive))))) @@ -13,9 +14,15 @@ ;; CHECK: (type $struct.nonnullable (struct (field (ref $struct.A)))) ;; CHECK: (type $struct.packed (struct (field (mut i8)))) + ;; NOMNL: (type $struct.recursive (struct_subtype (field (mut (ref null $struct.recursive))) data)) + + ;; NOMNL: (type $struct.nonnullable (struct_subtype (field (ref $struct.A)) data)) + + ;; NOMNL: (type $struct.packed (struct_subtype (field (mut i8)) data)) (type $struct.packed (struct (field (mut i8)))) ;; CHECK: (type $struct.nondefaultable (struct (field (rtt $struct.A)))) + ;; NOMNL: (type $struct.nondefaultable (struct_subtype (field (rtt $struct.A)) data)) (type $struct.nondefaultable (struct (field (rtt $struct.A)))) (type $struct.recursive (struct (field (mut (ref null $struct.recursive))))) @@ -40,6 +47,24 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $simple + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $simple ;; Other passes can remove such a trivial case of an unused allocation, but ;; we still optimize it. @@ -69,6 +94,25 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $to-local + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $to-local (local $ref (ref null $struct.A)) ;; While set to a local, this allocation has no get/set operations. Other @@ -105,6 +149,29 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $one-get + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $one-get ;; An allocation followed by an immediate get of a field. This is a non- ;; escaping allocation, with a use, so we can optimize it out. The @@ -143,6 +210,29 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $one-get-b + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $one-get-b ;; Similar to the above, but using a different field index. (drop @@ -175,6 +265,27 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $one-set + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $one-set ;; A simple optimizable allocation only used in one set. (struct.set $struct.A 0 @@ -194,6 +305,15 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $packed + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (struct.get_u $struct.packed 0 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.packed + ;; NOMNL-NEXT: (rtt.canon $struct.packed) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $packed ;; We do not optimize packed structs yet. (drop @@ -236,6 +356,37 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $with-init-values + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (local $2 i32) + ;; NOMNL-NEXT: (local $3 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (f64.const 3.14159) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $with-init-values ;; When we get values to initialize the struct with, assign them to the ;; proper locals. @@ -263,6 +414,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $ignore-unreachable + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $ignore-unreachable ;; An unreachable allocation is not worth trying to process; DCE should ;; remove it. @@ -287,6 +451,16 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $nondefaultable + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (struct.get $struct.nondefaultable 0 + ;; NOMNL-NEXT: (struct.new_with_rtt $struct.nondefaultable + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: (rtt.canon $struct.nondefaultable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $nondefaultable ;; We do not optimize structs with nondefaultable types that we cannot ;; handle, like rtts. @@ -327,6 +501,33 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $simple-one-local-set + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $simple-one-local-set (local $ref (ref null $struct.A)) ;; A simple optimizable allocation only used in one set, and also stored @@ -368,6 +569,31 @@ ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $simple-one-local-get (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $simple-one-local-get (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -384,6 +610,9 @@ ;; CHECK: (func $send-ref (param $0 (ref null $struct.A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) + ;; NOMNL: (func $send-ref (param $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) (func $send-ref (param (ref null $struct.A)) ) @@ -415,6 +644,34 @@ ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $safe-to-drop (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $safe-to-drop (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -445,6 +702,20 @@ ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $escape-via-call (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $send-ref + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $escape-via-call (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -493,6 +764,38 @@ ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $safe-to-drop-multiflow (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $safe-to-drop-multiflow (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -533,6 +836,24 @@ ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $escape-after-multiflow (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $send-ref + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $escape-after-multiflow (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -572,6 +893,23 @@ ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $non-exclusive-set (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (select (result (ref $struct.A)) + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $non-exclusive-set (result f64) (local $ref (ref null $struct.A)) ;; A set that receives two different allocations, and so we should not try @@ -620,6 +958,34 @@ ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $local-copies (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $local-copies (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -675,6 +1041,45 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $local-copies-2 + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $ref-2 (ref null $struct.A)) + ;; NOMNL-NEXT: (local $2 i32) + ;; NOMNL-NEXT: (local $3 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $local-copies-2 (local $ref (ref null $struct.A)) (local $ref-2 (ref null $struct.A)) @@ -731,6 +1136,37 @@ ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $local-copies-conditional (param $x i32) (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $2 i32) + ;; NOMNL-NEXT: (local $3 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $local-copies-conditional (param $x i32) (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -781,6 +1217,36 @@ ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $block-value (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (call $send-ref + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $block-value (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -817,6 +1283,23 @@ ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $non-exclusive-get (param $x i32) (result f64) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $non-exclusive-get (param $x i32) (result f64) (local $ref (ref null $struct.A)) (local.set $ref @@ -856,6 +1339,26 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) + ;; NOMNL: (func $tee (result i32) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) (func $tee (result i32) (local $ref (ref null $struct.A)) (struct.get $struct.A 0 @@ -886,6 +1389,24 @@ ;; CHECK-NEXT: (ref.null $struct.recursive) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $tee-set + ;; NOMNL-NEXT: (local $ref (ref null $struct.recursive)) + ;; NOMNL-NEXT: (local $1 (ref null $struct.recursive)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.recursive)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $tee-set (local $ref (ref null $struct.recursive)) ;; As above, but with a set, and also a recursive type. @@ -910,6 +1431,17 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $set-value + ;; NOMNL-NEXT: (local $ref (ref null $struct.recursive)) + ;; NOMNL-NEXT: (struct.set $struct.recursive 0 + ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (local.tee $ref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.recursive + ;; NOMNL-NEXT: (rtt.canon $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $set-value (local $ref (ref null $struct.recursive)) (struct.set $struct.recursive 0 @@ -953,6 +1485,35 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $initialize-with-reference + ;; NOMNL-NEXT: (local $0 (ref null $struct.recursive)) + ;; NOMNL-NEXT: (local $1 (ref null $struct.recursive)) + ;; NOMNL-NEXT: (local $2 (ref null $struct.recursive)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.recursive)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.recursive + ;; NOMNL-NEXT: (rtt.canon $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.recursive)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $initialize-with-reference (local $0 (ref null $struct.recursive)) (local.set $0 @@ -990,6 +1551,18 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) + ;; NOMNL: (func $escape-flow-out (result anyref) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (struct.set $struct.A 0 + ;; NOMNL-NEXT: (local.tee $ref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) (func $escape-flow-out (result anyref) (local $ref (ref null $struct.A)) (struct.set $struct.A 0 @@ -1018,6 +1591,20 @@ ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $escape-return (result anyref) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (struct.set $struct.A 0 + ;; NOMNL-NEXT: (local.tee $ref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $escape-return (result anyref) (local $ref (ref null $struct.A)) (struct.set $struct.A 0 @@ -1061,6 +1648,33 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $non-nullable (param $a (ref $struct.A)) + ;; NOMNL-NEXT: (local $1 (ref null $struct.A)) + ;; NOMNL-NEXT: (local $2 (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.nonnullable)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (local.get $a) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.nonnullable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.nonnullable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $non-nullable (param $a (ref $struct.A)) (drop ;; An optimizable case where the type is non-nullable, which requires @@ -1171,6 +1785,103 @@ ;; CHECK-NEXT: (br $outer) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $before-loop-use-multi (param $x i32) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $2 i32) + ;; NOMNL-NEXT: (local $3 f64) + ;; NOMNL-NEXT: (local $4 i32) + ;; NOMNL-NEXT: (local $5 f64) + ;; NOMNL-NEXT: (loop $outer + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $4 + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $5 + ;; NOMNL-NEXT: (f64.const 2.1828) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (local.get $4) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (local.get $5) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (f64.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (loop $inner + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (i32.add + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br_if $inner + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br $outer) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $before-loop-use-multi (param $x i32) (local $ref (ref null $struct.A)) ;; Allocate in a loop, and use that allocation multiple times in that loop @@ -1294,6 +2005,71 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $multi-separate + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (local $2 i32) + ;; NOMNL-NEXT: (local $3 f64) + ;; NOMNL-NEXT: (local $4 i32) + ;; NOMNL-NEXT: (local $5 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $4 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $5 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $5) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $multi-separate ;; Multiple independent things we can optimize. (drop @@ -1370,6 +2146,57 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $multi-separate-same-local-index + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (local $3 i32) + ;; NOMNL-NEXT: (local $4 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $4 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $multi-separate-same-local-index (local $ref (ref null $struct.A)) ;; Multiple independent things we can optimize that use the same local @@ -1448,6 +2275,58 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $multi-separate-different-local-index-overlapping-lifetimes + ;; NOMNL-NEXT: (local $ref1 (ref null $struct.A)) + ;; NOMNL-NEXT: (local $ref2 (ref null $struct.A)) + ;; NOMNL-NEXT: (local $2 i32) + ;; NOMNL-NEXT: (local $3 f64) + ;; NOMNL-NEXT: (local $4 i32) + ;; NOMNL-NEXT: (local $5 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $4 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $5 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $4) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $multi-separate-different-local-index-overlapping-lifetimes (local $ref1 (ref null $struct.A)) (local $ref2 (ref null $struct.A)) @@ -1494,6 +2373,25 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $get-through-block (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $get-through-block (result f64) (local $0 (ref null $struct.A)) (local.set $0 @@ -1537,6 +2435,25 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $branch-to-block (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $branch-to-block (result f64) (local $0 (ref null $struct.A)) (local.set $0 @@ -1594,6 +2511,41 @@ ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $branch-to-block-no-fallthrough (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (f64.const 2.1828) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $branch-to-block-no-fallthrough (result f64) (local $0 (ref null $struct.A)) (local.set $0 @@ -1644,6 +2596,33 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $two-branches (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (f64.const 2.1828) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $two-branches (result f64) (local $0 (ref null $struct.A)) (local.set $0 @@ -1699,6 +2678,33 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $two-branches-b (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (f64.const 2.1828) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $two-branches-b (result f64) (local $0 (ref null $struct.A)) (local.set $0 @@ -1749,6 +2755,27 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $br_if_flow (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (struct.new_default_with_rtt $struct.A + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct.A 1 + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (call $send-ref + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (f64.const 2.1828) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $br_if_flow (result f64) (local $0 (ref null $struct.A)) (local.set $0 @@ -1804,6 +2831,38 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $ref-as-non-null + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $ref-as-non-null (local $ref (ref null $struct.A)) (local.set $ref @@ -1856,6 +2915,34 @@ ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $ref-as-non-null-through-local (result i32) + ;; NOMNL-NEXT: (local $ref (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block (result i32) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $ref-as-non-null-through-local (result i32) (local $ref (ref null $struct.A)) (local.set $ref @@ -1917,6 +3004,44 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) + ;; NOMNL: (func $br_if-allocation (result f64) + ;; NOMNL-NEXT: (local $0 (ref null $struct.A)) + ;; NOMNL-NEXT: (local $1 i32) + ;; NOMNL-NEXT: (local $2 f64) + ;; NOMNL-NEXT: (local $3 i32) + ;; NOMNL-NEXT: (local $4 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_if $block + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $3 + ;; NOMNL-NEXT: (i32.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $4 + ;; NOMNL-NEXT: (f64.const 13.37) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (local.get $3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (local.get $4) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (rtt.canon $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (return + ;; NOMNL-NEXT: (f64.const 2.1828) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) (func $br_if-allocation (result f64) (local $0 (ref null $struct.A)) (struct.get $struct.A 1 @@ -1953,6 +3078,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $simple-no-rtt + ;; NOMNL-NEXT: (local $0 i32) + ;; NOMNL-NEXT: (local $1 f64) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (f64.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $simple-no-rtt (drop ;; This allocation has no rtt, so we have nothing to drop from it when diff --git a/test/lit/passes/inlining_all-features.wast b/test/lit/passes/inlining_all-features.wast index b3089baeb..fce3cc460 100644 --- a/test/lit/passes/inlining_all-features.wast +++ b/test/lit/passes/inlining_all-features.wast @@ -1,7 +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 --inlining --all-features -S -o - | filecheck %s -;; RUN: foreach %s %t wasm-opt --inlining --all-features --nominal -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --inlining --all-features --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $none_=>_none (func)) @@ -11,6 +11,13 @@ ;; CHECK: (elem declare func $foo) ;; CHECK: (export "ref_func_test" (func $ref_func_test)) + ;; NOMNL: (type $none_=>_none (func_subtype func)) + + ;; NOMNL: (type $none_=>_funcref (func_subtype (result funcref) func)) + + ;; NOMNL: (elem declare func $foo) + + ;; NOMNL: (export "ref_func_test" (func $ref_func_test)) (export "ref_func_test" (func $ref_func_test)) ;; $foo should not be removed after being inlined, because there is 'ref.func' @@ -18,6 +25,9 @@ ;; CHECK: (func $foo ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) + ;; NOMNL: (func $foo + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) (func $foo) ;; CHECK: (func $ref_func_test (result funcref) @@ -28,6 +38,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: ) + ;; NOMNL: (func $ref_func_test (result funcref) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (block $__inlined_func$foo + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.func $foo) + ;; NOMNL-NEXT: ) (func $ref_func_test (result funcref) (call $foo) (ref.func $foo) @@ -40,11 +58,17 @@ ;; CHECK: (type $none_=>_i32 (func (result i32))) ;; CHECK: (global $global$0 (mut funcref) (ref.func $0)) + ;; NOMNL: (type $none_=>_i32 (func_subtype (result i32) func)) + + ;; NOMNL: (global $global$0 (mut funcref) (ref.func $0)) (global $global$0 (mut funcref) (ref.func $0)) ;; CHECK: (func $0 (result i32) ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) + ;; NOMNL: (func $0 (result i32) + ;; NOMNL-NEXT: (i32.const 1337) + ;; NOMNL-NEXT: ) (func $0 (result i32) (i32.const 1337) ) @@ -54,6 +78,11 @@ ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $1 (result i32) + ;; NOMNL-NEXT: (block $__inlined_func$0 (result i32) + ;; NOMNL-NEXT: (i32.const 1337) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $1 (result i32) (call $0) ) @@ -65,11 +94,17 @@ ;; CHECK: (type $none_=>_none (func)) ;; CHECK: (start $0) + ;; NOMNL: (type $none_=>_none (func_subtype func)) + + ;; NOMNL: (start $0) (start $0) ;; CHECK: (func $0 ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) + ;; NOMNL: (func $0 + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) (func $0 (nop) ) @@ -79,6 +114,11 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $1 + ;; NOMNL-NEXT: (block $__inlined_func$0 + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $1 (call $0) ) @@ -87,9 +127,11 @@ ;; inline a return_call_ref (module ;; CHECK: (type $none_=>_none (func)) + ;; NOMNL: (type $none_=>_none (func_subtype func)) (type $none_=>_none (func)) ;; CHECK: (export "func_36_invoker" (func $1)) + ;; NOMNL: (export "func_36_invoker" (func $1)) (export "func_36_invoker" (func $1)) (func $0 @@ -108,6 +150,17 @@ ;; CHECK-NEXT: (br $__inlined_func$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $1 + ;; NOMNL-NEXT: (block $__inlined_func$0 + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (call_ref + ;; NOMNL-NEXT: (ref.null $none_=>_none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br $__inlined_func$0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br $__inlined_func$0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $1 (call $0) ) @@ -134,6 +187,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (type $none_=>_ref|func| (func_subtype (result (ref func)) func)) + + ;; NOMNL: (elem declare func $1) + + ;; NOMNL: (func $1 (result (ref func)) + ;; NOMNL-NEXT: (local $0 funcref) + ;; NOMNL-NEXT: (block $__inlined_func$0 (result (ref func)) + ;; NOMNL-NEXT: (local.set $0 + ;; NOMNL-NEXT: (ref.func $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $1 (result (ref func)) (call $0 (ref.func $1) @@ -144,6 +212,7 @@ ;; never inline an rtt parameter, as those cannot be handled as locals (module ;; CHECK: (type $struct (struct )) + ;; NOMNL: (type $struct (struct_subtype data)) (type $struct (struct)) ;; CHECK: (type $rtt_$struct_=>_none (func (param (rtt $struct)))) @@ -152,6 +221,13 @@ ;; CHECK: (func $0 (param $rtt (rtt $struct)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) + ;; NOMNL: (type $rtt_$struct_=>_none (func_subtype (param (rtt $struct)) func)) + + ;; NOMNL: (type $none_=>_none (func_subtype func)) + + ;; NOMNL: (func $0 (param $rtt (rtt $struct)) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) (func $0 (param $rtt (rtt $struct)) ) ;; CHECK: (func $1 @@ -159,6 +235,11 @@ ;; CHECK-NEXT: (rtt.canon $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $1 + ;; NOMNL-NEXT: (call $0 + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $1 (call $0 (rtt.canon $struct) diff --git a/test/lit/passes/instrument-memory-gc.wast b/test/lit/passes/instrument-memory-gc.wast index 1866bdcb8..bbc55ba77 100644 --- a/test/lit/passes/instrument-memory-gc.wast +++ b/test/lit/passes/instrument-memory-gc.wast @@ -1,7 +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 --instrument-memory -all -S -o - | filecheck %s -;; RUN: foreach %s %t wasm-opt --instrument-memory --nominal -all -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --instrument-memory --nominal -all -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) @@ -13,6 +13,15 @@ ;; CHECK: (type $i32_f64_=>_f64 (func (param i32 f64) (result f64))) ;; CHECK: (type $struct (struct (field (mut i32)) (field f32) (field $named f64))) + ;; NOMNL: (type $i32_i32_=>_i32 (func_subtype (param i32 i32) (result i32) func)) + + ;; NOMNL: (type $i32_i64_=>_i64 (func_subtype (param i32 i64) (result i64) func)) + + ;; NOMNL: (type $i32_f32_=>_f32 (func_subtype (param i32 f32) (result f32) func)) + + ;; NOMNL: (type $i32_f64_=>_f64 (func_subtype (param i32 f64) (result f64) func)) + + ;; NOMNL: (type $struct (struct_subtype (field (mut i32)) (field f32) (field $named f64) data)) (type $struct (struct (field (mut i32)) (field f32) @@ -25,6 +34,13 @@ ;; CHECK: (type $ref|$array|_=>_none (func (param (ref $array)))) ;; CHECK: (type $array (array (mut f64))) + ;; NOMNL: (type $i32_i32_i32_i32_=>_i32 (func_subtype (param i32 i32 i32 i32) (result i32) func)) + + ;; NOMNL: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func)) + + ;; NOMNL: (type $ref|$array|_=>_none (func_subtype (param (ref $array)) func)) + + ;; NOMNL: (type $array (array_subtype (mut f64) data)) (type $array (array (mut f64))) ;; CHECK: (import "env" "load_ptr" (func $load_ptr (param i32 i32 i32 i32) (result i32))) @@ -116,6 +132,95 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (import "env" "load_ptr" (func $load_ptr (param i32 i32 i32 i32) (result i32))) + + ;; NOMNL: (import "env" "load_val_i32" (func $load_val_i32 (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "load_val_i64" (func $load_val_i64 (param i32 i64) (result i64))) + + ;; NOMNL: (import "env" "load_val_f32" (func $load_val_f32 (param i32 f32) (result f32))) + + ;; NOMNL: (import "env" "load_val_f64" (func $load_val_f64 (param i32 f64) (result f64))) + + ;; NOMNL: (import "env" "store_ptr" (func $store_ptr (param i32 i32 i32 i32) (result i32))) + + ;; NOMNL: (import "env" "store_val_i32" (func $store_val_i32 (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "store_val_i64" (func $store_val_i64 (param i32 i64) (result i64))) + + ;; NOMNL: (import "env" "store_val_f32" (func $store_val_f32 (param i32 f32) (result f32))) + + ;; NOMNL: (import "env" "store_val_f64" (func $store_val_f64 (param i32 f64) (result f64))) + + ;; NOMNL: (import "env" "struct_get_val_i32" (func $struct_get_val_i32 (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "struct_get_val_i64" (func $struct_get_val_i64 (param i32 i64) (result i64))) + + ;; NOMNL: (import "env" "struct_get_val_f32" (func $struct_get_val_f32 (param i32 f32) (result f32))) + + ;; NOMNL: (import "env" "struct_get_val_f64" (func $struct_get_val_f64 (param i32 f64) (result f64))) + + ;; NOMNL: (import "env" "struct_set_val_i32" (func $struct_set_val_i32 (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "struct_set_val_i64" (func $struct_set_val_i64 (param i32 i64) (result i64))) + + ;; NOMNL: (import "env" "struct_set_val_f32" (func $struct_set_val_f32 (param i32 f32) (result f32))) + + ;; NOMNL: (import "env" "struct_set_val_f64" (func $struct_set_val_f64 (param i32 f64) (result f64))) + + ;; NOMNL: (import "env" "array_get_val_i32" (func $array_get_val_i32 (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "array_get_val_i64" (func $array_get_val_i64 (param i32 i64) (result i64))) + + ;; NOMNL: (import "env" "array_get_val_f32" (func $array_get_val_f32 (param i32 f32) (result f32))) + + ;; NOMNL: (import "env" "array_get_val_f64" (func $array_get_val_f64 (param i32 f64) (result f64))) + + ;; NOMNL: (import "env" "array_set_val_i32" (func $array_set_val_i32 (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "array_set_val_i64" (func $array_set_val_i64 (param i32 i64) (result i64))) + + ;; NOMNL: (import "env" "array_set_val_f32" (func $array_set_val_f32 (param i32 f32) (result f32))) + + ;; NOMNL: (import "env" "array_set_val_f64" (func $array_set_val_f64 (param i32 f64) (result f64))) + + ;; NOMNL: (import "env" "array_get_index" (func $array_get_index (param i32 i32) (result i32))) + + ;; NOMNL: (import "env" "array_set_index" (func $array_set_index (param i32 i32) (result i32))) + + ;; NOMNL: (func $structs (param $x (ref $struct)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $struct_get_val_i32 + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $struct_get_val_f32 + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: (struct.get $struct 1 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $struct_get_val_f64 + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: (struct.get $struct $named + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.set $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (call $struct_set_val_i32 + ;; NOMNL-NEXT: (i32.const 3) + ;; NOMNL-NEXT: (i32.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $structs (param $x (ref $struct)) (drop (struct.get $struct 0 (local.get $x)) @@ -154,6 +259,31 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $arrays (param $x (ref $array)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $array_get_val_f64 + ;; NOMNL-NEXT: (i32.const 5) + ;; NOMNL-NEXT: (array.get $array + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (call $array_get_index + ;; NOMNL-NEXT: (i32.const 4) + ;; NOMNL-NEXT: (i32.const 10) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (array.set $array + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (call $array_set_index + ;; NOMNL-NEXT: (i32.const 6) + ;; NOMNL-NEXT: (i32.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $array_set_val_f64 + ;; NOMNL-NEXT: (i32.const 7) + ;; NOMNL-NEXT: (f64.const 3.14159) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $arrays (param $x (ref $array)) (drop (array.get $array (local.get $x) (i32.const 10)) diff --git a/test/lit/passes/local-subtyping-nn.wast b/test/lit/passes/local-subtyping-nn.wast index bcf13f7c2..290fe032d 100644 --- a/test/lit/passes/local-subtyping-nn.wast +++ b/test/lit/passes/local-subtyping-nn.wast @@ -2,13 +2,15 @@ ;; RUN: wasm-opt %s --local-subtyping -all --enable-gc-nn-locals -S -o - \ ;; RUN: | filecheck %s ;; RUN: wasm-opt %s --local-subtyping -all --enable-gc-nn-locals --nominal -S -o - \ -;; RUN: | filecheck %s +;; RUN: | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $struct (struct )) + ;; NOMNL: (type $struct (struct_subtype data)) (type $struct (struct)) ;; CHECK: (import "out" "i32" (func $i32 (result i32))) + ;; NOMNL: (import "out" "i32" (func $i32 (result i32))) (import "out" "i32" (func $i32 (result i32))) ;; CHECK: (func $non-nullable @@ -26,6 +28,21 @@ ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $non-nullable + ;; NOMNL-NEXT: (local $x (ref $struct)) + ;; NOMNL-NEXT: (local $y (ref $none_=>_i32)) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $y + ;; NOMNL-NEXT: (ref.func $i32) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $non-nullable (local $x (ref null $struct)) (local $y anyref) @@ -58,6 +75,20 @@ ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $uses-default (param $i i32) + ;; NOMNL-NEXT: (local $x (ref null $struct)) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $i) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $uses-default (param $i i32) (local $x (ref null any)) (if diff --git a/test/lit/passes/name-types.wast b/test/lit/passes/name-types.wast index 39cc00423..12fe549ea 100644 --- a/test/lit/passes/name-types.wast +++ b/test/lit/passes/name-types.wast @@ -1,6 +1,6 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; RUN: wasm-opt %s -all --name-types -S -o - | filecheck %s -;; RUN: wasm-opt %s -all --name-types --nominal -S -o - | filecheck %s +;; RUN: wasm-opt %s -all --name-types --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; An obnoxious name that will be renamed. @@ -12,11 +12,19 @@ ;; CHECK: (type $type$1 (struct )) ;; CHECK: (type $reasonable-name (struct (field i32))) + ;; NOMNL: (type $type$0 (func_subtype (param (ref $type$1) (ref $reasonable-name)) func)) + + ;; NOMNL: (type $type$1 (struct_subtype data)) + + ;; NOMNL: (type $reasonable-name (struct_subtype (field i32) data)) (type $reasonable-name (struct (field i32))) ;; CHECK: (func $foo (param $x (ref $type$1)) (param $y (ref $reasonable-name)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) + ;; NOMNL: (func $foo (param $x (ref $type$1)) (param $y (ref $reasonable-name)) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) (func $foo ;; Use the types to keep them alive. (param $x (ref $obnoxious-super-long-type-name_____________________________1)) diff --git a/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast b/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast index 5bbec4b64..0477abe79 100644 --- a/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast +++ b/test/lit/passes/optimize-instructions-call_ref-roundtrip.wast @@ -10,16 +10,16 @@ ;; distinct nominally. The three tables will use different ones, and the ;; emitted call_indirects should use the corresponding ones. - ;; CHECK: (type $v1 (func)) + ;; CHECK: (type $v1 (func_subtype func)) (type $v1 (func)) - ;; CHECK: (type $v2 (func)) + ;; CHECK: (type $v2 (func_subtype func)) (type $v2 (func)) - ;; CHECK: (type $v3 (func)) + ;; CHECK: (type $v3 (func_subtype func)) (type $v3 (func)) - ;; CHECK: (type $i32_=>_none (func (param i32))) + ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) ;; CHECK: (table $table-1 10 (ref null $v1)) (table $table-1 10 (ref null $v1)) diff --git a/test/lit/passes/optimize-instructions-gc-iit.wast b/test/lit/passes/optimize-instructions-gc-iit.wast index d6bb9eb31..9923bf89b 100644 --- a/test/lit/passes/optimize-instructions-gc-iit.wast +++ b/test/lit/passes/optimize-instructions-gc-iit.wast @@ -9,16 +9,16 @@ (module ;; CHECK: (type $parent (struct (field i32))) - ;; NOMNL: (type $parent (struct (field i32))) - ;; NOMNL-TNH: (type $parent (struct (field i32))) + ;; NOMNL: (type $parent (struct_subtype (field i32) data)) + ;; NOMNL-TNH: (type $parent (struct_subtype (field i32) data)) (type $parent (struct (field i32))) ;; CHECK: (type $child (struct (field i32) (field f64))) - ;; NOMNL: (type $child (struct (field i32) (field f64)) (extends $parent)) - ;; NOMNL-TNH: (type $child (struct (field i32) (field f64)) (extends $parent)) - (type $child (struct (field i32) (field f64)) (extends $parent)) + ;; NOMNL: (type $child (struct_subtype (field i32) (field f64) $parent)) + ;; NOMNL-TNH: (type $child (struct_subtype (field i32) (field f64) $parent)) + (type $child (struct_subtype (field i32) (field f64) $parent)) ;; CHECK: (type $other (struct (field i64) (field f32))) - ;; NOMNL: (type $other (struct (field i64) (field f32))) - ;; NOMNL-TNH: (type $other (struct (field i64) (field f32))) + ;; NOMNL: (type $other (struct_subtype (field i64) (field f32) data)) + ;; NOMNL-TNH: (type $other (struct_subtype (field i64) (field f32) data)) (type $other (struct (field i64) (field f32))) ;; CHECK: (func $foo diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index ab973ffae..47d2a17bc 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -6,7 +6,7 @@ (module ;; CHECK: (type $struct (struct (field $i8 (mut i8)) (field $i16 (mut i16)) (field $i32 (mut i32)) (field $i64 (mut i64)))) - ;; NOMNL: (type $struct (struct (field $i8 (mut i8)) (field $i16 (mut i16)) (field $i32 (mut i32)) (field $i64 (mut i64)))) + ;; NOMNL: (type $struct (struct_subtype (field $i8 (mut i8)) (field $i16 (mut i16)) (field $i32 (mut i32)) (field $i64 (mut i64)) data)) (type $struct (struct (field $i8 (mut i8)) (field $i16 (mut i16)) @@ -15,28 +15,28 @@ )) ;; CHECK: (type $A (struct (field i32))) - ;; NOMNL: (type $A (struct (field i32))) + ;; NOMNL: (type $A (struct_subtype (field i32) data)) (type $A (struct (field i32))) ;; CHECK: (type $array (array (mut i8))) - ;; NOMNL: (type $array (array (mut i8))) + ;; NOMNL: (type $array (array_subtype (mut i8) data)) (type $array (array (mut i8))) ;; CHECK: (type $B (struct (field i32) (field i32) (field f32))) - ;; NOMNL: (type $B (struct (field i32) (field i32) (field f32)) (extends $A)) - (type $B (struct (field i32) (field i32) (field f32)) (extends $A)) + ;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A)) + (type $B (struct_subtype (field i32) (field i32) (field f32) $A)) ;; CHECK: (type $B-child (struct (field i32) (field i32) (field f32) (field i64))) - ;; NOMNL: (type $B-child (struct (field i32) (field i32) (field f32) (field i64)) (extends $B)) - (type $B-child (struct (field i32) (field i32) (field f32) (field i64)) (extends $B)) + ;; NOMNL: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B)) + (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B)) ;; CHECK: (type $empty (struct )) - ;; NOMNL: (type $empty (struct )) + ;; NOMNL: (type $empty (struct_subtype data)) (type $empty (struct)) ;; CHECK: (type $C (struct (field i32) (field i32) (field f64))) - ;; NOMNL: (type $C (struct (field i32) (field i32) (field f64)) (extends $A)) - (type $C (struct (field i32) (field i32) (field f64)) (extends $A)) + ;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A)) + (type $C (struct_subtype (field i32) (field i32) (field f64) $A)) ;; CHECK: (import "env" "get-i32" (func $get-i32 (result i32))) ;; NOMNL: (import "env" "get-i32" (func $get-i32 (result i32))) diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast index c12e86635..2d50fcaa6 100644 --- a/test/lit/passes/precompute-gc.wast +++ b/test/lit/passes/precompute-gc.wast @@ -2,24 +2,29 @@ ;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate --fuzz-exec -all -S -o - \ ;; RUN: | filecheck %s ;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate --fuzz-exec -all --nominal -S -o - \ -;; RUN: | filecheck %s +;; RUN: | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $empty (struct )) + ;; NOMNL: (type $empty (struct_subtype data)) + (type $empty (struct)) ;; CHECK: (type $struct (struct (field (mut i32)))) + ;; NOMNL: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - (type $empty (struct)) ;; two incompatible struct types (type $A (struct (field (mut f32)))) ;; CHECK: (type $B (struct (field (mut f64)))) + ;; NOMNL: (type $B (struct_subtype (field (mut f64)) data)) (type $B (struct (field (mut f64)))) ;; CHECK: (type $func-return-i32 (func (result i32))) + ;; NOMNL: (type $func-return-i32 (func_subtype (result i32) func)) (type $func-return-i32 (func (result i32))) ;; CHECK: (import "fuzzing-support" "log-i32" (func $log (param i32))) + ;; NOMNL: (import "fuzzing-support" "log-i32" (func $log (param i32))) (import "fuzzing-support" "log-i32" (func $log (param i32))) ;; CHECK: (func $test-fallthrough (result i32) @@ -34,6 +39,18 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) + ;; NOMNL: (func $test-fallthrough (result i32) + ;; NOMNL-NEXT: (local $x funcref) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (block (result funcref) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $test-fallthrough) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null func) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) (func $test-fallthrough (result i32) (local $x funcref) (local.set $x @@ -88,6 +105,40 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $load-from-struct + ;; NOMNL-NEXT: (local $x (ref null $struct)) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (struct.new_with_rtt $struct + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (struct.new_with_rtt $struct + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.set $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (i32.const 3) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $load-from-struct (local $x (ref null $struct)) (local.set $x @@ -143,6 +194,29 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $load-from-struct-bad-merge (param $i i32) + ;; NOMNL-NEXT: (local $x (ref null $struct)) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $i) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (struct.new_with_rtt $struct + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (struct.new_with_rtt $struct + ;; NOMNL-NEXT: (i32.const 2) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $load-from-struct-bad-merge (param $i i32) (local $x (ref null $struct)) ;; a merge of two different $x values cannot be precomputed @@ -176,6 +250,17 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $modify-gc-heap (param $x (ref null $struct)) + ;; NOMNL-NEXT: (struct.set $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (i32.add + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $modify-gc-heap (param $x (ref null $struct)) (struct.set $struct 0 (local.get $x) @@ -206,6 +291,23 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $load-from-struct-bad-escape + ;; NOMNL-NEXT: (local $x (ref null $struct)) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (struct.new_with_rtt $struct + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $modify-gc-heap + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $load-from-struct-bad-escape (export "test") (local $x (ref null $struct)) (local.set $x @@ -228,6 +330,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $load-from-struct-bad-arrive (param $x (ref null $struct)) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $load-from-struct-bad-arrive (param $x (ref null $struct)) ;; a parameter cannot be precomputed (call $log @@ -259,6 +368,31 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $ref-comparisons (param $x (ref null $struct)) (param $y (ref null $struct)) + ;; NOMNL-NEXT: (local $z (ref null $struct)) + ;; NOMNL-NEXT: (local $w (ref null $struct)) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $log + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $ref-comparisons (param $x (ref null $struct)) (param $y (ref null $struct)) @@ -310,6 +444,24 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) + ;; NOMNL: (func $new-ref-comparisons (result i32) + ;; NOMNL-NEXT: (local $x (ref null $struct)) + ;; NOMNL-NEXT: (local $y (ref null $struct)) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (struct.new_with_rtt $struct + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $y + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) (func $new-ref-comparisons (result i32) (local $x (ref null $struct)) (local $y (ref null $struct)) @@ -349,6 +501,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-equal (result i32) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.tee $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) (func $propagate-equal (result i32) (local $tempresult i32) (local $tempref (ref null $empty)) @@ -376,6 +543,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-unequal (result i32) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) (func $propagate-unequal (result i32) (local $tempresult i32) (local $tempref (ref null $empty)) @@ -410,6 +585,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $tempresult) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-uncertain-param (param $input (ref $empty)) (result i32) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $input) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $tempresult) + ;; NOMNL-NEXT: ) (func $propagate-uncertain-param (param $input (ref $empty)) (result i32) (local $tempresult i32) (local $tempref (ref null $empty)) @@ -436,6 +624,16 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $tempresult) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-different-params (param $input1 (ref $empty)) (param $input2 (ref $empty)) (result i32) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $input1) + ;; NOMNL-NEXT: (local.get $input2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $tempresult) + ;; NOMNL-NEXT: ) (func $propagate-different-params (param $input1 (ref $empty)) (param $input2 (ref $empty)) (result i32) (local $tempresult i32) (local.set $tempresult @@ -458,6 +656,16 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $tempresult) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-same-param (param $input (ref $empty)) (result i32) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $input) + ;; NOMNL-NEXT: (local.get $input) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $tempresult) + ;; NOMNL-NEXT: ) (func $propagate-same-param (param $input (ref $empty)) (result i32) (local $tempresult i32) (local.set $tempresult @@ -501,6 +709,36 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $tempresult) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-uncertain-local (result i32) + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local $stashedref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $stashedref + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: (local.get $stashedref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $tempresult) + ;; NOMNL-NEXT: ) (func $propagate-uncertain-local (result i32) (local $tempresult i32) (local $tempref (ref null $empty)) @@ -565,6 +803,37 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-uncertain-loop + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local $stashedref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $stashedref + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (loop $loop + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: (local.get $stashedref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br_if $loop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (local.get $tempresult) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $propagate-uncertain-loop (local $tempresult i32) (local $tempref (ref null $empty)) @@ -622,6 +891,29 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-certain-loop + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local $stashedref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $stashedref + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (loop $loop + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br_if $loop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $propagate-certain-loop (local $tempresult i32) (local $tempref (ref null $empty)) @@ -674,6 +966,29 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-certain-loop-2 + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local $stashedref (ref null $empty)) + ;; NOMNL-NEXT: (loop $loop + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $stashedref + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br_if $loop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $propagate-certain-loop-2 (local $tempresult i32) (local $tempref (ref null $empty)) @@ -734,6 +1049,37 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $propagate-possibly-certain-loop + ;; NOMNL-NEXT: (local $tempresult i32) + ;; NOMNL-NEXT: (local $tempref (ref null $empty)) + ;; NOMNL-NEXT: (local $stashedref (ref null $empty)) + ;; NOMNL-NEXT: (loop $loop + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempref + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $stashedref + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $tempresult + ;; NOMNL-NEXT: (ref.eq + ;; NOMNL-NEXT: (local.get $tempref) + ;; NOMNL-NEXT: (local.get $stashedref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br_if $loop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (local.get $tempresult) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $propagate-possibly-certain-loop (local $tempresult i32) (local $tempref (ref null $empty)) @@ -773,6 +1119,9 @@ ;; CHECK: (func $helper (param $0 i32) (result i32) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; NOMNL: (func $helper (param $0 i32) (result i32) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) (func $helper (param i32) (result i32) (unreachable) ) @@ -788,6 +1137,17 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $odd-cast-and-get + ;; NOMNL-NEXT: (local $temp (ref null $B)) + ;; NOMNL-NEXT: (local.set $temp + ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (struct.get $B 0 + ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $odd-cast-and-get (local $temp (ref null $B)) ;; Try to cast a null of A to B. While the types are incompatible, ref.cast @@ -823,6 +1183,20 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $odd-cast-and-get-tuple + ;; NOMNL-NEXT: (local $temp ((ref null $B) i32)) + ;; NOMNL-NEXT: (local.set $temp + ;; NOMNL-NEXT: (tuple.make + ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (i32.const 10) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (struct.get $B 0 + ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $odd-cast-and-get-tuple (local $temp ((ref null $B) i32)) ;; As above, but with a tuple. @@ -847,6 +1221,9 @@ ;; CHECK: (func $receive-f64 (param $0 f64) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; NOMNL: (func $receive-f64 (param $0 f64) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) (func $receive-f64 (param f64) (unreachable) ) @@ -864,6 +1241,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $odd-cast-and-get-non-null (param $temp (ref $func-return-i32)) + ;; NOMNL-NEXT: (local.set $temp + ;; NOMNL-NEXT: (ref.cast + ;; NOMNL-NEXT: (ref.func $receive-f64) + ;; NOMNL-NEXT: (rtt.canon $func-return-i32) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call_ref + ;; NOMNL-NEXT: (local.get $temp) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $odd-cast-and-get-non-null (param $temp (ref $func-return-i32)) ;; Try to cast a function to an incompatible type. (local.set $temp @@ -889,6 +1279,14 @@ ;; CHECK-NEXT: (rtt.canon $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $new_block_unreachable (result anyref) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (rtt.canon $struct) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $new_block_unreachable (result anyref) (struct.new_with_rtt $struct ;; The value is a block with an unreachable. precompute will get rid of the @@ -914,6 +1312,19 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $br_on_cast-on-creation-rtt (result (ref $empty)) + ;; NOMNL-NEXT: (block $label (result (ref $empty)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_on_cast $label + ;; NOMNL-NEXT: (struct.new_default_with_rtt $empty + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (rtt.canon $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $br_on_cast-on-creation-rtt (result (ref $empty)) (block $label (result (ref $empty)) (drop @@ -941,6 +1352,16 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $br_on_cast-on-creation-nortt (result (ref $empty)) + ;; NOMNL-NEXT: (block $label (result (ref $empty)) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_on_cast_static $label $empty + ;; NOMNL-NEXT: (struct.new_default $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $br_on_cast-on-creation-nortt (result (ref $empty)) (block $label (result (ref $empty)) (drop @@ -985,6 +1406,38 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $ref.is_null (param $param i32) + ;; NOMNL-NEXT: (local $ref (ref null $empty)) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (struct.new_default $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (ref.null $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (i32.const 1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (if + ;; NOMNL-NEXT: (local.get $param) + ;; NOMNL-NEXT: (local.set $ref + ;; NOMNL-NEXT: (struct.new_default $empty) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $helper + ;; NOMNL-NEXT: (ref.is_null + ;; NOMNL-NEXT: (local.get $ref) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $ref.is_null (param $param i32) (local $ref (ref null $empty)) ;; Test ref.null on references, and also test that we can infer multiple diff --git a/test/lit/passes/roundtrip-gc-types.wast b/test/lit/passes/roundtrip-gc-types.wast index c5ed84d54..d14415f3b 100644 --- a/test/lit/passes/roundtrip-gc-types.wast +++ b/test/lit/passes/roundtrip-gc-types.wast @@ -8,19 +8,19 @@ (module ;; CHECK: (type $A (struct (field (ref $C)))) - ;; NOMNL: (type $A (struct (field (ref $C)))) + ;; NOMNL: (type $A (struct_subtype (field (ref $C)) data)) (type $A (struct (field (ref $C)))) ;; CHECK: (type $C (struct (field (mut (ref $B))))) ;; CHECK: (type $B (func (param (ref $A)) (result (ref $B)))) - ;; NOMNL: (type $C (struct (field (mut (ref $B))))) + ;; NOMNL: (type $C (struct_subtype (field (mut (ref $B))) data)) - ;; NOMNL: (type $B (func (param (ref $A)) (result (ref $B)))) + ;; NOMNL: (type $B (func_subtype (param (ref $A)) (result (ref $B)) func)) (type $B (func (param (ref $A)) (result (ref $B)))) (type $C (struct (field (mut (ref $B))))) ;; CHECK: (type $D (struct (field (ref $C)) (field (ref $A)))) - ;; NOMNL: (type $D (struct (field (ref $C)) (field (ref $A))) (extends $A)) - (type $D (struct (field (ref $C)) (field (ref $A))) (extends $A)) + ;; NOMNL: (type $D (struct_subtype (field (ref $C)) (field (ref $A)) $A)) + (type $D (struct_subtype (field (ref $C)) (field (ref $A)) $A)) ;; CHECK: (global $g0 (rtt 0 $A) (rtt.canon $A)) ;; NOMNL: (global $g0 (rtt 0 $A) (rtt.canon $A)) (global $g0 (rtt 0 $A) (rtt.canon $A)) diff --git a/test/lit/passes/simplify-locals-gc.wast b/test/lit/passes/simplify-locals-gc.wast index 97891aca4..380bcc16b 100644 --- a/test/lit/passes/simplify-locals-gc.wast +++ b/test/lit/passes/simplify-locals-gc.wast @@ -2,13 +2,15 @@ ;; RUN: wasm-opt %s --simplify-locals -all -S -o - \ ;; RUN: | filecheck %s ;; RUN: wasm-opt %s --simplify-locals -all --nominal -S -o - \ -;; RUN: | filecheck %s +;; RUN: | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type $struct (struct (field (mut i32)))) + ;; NOMNL: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (field (mut i32)))) ;; CHECK: (type $struct-immutable (struct (field i32))) + ;; NOMNL: (type $struct-immutable (struct_subtype (field i32) data)) (type $struct-immutable (struct (field i32))) ;; Writes to heap objects cannot be reordered with reads. @@ -25,6 +27,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $temp) ;; CHECK-NEXT: ) + ;; NOMNL: (func $no-reorder-past-write (param $x (ref $struct)) (result i32) + ;; NOMNL-NEXT: (local $temp i32) + ;; NOMNL-NEXT: (local.set $temp + ;; NOMNL-NEXT: (struct.get $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.set $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (i32.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $temp) + ;; NOMNL-NEXT: ) (func $no-reorder-past-write (param $x (ref $struct)) (result i32) (local $temp i32) (local.set $temp @@ -50,6 +65,17 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $reorder-past-write-if-immutable (param $x (ref $struct)) (param $y (ref $struct-immutable)) (result i32) + ;; NOMNL-NEXT: (local $temp i32) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: (struct.set $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (i32.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $struct-immutable 0 + ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $reorder-past-write-if-immutable (param $x (ref $struct)) (param $y (ref $struct-immutable)) (result i32) (local $temp i32) (local.set $temp @@ -79,6 +105,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $temp) ;; CHECK-NEXT: ) + ;; NOMNL: (func $unreachable-struct.get (param $x (ref $struct)) (param $y (ref $struct-immutable)) (result i32) + ;; NOMNL-NEXT: (local $temp i32) + ;; NOMNL-NEXT: (local.tee $temp + ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.set $struct 0 + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (i32.const 42) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.get $temp) + ;; NOMNL-NEXT: ) (func $unreachable-struct.get (param $x (ref $struct)) (param $y (ref $struct-immutable)) (result i32) (local $temp i32) ;; As above, but the get's ref is unreachable. This tests we do not hit an @@ -119,6 +160,28 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; NOMNL: (func $no-block-values-if-br_on + ;; NOMNL-NEXT: (local $temp anyref) + ;; NOMNL-NEXT: (block $block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (br_on_null $block + ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $temp + ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (br $block) + ;; NOMNL-NEXT: (local.set $temp + ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.get $temp) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) (func $no-block-values-if-br_on (local $temp (ref null any)) (block $block diff --git a/test/lit/tail-call.wast b/test/lit/tail-call.wast index f65ecf165..c5e863ff9 100644 --- a/test/lit/tail-call.wast +++ b/test/lit/tail-call.wast @@ -8,7 +8,7 @@ (module ;; CHECK: (type $void (func)) - ;; NOMNL: (type $void (func)) + ;; NOMNL: (type $void (func_subtype func)) (type $void (func)) ;; CHECK: (table $t 1 1 funcref) @@ -47,20 +47,20 @@ ;; Check GC types and subtyping (module ;; CHECK: (type $return-B (func (result (ref $B)))) - ;; NOMNL: (type $return-B (func (result (ref $B)))) + ;; NOMNL: (type $return-B (func_subtype (result (ref $B)) func)) (type $return-B (func (result (ref $B)))) ;; CHECK: (type $return-A (func (result (ref null $A)))) - ;; NOMNL: (type $return-A (func (result (ref null $A)))) + ;; NOMNL: (type $return-A (func_subtype (result (ref null $A)) func)) (type $return-A (func (result (ref null $A)))) ;; CHECK: (type $A (struct (field i32))) - ;; NOMNL: (type $A (struct (field i32))) + ;; NOMNL: (type $A (struct_subtype (field i32) data)) (type $A (struct i32)) ;; CHECK: (type $B (struct (field i32) (field i32))) - ;; NOMNL: (type $B (struct (field i32) (field i32)) (extends $A)) - (type $B (struct i32 i32) (extends $A)) + ;; NOMNL: (type $B (struct_subtype (field i32) (field i32) $A)) + (type $B (struct_subtype i32 i32 $A)) ;; CHECK: (table $t 1 1 funcref) ;; NOMNL: (table $t 1 1 funcref) |