summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/module-utils.cpp47
-rw-r--r--test/lit/lub-bug-3843.wast3
-rw-r--r--test/lit/nominal-chain.wast13
-rw-r--r--test/lit/parse-nominal-types-extends.wast15
-rw-r--r--test/lit/parse-nominal-types.wast15
-rw-r--r--test/lit/passes/cfp.wast35
-rw-r--r--test/lit/passes/dae-gc-refine-params.wast3
-rw-r--r--test/lit/passes/dae-gc-refine-return.wast3
-rw-r--r--test/lit/passes/gto-mutability.wast3
-rw-r--r--test/lit/passes/gto-removals.wast11
-rw-r--r--test/lit/passes/optimize-instructions-gc-iit.wast12
-rw-r--r--test/lit/passes/signature-refining.wast3
-rw-r--r--test/lit/passes/type-refining.wast24
13 files changed, 119 insertions, 68 deletions
diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp
index 7861bde54..bf1a45205 100644
--- a/src/ir/module-utils.cpp
+++ b/src/ir/module-utils.cpp
@@ -203,9 +203,10 @@ std::vector<HeapType> collectHeapTypes(Module& wasm) {
}
IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
+ TypeSystem system = getTypeSystem();
Counts counts = getHeapTypeCounts(wasm);
- if (getTypeSystem() != TypeSystem::Isorecursive) {
+ if (system == TypeSystem::Equirecursive) {
// Sort by frequency and then original insertion order.
std::vector<std::pair<HeapType, size_t>> sorted(counts.begin(),
counts.end());
@@ -223,9 +224,12 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
return indexedTypes;
}
- // Isorecursive types have to be arranged into topologically ordered recursion
- // groups. Sort the groups by average use count among their members so that
- // the topological sort will place frequently used types first.
+ // Types have to be arranged into topologically ordered recursion groups.
+ // Under isorecrsive typing, the topological sort has to take all referenced
+ // rec groups into account but under nominal typing it only has to take
+ // supertypes into account. First, sort the groups by average use count among
+ // their members so that the later topological sort will place frequently used
+ // types first.
struct GroupInfo {
size_t index;
double useCount = 0;
@@ -236,7 +240,7 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
if (useCount != other.useCount) {
return useCount < other.useCount;
}
- return index < other.index;
+ return index > other.index;
}
};
@@ -257,20 +261,35 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
// Update the reference count.
info.useCount += counts.at(type);
// Collect predecessor groups.
- for (auto child : type.getReferencedHeapTypes()) {
- if (!child.isBasic()) {
- RecGroup otherGroup = child.getRecGroup();
- if (otherGroup != group) {
- info.preds.insert(otherGroup);
+ switch (system) {
+ case TypeSystem::Isorecursive:
+ for (auto child : type.getReferencedHeapTypes()) {
+ if (!child.isBasic()) {
+ RecGroup otherGroup = child.getRecGroup();
+ if (otherGroup != group) {
+ info.preds.insert(otherGroup);
+ }
+ }
}
- }
+ break;
+ case TypeSystem::Nominal:
+ if (auto super = type.getSuperType()) {
+ info.preds.insert(super->getRecGroup());
+ }
+ break;
+ case TypeSystem::Equirecursive:
+ WASM_UNREACHABLE(
+ "Equirecursive types should already have been handled");
}
}
// Fix up the use counts to be averages to ensure groups are used comensurate
- // with the amount of index space they occupy.
- for (auto& [group, info] : groupInfos) {
- info.useCount /= group.size();
+ // with the amount of index space they occupy. Skip this for nominal types
+ // since their internal group size is always 1.
+ if (system != TypeSystem::Nominal) {
+ for (auto& [group, info] : groupInfos) {
+ info.useCount /= group.size();
+ }
}
// Sort the predecessors so the most used will be visited first.
diff --git a/test/lit/lub-bug-3843.wast b/test/lit/lub-bug-3843.wast
index 596f4a6d9..f5bb439f2 100644
--- a/test/lit/lub-bug-3843.wast
+++ b/test/lit/lub-bug-3843.wast
@@ -16,11 +16,12 @@
(type $B (struct_subtype (field (ref null $D)) $A))
;; CHECK: (type $D (struct (field (mut (ref $A))) (field (mut (ref $A)))))
+ ;; NOMNL: (type $C (struct_subtype (field (mut (ref $A))) data))
+
;; 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_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 474286e6b..dda04b32c 100644
--- a/test/lit/nominal-chain.wast
+++ b/test/lit/nominal-chain.wast
@@ -7,18 +7,21 @@
;; types.
(module
- ;; 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_subtype data))
+ ;; CHECK: (type $trunk (struct_subtype (field i32) $root))
+
+ ;; CHECK: (type $branch (struct_subtype (field i32) (field i64) $trunk))
+
;; CHECK: (type $twig (struct_subtype (field i32) (field i64) (field f32) $branch))
+
+ ;; CHECK: (type $leaf (struct_subtype (field i32) (field i64) (field f32) (field f64) $twig))
+ (type $leaf (struct_subtype i32 i64 f32 f64 $twig))
+
(type $twig (struct_subtype i32 i64 f32 $branch))
- ;; CHECK: (type $branch (struct_subtype (field i32) (field i64) $trunk))
(type $branch (struct_subtype i32 i64 $trunk))
- ;; CHECK: (type $trunk (struct_subtype (field i32) $root))
(type $trunk (struct_subtype i32 $root))
(type $root (struct))
diff --git a/test/lit/parse-nominal-types-extends.wast b/test/lit/parse-nominal-types-extends.wast
index 2077bd90f..ea9461e67 100644
--- a/test/lit/parse-nominal-types-extends.wast
+++ b/test/lit/parse-nominal-types-extends.wast
@@ -8,10 +8,11 @@
;; void function type
(module
+ ;; CHECK: (type $super (func_subtype func))
+
;; 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))
@@ -20,10 +21,11 @@
;; function type with params and results
(module
+ ;; CHECK: (type $super (func_subtype (param i32) (result i32) func))
+
;; 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))
@@ -32,10 +34,11 @@
;; empty struct type
(module
+ ;; CHECK: (type $super (struct_subtype data))
+
;; 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))
@@ -44,10 +47,11 @@
;; struct type with fields
(module
+ ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data))
+
;; 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))
@@ -56,10 +60,11 @@
;; array type
(module
+ ;; CHECK: (type $super (array_subtype i8 data))
+
;; 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))
diff --git a/test/lit/parse-nominal-types.wast b/test/lit/parse-nominal-types.wast
index fb4a0cf53..db681ead9 100644
--- a/test/lit/parse-nominal-types.wast
+++ b/test/lit/parse-nominal-types.wast
@@ -8,10 +8,11 @@
;; void function type
(module
+ ;; CHECK: (type $super (func_subtype func))
+
;; CHECK: (type $sub (func_subtype $super))
(type $sub (func_subtype $super))
- ;; CHECK: (type $super (func_subtype func))
(type $super (func_subtype func))
;; CHECK: (global $g (ref null $super) (ref.null $sub))
@@ -20,10 +21,11 @@
;; function type with params and results
(module
+ ;; CHECK: (type $super (func_subtype (param i32) (result i32) func))
+
;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super))
(type $sub (func_subtype (param i32) (result i32) $super))
- ;; 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 +34,11 @@
;; empty struct type
(module
+ ;; CHECK: (type $super (struct_subtype data))
+
;; CHECK: (type $sub (struct_subtype $super))
(type $sub (struct_subtype $super))
- ;; CHECK: (type $super (struct_subtype data))
(type $super (struct_subtype data))
;; CHECK: (global $g (ref null $super) (ref.null $sub))
@@ -44,10 +47,11 @@
;; struct type with fields
(module
+ ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data))
+
;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super))
(type $sub (struct_subtype i32 (field i64) $super))
- ;; 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 +60,11 @@
;; array type
(module
+ ;; CHECK: (type $super (array_subtype i8 data))
+
;; CHECK: (type $sub (array_subtype i8 $super))
(type $sub (array_subtype i8 $super))
- ;; 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 d1eecc658..5caadf16d 100644
--- a/test/lit/passes/cfp.wast
+++ b/test/lit/passes/cfp.wast
@@ -664,10 +664,11 @@
(module
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $struct (struct_subtype (field i32) data))
+
;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct))
(type $substruct (struct_subtype i32 f64 $struct))
- ;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (func $create (type $none_=>_none)
@@ -834,10 +835,11 @@
(module
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $struct (struct_subtype (field i32) data))
+
;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct))
(type $substruct (struct_subtype i32 f64 $struct))
- ;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (func $create (type $none_=>_none)
@@ -958,17 +960,19 @@
;; Multi-level subtyping, check that we propagate not just to the immediate
;; supertype but all the way as needed.
(module
+ ;; CHECK: (type $struct1 (struct_subtype (field i32) data))
+
+ ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1))
+
;; 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_subtype func))
-
- ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1))
(type $struct2 (struct_subtype i32 f64 $struct1))
- ;; CHECK: (type $struct1 (struct_subtype (field i32) data))
(type $struct1 (struct i32))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $create (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_with_rtt $struct3
@@ -1093,13 +1097,15 @@
;; different values in the sub-most type. Create the top and bottom types, but
;; not the middle one.
(module
+ ;; CHECK: (type $struct1 (struct_subtype (field i32) (field i32) data))
+
+ ;; CHECK: (type $struct2 (struct_subtype (field i32) (field i32) (field f64) (field f64) $struct1))
+
;; 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_subtype (field i32) (field i32) data))
(type $struct1 (struct i32 i32))
- ;; 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_subtype (param anyref) func))
@@ -1427,10 +1433,11 @@
;; 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 $struct1 (struct_subtype (field (mut i32)) data))
+
;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1))
(type $struct2 (struct_subtype (mut i32) f64 $struct1))
- ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data))
(type $struct1 (struct (mut i32)))
;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2))
@@ -1657,21 +1664,23 @@
;; 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 $A (struct_subtype (field (mut i32)) data))
+
+ ;; CHECK: (type $B (struct_subtype (field (mut i32)) $A))
+
;; CHECK: (type $C (struct_subtype (field (mut i32)) $B))
(type $C (struct_subtype (mut i32) $B))
- ;; CHECK: (type $A (struct_subtype (field (mut i32)) data))
(type $A (struct (mut i32)))
+ (type $B (struct_subtype (mut i32) $A))
+
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func))
;; CHECK: (type $ref|$C|_=>_none (func_subtype (param (ref $C)) func))
- ;; CHECK: (type $B (struct_subtype (field (mut i32)) $A))
- (type $B (struct_subtype (mut i32) $A))
-
;; CHECK: (func $create (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_with_rtt $C
diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast
index 767c2d716..25494d160 100644
--- a/test/lit/passes/dae-gc-refine-params.wast
+++ b/test/lit/passes/dae-gc-refine-params.wast
@@ -4,11 +4,12 @@
(module
;; CHECK: (type ${i32} (struct (field i32)))
+ ;; NOMNL: (type ${} (struct_subtype data))
+
;; NOMNL: (type ${i32} (struct_subtype (field i32) ${}))
(type ${i32} (struct_subtype (field i32) ${}))
;; CHECK: (type ${} (struct ))
- ;; NOMNL: (type ${} (struct_subtype data))
(type ${} (struct))
;; CHECK: (type ${i32_i64} (struct (field i32) (field i64)))
diff --git a/test/lit/passes/dae-gc-refine-return.wast b/test/lit/passes/dae-gc-refine-return.wast
index 15a40652d..a349fbdfd 100644
--- a/test/lit/passes/dae-gc-refine-return.wast
+++ b/test/lit/passes/dae-gc-refine-return.wast
@@ -12,6 +12,8 @@
;; CHECK: (type ${i32_i64} (struct (field i32) (field i64)))
;; CHECK: (type ${i32_f32} (struct (field i32) (field f32)))
+ ;; NOMNL: (type ${} (struct_subtype data))
+
;; NOMNL: (type ${i32} (struct_subtype (field i32) ${}))
;; NOMNL: (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32}))
@@ -24,7 +26,6 @@
(type ${i32} (struct_subtype (field i32) ${}))
;; CHECK: (type ${} (struct ))
- ;; NOMNL: (type ${} (struct_subtype data))
(type ${} (struct))
(table 1 1 funcref)
diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast
index 89c2a537f..4ecab4f8c 100644
--- a/test/lit/passes/gto-mutability.wast
+++ b/test/lit/passes/gto-mutability.wast
@@ -531,10 +531,9 @@
;; As above, but add a write in the sub, which prevents optimization.
- ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super))
-
;; CHECK: (type $super (struct_subtype (field (mut i32)) data))
(type $super (struct (field (mut i32))))
+ ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super))
(type $sub (struct_subtype (field (mut i32)) $super))
;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func))
diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast
index 1d80b24ee..f3cbae2aa 100644
--- a/test/lit/passes/gto-removals.wast
+++ b/test/lit/passes/gto-removals.wast
@@ -645,10 +645,11 @@
;; We can remove fields from the end if they are only used in subtypes, because
;; the subtypes can always add fields at the end (and only at the end).
(module
+ ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) data))
+
;; CHECK: (type $child (struct_subtype (field i32) (field i64) (field f32) (field f64) (field anyref) $parent))
(type $child (struct_subtype (field i32) (field i64) (field f32) (field f64) (field anyref) $parent))
- ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) data))
(type $parent (struct_subtype (field i32) (field i64) (field f32) (field f64) data))
;; CHECK: (type $ref|$parent|_ref|$child|_=>_none (func_subtype (param (ref $parent) (ref $child)) func))
@@ -694,10 +695,11 @@
)
(module
+ ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) (field (mut f32)) data))
+
;; CHECK: (type $child (struct_subtype (field i32) (field i64) (field (mut f32)) (field f64) (field anyref) $parent))
(type $child (struct_subtype (field (mut i32)) (field (mut i64)) (field (mut f32)) (field (mut f64)) (field (mut anyref)) $parent))
- ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) (field (mut f32)) data))
(type $parent (struct_subtype (field (mut i32)) (field (mut i64)) (field (mut f32)) (field (mut f64)) data))
;; CHECK: (type $ref|$parent|_ref|$child|_=>_none (func_subtype (param (ref $parent) (ref $child)) func))
@@ -774,13 +776,14 @@
;; As above, but now the read is just of one child. We can remove the field
;; from the parent and the other child.
(module
+ ;; CHECK: (type $parent (struct_subtype data))
+
;; CHECK: (type $child1 (struct_subtype (field i32) $parent))
(type $child1 (struct_subtype (field i32) $parent))
+ (type $parent (struct_subtype (field i32) data))
;; CHECK: (type $ref|$parent|_ref|$child1|_ref|$child2|_=>_none (func_subtype (param (ref $parent) (ref $child1) (ref $child2)) func))
- ;; CHECK: (type $parent (struct_subtype data))
- (type $parent (struct_subtype (field i32) data))
;; CHECK: (type $child2 (struct_subtype $parent))
(type $child2 (struct_subtype (field i32) $parent))
diff --git a/test/lit/passes/optimize-instructions-gc-iit.wast b/test/lit/passes/optimize-instructions-gc-iit.wast
index d0638860f..4117dce19 100644
--- a/test/lit/passes/optimize-instructions-gc-iit.wast
+++ b/test/lit/passes/optimize-instructions-gc-iit.wast
@@ -372,21 +372,17 @@
;; CHECK: (type $B (struct (field (ref null $A))))
;; CHECK: (type $A (struct ))
- ;; NOMNL: (type $C (struct_subtype (field (ref null $D)) $B))
-
- ;; NOMNL: (type $D (struct_subtype $A))
-
;; NOMNL: (type $A (struct_subtype data))
- ;; NOMNL-TNH: (type $C (struct_subtype (field (ref null $D)) $B))
-
- ;; NOMNL-TNH: (type $D (struct_subtype $A))
-
;; NOMNL-TNH: (type $A (struct_subtype data))
(type $A (struct_subtype data))
;; NOMNL: (type $B (struct_subtype (field (ref null $A)) $A))
;; NOMNL-TNH: (type $B (struct_subtype (field (ref null $A)) $A))
(type $B (struct_subtype (field (ref null $A)) $A))
+ ;; NOMNL: (type $C (struct_subtype (field (ref null $D)) $B))
+ ;; NOMNL-TNH: (type $C (struct_subtype (field (ref null $D)) $B))
(type $C (struct_subtype (field (ref null $D)) $B))
+ ;; NOMNL: (type $D (struct_subtype $A))
+ ;; NOMNL-TNH: (type $D (struct_subtype $A))
(type $D (struct_subtype $A))
;; CHECK: (func $test (param $C (ref $B)) (result anyref)
diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast
index a6d4ba53f..c67e04917 100644
--- a/test/lit/passes/signature-refining.wast
+++ b/test/lit/passes/signature-refining.wast
@@ -123,13 +123,14 @@
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $struct (struct_subtype data))
+
;; CHECK: (type $struct-sub1 (struct_subtype $struct))
(type $struct-sub1 (struct_subtype $struct))
;; CHECK: (type $struct-sub2 (struct_subtype $struct))
(type $struct-sub2 (struct_subtype $struct))
- ;; CHECK: (type $struct (struct_subtype data))
(type $struct (struct_subtype data))
;; CHECK: (func $func-1 (type $sig) (param $x (ref $struct))
diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast
index 7f903d64e..91e47cdb0 100644
--- a/test/lit/passes/type-refining.wast
+++ b/test/lit/passes/type-refining.wast
@@ -121,10 +121,11 @@
;; As above, but all writes are of $child-A, which allows more optimization
;; up to that type.
+ ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child-A))) data))
+
;; CHECK: (type $child-A (struct_subtype (field (mut (ref $child-A))) $struct))
(type $child-A (struct_subtype (field (mut dataref)) $struct))
- ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child-A))) data))
(type $struct (struct_subtype (field (mut dataref)) data))
;; CHECK: (type $ref|$struct|_ref|$child-A|_=>_none (func_subtype (param (ref $struct) (ref $child-A)) func))
@@ -205,10 +206,11 @@
(module
;; As above, but both writes are of $child, so we can optimize.
+ ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child))) data))
+
;; CHECK: (type $child (struct_subtype (field (mut (ref $child))) $struct))
(type $child (struct_subtype (field (mut dataref)) $struct))
- ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child))) data))
(type $struct (struct_subtype (field (mut dataref)) data))
;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func_subtype (param (ref $struct) (ref $child)) func))
@@ -435,21 +437,23 @@
)
(module
+ ;; CHECK: (type $X (struct_subtype data))
+
;; CHECK: (type $Y (struct_subtype $X))
(type $Y (struct_subtype $X))
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $A (struct_subtype (field (ref $Y)) data))
+
;; CHECK: (type $C (struct_subtype (field (ref $Y)) $A))
(type $C (struct_subtype (field (ref $X)) $A))
;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A))
(type $B (struct_subtype (field (ref $X)) $A))
- ;; CHECK: (type $A (struct_subtype (field (ref $Y)) data))
(type $A (struct_subtype (field (ref $X)) data))
- ;; CHECK: (type $X (struct_subtype data))
(type $X (struct_subtype data))
;; CHECK: (func $foo (type $none_=>_none)
@@ -489,6 +493,8 @@
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $A (struct_subtype (field (ref $X)) data))
+
;; CHECK: (type $C (struct_subtype (field (ref $X)) $A))
(type $C (struct_subtype (field (ref $X)) $A))
@@ -498,7 +504,6 @@
;; CHECK: (type $Y (struct_subtype $X))
(type $Y (struct_subtype $X))
- ;; CHECK: (type $A (struct_subtype (field (ref $X)) data))
(type $A (struct_subtype (field (ref $X)) data))
;; CHECK: (func $foo (type $none_=>_none)
@@ -520,10 +525,11 @@
(type $X (struct_subtype data))
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $A (struct_subtype (field (ref $X)) data))
+
;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A))
(type $B (struct_subtype (field (ref $Y)) $A))
- ;; CHECK: (type $A (struct_subtype (field (ref $X)) data))
(type $A (struct_subtype (field (ref $X)) data))
;; CHECK: (type $Y (struct_subtype $X))
@@ -784,21 +790,23 @@
;; Root-Outer[Root-Inner] -> Leaf1-Outer[Leaf1-Inner]
;; -> Leaf2-Outer[Leaf2-Inner]
+ ;; CHECK: (type $Root-Inner (struct_subtype data))
+
;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner))
(type $Leaf2-Inner (struct_subtype $Root-Inner))
;; CHECK: (type $none_=>_none (func_subtype func))
+ ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data))
+
;; CHECK: (type $Leaf1-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
(type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer))
;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
(type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
- ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data))
(type $Root-Outer (struct_subtype (field (ref $Root-Inner)) data))
- ;; CHECK: (type $Root-Inner (struct_subtype data))
(type $Root-Inner (struct_subtype data))
(type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner))