summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/CoalesceLocals.cpp24
-rw-r--r--test/lit/passes/coalesce-locals-eh-old.wast40
-rw-r--r--test/lit/passes/coalesce-locals-gc.wast21
3 files changed, 58 insertions, 27 deletions
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index eb3babeb0..313bbc03a 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -105,6 +105,10 @@ struct CoalesceLocals
bool interferes(Index i, Index j) {
return interferences.get(std::min(i, j), std::max(i, j));
}
+
+private:
+ // In some cases we need to refinalize at the end.
+ bool refinalize = false;
};
void CoalesceLocals::doWalkFunction(Function* func) {
@@ -118,6 +122,10 @@ void CoalesceLocals::doWalkFunction(Function* func) {
pickIndices(indices);
// apply indices
applyIndices(indices, func->body);
+
+ if (refinalize) {
+ ReFinalize().walkFunctionInModule(func, getModule());
+ }
}
// A copy on a backedge can be especially costly, forcing us to branch just to
@@ -563,21 +571,13 @@ void CoalesceLocals::applyIndices(std::vector<Index>& indices,
drop->value = value;
*action.origin = drop;
} else {
- // This is a tee, and so, as earlier in this function, we must be
- // careful of subtyping. Above we simply avoided the problem by
- // leaving it for other passes, but we do want to remove ineffective
- // stores - nothing else does that as well as this pass. Instead,
- // create a block to cast back to the original type, which avoids
- // changing types here, and leave it to other passes to refine types
- // and remove the block.
auto originalType = (*action.origin)->type;
if (originalType != set->value->type) {
- (*action.origin) =
- Builder(*getModule()).makeBlock({set->value}, originalType);
- } else {
- // No special handling, just use the value.
- *action.origin = set->value;
+ // The value had a more refined type, which we must propagate at
+ // the end.
+ refinalize = true;
}
+ *action.origin = set->value;
}
continue;
}
diff --git a/test/lit/passes/coalesce-locals-eh-old.wast b/test/lit/passes/coalesce-locals-eh-old.wast
index 379f3dc31..3acbda064 100644
--- a/test/lit/passes/coalesce-locals-eh-old.wast
+++ b/test/lit/passes/coalesce-locals-eh-old.wast
@@ -4,7 +4,9 @@
(module
;; CHECK: (tag $e)
- ;; CHECK: (func $bar (type $1) (result i32)
+ ;; CHECK: (tag $any (param (ref any)))
+
+ ;; CHECK: (func $bar (type $2) (result i32)
;; CHECK-NEXT: (i32.const 1984)
;; CHECK-NEXT: )
(func $bar (result i32)
@@ -12,7 +14,10 @@
)
(tag $e)
- ;; CHECK: (func $bug-cfg-traversal (type $2) (param $0 i32) (result i32)
+
+ (tag $any (param (ref any)))
+
+ ;; CHECK: (func $bug-cfg-traversal (type $3) (param $0 i32) (result i32)
;; CHECK-NEXT: (try $try
;; CHECK-NEXT: (do
;; CHECK-NEXT: (local.set $0
@@ -42,4 +47,35 @@
)
(local.get $x)
)
+
+ ;; CHECK: (func $0 (type $0)
+ ;; CHECK-NEXT: (local $0 anyref)
+ ;; CHECK-NEXT: (try $try
+ ;; CHECK-NEXT: (do
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (catch $any
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (pop (ref any))
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $0
+ (local $0 (ref null any))
+ (try
+ (do)
+ (catch $any
+ (drop
+ ;; There is a difference between the type of the value here and the
+ ;; type of the local, due to the local being nullable. We should not
+ ;; error on that as we replace the tee with a drop (as it has no
+ ;; gets).
+ (local.tee $0
+ (pop (ref any))
+ )
+ )
+ )
+ )
+ )
)
diff --git a/test/lit/passes/coalesce-locals-gc.wast b/test/lit/passes/coalesce-locals-gc.wast
index b485f90d0..0fc83d74e 100644
--- a/test/lit/passes/coalesce-locals-gc.wast
+++ b/test/lit/passes/coalesce-locals-gc.wast
@@ -181,19 +181,16 @@
)
;; CHECK: (func $remove-tee-refinalize (type $5) (param $0 (ref null $A)) (param $1 (ref null $B)) (result structref)
- ;; CHECK-NEXT: (struct.get $A 0
- ;; CHECK-NEXT: (block (result (ref null $A))
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $remove-tee-refinalize
(param $a (ref null $A))
(param $b (ref null $B))
(result (ref null struct))
- ;; The local.tee receives a $B and flows out an $A. We want to avoid changing
- ;; types here, so we'll wrap it in a block, and leave further improvements
- ;; for other passes.
+ ;; The local.tee receives a $B and flows out an $A. We will ReFinalize here as
+ ;; we remove the tee, making the struct.get operate on $B.
(struct.get $A 0
(local.tee $a
(local.get $b)
@@ -202,10 +199,8 @@
)
;; CHECK: (func $remove-tee-refinalize-2 (type $5) (param $0 (ref null $A)) (param $1 (ref null $B)) (result structref)
- ;; CHECK-NEXT: (struct.get $A 0
- ;; CHECK-NEXT: (block (result (ref null $A))
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $remove-tee-refinalize-2
@@ -311,9 +306,9 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $nn-tuple-global
- ;; CHECK-NEXT: (block (type $1) (result (ref any) i32)
+ ;; CHECK-NEXT: (block (type $0) (result (ref any) i32)
;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (if (type $1) (result (ref any) i32)
+ ;; CHECK-NEXT: (if (type $0) (result (ref any) i32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (tuple.make 2