summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Heap2Local.cpp10
-rw-r--r--test/lit/passes/gto-mutability.wast3
-rw-r--r--test/lit/passes/heap2local.wast66
3 files changed, 76 insertions, 3 deletions
diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp
index ac6fb49a6..fc3c18db0 100644
--- a/src/passes/Heap2Local.cpp
+++ b/src/passes/Heap2Local.cpp
@@ -274,12 +274,14 @@ struct Heap2LocalOptimizer {
// left to other passes, like getting rid of dropped code without side
// effects.
- void visitBlock(Block* curr) {
+ // Adjust the type that flows through an expression, updating that type as
+ // necessary.
+ void adjustTypeFlowingThrough(Expression* curr) {
if (!reached.count(curr)) {
return;
}
- // Our allocation passes through this block. We must turn its type into a
+ // Our allocation passes through this expr. We must turn its type into a
// nullable one, because we will remove things like RefAsNonNull of it,
// which means we may no longer have a non-nullable value as our input,
// and we could fail to validate. It is safe to make this change in terms
@@ -290,6 +292,10 @@ struct Heap2LocalOptimizer {
curr->type = Type(curr->type.getHeapType(), Nullable);
}
+ void visitBlock(Block* curr) { adjustTypeFlowingThrough(curr); }
+
+ void visitLoop(Loop* curr) { adjustTypeFlowingThrough(curr); }
+
void visitLocalSet(LocalSet* curr) {
if (!reached.count(curr)) {
return;
diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast
index 6cb3575d7..26376e738 100644
--- a/test/lit/passes/gto-mutability.wast
+++ b/test/lit/passes/gto-mutability.wast
@@ -14,6 +14,8 @@
(type $two-params (func (param (ref $struct)) (param (ref $struct))))
;; Test that we update tag types properly.
+ (table 0 funcref)
+
;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
;; CHECK: (type $none_=>_ref?|$struct| (func_subtype (result (ref null $struct)) func))
@@ -21,7 +23,6 @@
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (table $0 0 funcref)
- (table 0 funcref)
;; CHECK: (elem declare func $func-two-params)
diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast
index 087b969b6..98b5d894e 100644
--- a/test/lit/passes/heap2local.wast
+++ b/test/lit/passes/heap2local.wast
@@ -3112,4 +3112,70 @@
(struct.new_default $struct.A)
)
)
+
+ ;; CHECK: (func $pass-through-loop
+ ;; CHECK-NEXT: (local $0 (ref null $struct.A))
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 f64)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (loop $loop (result (ref null $struct.A))
+ ;; CHECK-NEXT: (br_if $loop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result (ref null $struct.A))
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (f64.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (rtt.canon $struct.A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null $struct.A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $pass-through-loop
+ ;; NOMNL-NEXT: (local $0 (ref null $struct.A))
+ ;; NOMNL-NEXT: (local $1 i32)
+ ;; NOMNL-NEXT: (local $2 f64)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (loop $loop (result (ref null $struct.A))
+ ;; NOMNL-NEXT: (br_if $loop
+ ;; NOMNL-NEXT: (i32.const 0)
+ ;; NOMNL-NEXT: )
+ ;; 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: )
+ ;; NOMNL-NEXT: )
+ (func $pass-through-loop
+ (local $0 (ref null $struct.A))
+ ;; The allocation pass through a loop, which should change type to be
+ ;; nullable.
+ (drop
+ (loop $loop (result (ref $struct.A))
+ ;; Include a branch to the loop, so that the testcase does not become
+ ;; trivial (remove-unused-names will turn a loop with no name into a
+ ;; block).
+ (br_if $loop (i32.const 0))
+ ;; The allocation that will be turned into locals.
+ (struct.new_default_with_rtt $struct.A
+ (rtt.canon $struct.A)
+ )
+ )
+ )
+ )
)