diff options
Diffstat (limited to 'test/lit')
-rw-r--r-- | test/lit/passes/gufa-refs.wast | 375 |
1 files changed, 306 insertions, 69 deletions
diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index e02fdc70a..9e17a3a69 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -2452,11 +2452,11 @@ (type $substruct (struct_subtype (field i32) (field i32) $struct)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) + ;; CHECK: (type $subsubstruct (struct_subtype (field i32) (field i32) (field i32) $substruct)) (type $subsubstruct (struct_subtype (field i32) (field i32) (field i32) $substruct)) - ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) - ;; CHECK: (type $other (struct_subtype data)) (type $other (struct_subtype data)) @@ -2469,12 +2469,16 @@ ;; CHECK: (import "a" "b" (func $import (result i32))) (import "a" "b" (func $import (result i32))) + ;; CHECK: (export "test-cones" (func $test-cones)) + ;; CHECK: (export "ref.test-inexact" (func $ref.test-inexact)) ;; CHECK: (export "ref.eq-zero" (func $ref.eq-zero)) ;; CHECK: (export "ref.eq-unknown" (func $ref.eq-unknown)) + ;; CHECK: (export "ref.eq-cone" (func $ref.eq-cone)) + ;; CHECK: (export "local-no" (func $ref.eq-local-no)) ;; CHECK: (func $test (type $none_=>_none) @@ -2608,6 +2612,114 @@ ) ) + ;; CHECK: (func $test-cones (type $i32_=>_none) (param $x i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast_static $struct + ;; CHECK-NEXT: (select (result (ref null $struct)) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast_static $struct + ;; CHECK-NEXT: (select (result (ref $struct)) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast_static $substruct + ;; CHECK-NEXT: (select (result (ref $struct)) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: (i32.const 6) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test-cones (export "test-cones") (param $x i32) + ;; The input to the ref.cast is potentially null, so we cannot infer here. + (drop + (ref.cast_static $struct + (select + (struct.new $struct + (i32.const 0) + ) + (ref.null any) + (local.get $x) + ) + ) + ) + ;; The input to the ref.cast is either $struct or $substruct, both of which + ;; work, so we cannot optimize anything here away. + (drop + (ref.cast_static $struct + (select + (struct.new $struct + (i32.const 1) + ) + (struct.new $substruct + (i32.const 2) + (i32.const 3) + ) + (local.get $x) + ) + ) + ) + ;; As above, but now we test with $substruct, so one possibility fails and + ;; one succeeds. We cannot infer here either. + (drop + (ref.cast_static $substruct + (select + (struct.new $struct + (i32.const 4) + ) + (struct.new $substruct + (i32.const 5) + (i32.const 6) + ) + (local.get $x) + ) + ) + ) + ;; Two possible types, both are supertypes, so neither is a subtype, and we + ;; can infer an unreachable. The combination of these two is a cone from + ;; $struct of depth 1, which does not overlap with $subsubstruct. + (drop + (ref.cast_static $subsubstruct + (select + (struct.new $struct + (i32.const 7) + ) + (struct.new $substruct + (i32.const 8) + (i32.const 9) + ) + (local.get $x) + ) + ) + ) + ) + ;; CHECK: (func $ref.test-exact (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) @@ -2663,18 +2775,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.test_static $struct - ;; CHECK-NEXT: (select (result (ref $struct)) - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new $substruct - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.test_static $substruct @@ -2691,18 +2792,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.test_static $subsubstruct - ;; CHECK-NEXT: (select (result (ref $struct)) - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (i32.const 7) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new $substruct - ;; CHECK-NEXT: (i32.const 8) - ;; CHECK-NEXT: (i32.const 9) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $ref.test-inexact (export "ref.test-inexact") (param $x i32) @@ -2719,7 +2809,9 @@ ) ) ;; The input to the ref.test is either $struct or $substruct, both of which - ;; work, so here we can infer a 1 - but we need a cone type for that TODO + ;; work, so here we can infer a 1. We do so using a cone type: the + ;; combination of those two types is a cone on $struct of depth 1, and that + ;; cone is 100% a subtype of $struct, so the test will succeed. (drop (ref.test_static $struct (select @@ -2751,7 +2843,8 @@ ) ) ;; Two possible types, both are supertypes, so neither is a subtype, and we - ;; can infer a 0 - but we need more precise type info than we have TODO + ;; can infer a 0. The combination of these two is a cone from $struct of + ;; depth 1, which does not overlap with $subsubstruct. (drop (ref.test_static $subsubstruct (select @@ -2832,25 +2925,6 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (select (result (ref $substruct)) - ;; CHECK-NEXT: (struct.new $substruct - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new $subsubstruct - ;; CHECK-NEXT: (i32.const 4) - ;; CHECK-NEXT: (i32.const 5) - ;; CHECK-NEXT: (i32.const 6) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (local.get $other) ;; CHECK-NEXT: ) @@ -2918,28 +2992,6 @@ (ref.null $struct) ) ) - ;; One side has two possible types, which we see as Many, and so we cannot - ;; infer anything here. With a cone type, however, we could infer a 0. - ;; TODO: add more tests for cone types here when we get them - (drop - (ref.eq - (struct.new $struct - (i32.const 1) - ) - (select - (struct.new $substruct - (i32.const 2) - (i32.const 3) - ) - (struct.new $subsubstruct - (i32.const 4) - (i32.const 5) - (i32.const 6) - ) - (local.get $x) - ) - ) - ) ;; When nulls are possible, we cannot infer anything (with or without the ;; same type on both sides). (drop @@ -2998,6 +3050,191 @@ ) ) + ;; CHECK: (func $ref.eq-cone (type $i32_=>_none) (param $x i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (select (result (ref $struct)) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $subsubstruct + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: (i32.const 6) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (select (result (ref $struct)) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (select (result (ref $substruct)) + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $subsubstruct + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: (i32.const 6) + ;; CHECK-NEXT: (i32.const 7) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (select (result (ref $substruct)) + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $substruct + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: (i32.const 6) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $ref.eq-cone (export "ref.eq-cone") (param $x i32) + ;; One side has two possible types, so we have a cone there. This cone is + ;; of subtypes of the other type, which is exact, so we cannot intersect + ;; here and we infer a 0. + (drop + (ref.eq + (struct.new $struct + (i32.const 1) + ) + (select + (struct.new $substruct + (i32.const 2) + (i32.const 3) + ) + (struct.new $subsubstruct + (i32.const 4) + (i32.const 5) + (i32.const 6) + ) + (local.get $x) + ) + ) + ) + ;; Now the cone is large enough, so there might be an intersection, and we + ;; do not optimize (the cone of $struct and $subsubstruct contains + ;; $substruct which is in the middle). + (drop + (ref.eq + (struct.new $substruct + (i32.const 1) + (i32.const 2) + ) + (select + (struct.new $struct + (i32.const 3) + ) + (struct.new $subsubstruct + (i32.const 4) + (i32.const 5) + (i32.const 6) + ) + (local.get $x) + ) + ) + ) + (drop + (ref.eq + (struct.new $substruct + (i32.const 1) + (i32.const 2) + ) + (select + (struct.new $struct + (i32.const 3) + ) + (struct.new $substruct ;; As above, but with this changed. We still + (i32.const 4) ;; cannot optimize. + (i32.const 5) + ) + (local.get $x) + ) + ) + ) + (drop + (ref.eq + (struct.new $substruct + (i32.const 1) + (i32.const 2) + ) + (select + (struct.new $substruct ;; As above, but with this changed. We still + (i32.const 3) ;; cannot optimize. + (i32.const 4) + ) + (struct.new $subsubstruct + (i32.const 5) + (i32.const 6) + (i32.const 7) + ) + (local.get $x) + ) + ) + ) + (drop + (ref.eq + (struct.new $substruct + (i32.const 1) + (i32.const 2) + ) + (select + (struct.new $substruct + (i32.const 3) + (i32.const 4) + ) + (struct.new $substruct ;; As above, but with this changed. We still + (i32.const 5) ;; cannot optimize (here the type is actually + (i32.const 6) ;; exact, despite the select). + ) + (local.get $x) + ) + ) + ) + ) + ;; CHECK: (func $unreachable (type $none_=>_ref|eq|) (result (ref eq)) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) |