Skip to content

Commit e29d778

Browse files
authored
CoalesceLocals: ReFinalize when we refine a type (#6502)
The code had a different workaround, namely to add a block with an explicit type to avoid changing the type at all (i.e. the block declared the original type of the thing we replaced, not the refined type). But by adding a block we can end up with an invalid pop, as the fuzzer found, see the EH testcase here. To fix this, use the usual workaround of just running ReFinalize. That is simpler and also improves the code while we do it. It does add more work, but this is likely a very rare situation anyhow.
1 parent e460877 commit e29d778

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

src/passes/CoalesceLocals.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ struct CoalesceLocals
105105
bool interferes(Index i, Index j) {
106106
return interferences.get(std::min(i, j), std::max(i, j));
107107
}
108+
109+
private:
110+
// In some cases we need to refinalize at the end.
111+
bool refinalize = false;
108112
};
109113

110114
void CoalesceLocals::doWalkFunction(Function* func) {
@@ -118,6 +122,10 @@ void CoalesceLocals::doWalkFunction(Function* func) {
118122
pickIndices(indices);
119123
// apply indices
120124
applyIndices(indices, func->body);
125+
126+
if (refinalize) {
127+
ReFinalize().walkFunctionInModule(func, getModule());
128+
}
121129
}
122130

123131
// 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,
563571
drop->value = value;
564572
*action.origin = drop;
565573
} else {
566-
// This is a tee, and so, as earlier in this function, we must be
567-
// careful of subtyping. Above we simply avoided the problem by
568-
// leaving it for other passes, but we do want to remove ineffective
569-
// stores - nothing else does that as well as this pass. Instead,
570-
// create a block to cast back to the original type, which avoids
571-
// changing types here, and leave it to other passes to refine types
572-
// and remove the block.
573574
auto originalType = (*action.origin)->type;
574575
if (originalType != set->value->type) {
575-
(*action.origin) =
576-
Builder(*getModule()).makeBlock({set->value}, originalType);
577-
} else {
578-
// No special handling, just use the value.
579-
*action.origin = set->value;
576+
// The value had a more refined type, which we must propagate at
577+
// the end.
578+
refinalize = true;
580579
}
580+
*action.origin = set->value;
581581
}
582582
continue;
583583
}

test/lit/passes/coalesce-locals-eh-old.wast

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
(module
55
;; CHECK: (tag $e)
66

7-
;; CHECK: (func $bar (type $1) (result i32)
7+
;; CHECK: (tag $any (param (ref any)))
8+
9+
;; CHECK: (func $bar (type $2) (result i32)
810
;; CHECK-NEXT: (i32.const 1984)
911
;; CHECK-NEXT: )
1012
(func $bar (result i32)
1113
(i32.const 1984)
1214
)
1315

1416
(tag $e)
15-
;; CHECK: (func $bug-cfg-traversal (type $2) (param $0 i32) (result i32)
17+
18+
(tag $any (param (ref any)))
19+
20+
;; CHECK: (func $bug-cfg-traversal (type $3) (param $0 i32) (result i32)
1621
;; CHECK-NEXT: (try $try
1722
;; CHECK-NEXT: (do
1823
;; CHECK-NEXT: (local.set $0
@@ -42,4 +47,35 @@
4247
)
4348
(local.get $x)
4449
)
50+
51+
;; CHECK: (func $0 (type $0)
52+
;; CHECK-NEXT: (local $0 anyref)
53+
;; CHECK-NEXT: (try $try
54+
;; CHECK-NEXT: (do
55+
;; CHECK-NEXT: (nop)
56+
;; CHECK-NEXT: )
57+
;; CHECK-NEXT: (catch $any
58+
;; CHECK-NEXT: (drop
59+
;; CHECK-NEXT: (pop (ref any))
60+
;; CHECK-NEXT: )
61+
;; CHECK-NEXT: )
62+
;; CHECK-NEXT: )
63+
;; CHECK-NEXT: )
64+
(func $0
65+
(local $0 (ref null any))
66+
(try
67+
(do)
68+
(catch $any
69+
(drop
70+
;; There is a difference between the type of the value here and the
71+
;; type of the local, due to the local being nullable. We should not
72+
;; error on that as we replace the tee with a drop (as it has no
73+
;; gets).
74+
(local.tee $0
75+
(pop (ref any))
76+
)
77+
)
78+
)
79+
)
80+
)
4581
)

test/lit/passes/coalesce-locals-gc.wast

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,16 @@
181181
)
182182

183183
;; CHECK: (func $remove-tee-refinalize (type $5) (param $0 (ref null $A)) (param $1 (ref null $B)) (result structref)
184-
;; CHECK-NEXT: (struct.get $A 0
185-
;; CHECK-NEXT: (block (result (ref null $A))
186-
;; CHECK-NEXT: (local.get $1)
187-
;; CHECK-NEXT: )
184+
;; CHECK-NEXT: (struct.get $B 0
185+
;; CHECK-NEXT: (local.get $1)
188186
;; CHECK-NEXT: )
189187
;; CHECK-NEXT: )
190188
(func $remove-tee-refinalize
191189
(param $a (ref null $A))
192190
(param $b (ref null $B))
193191
(result (ref null struct))
194-
;; The local.tee receives a $B and flows out an $A. We want to avoid changing
195-
;; types here, so we'll wrap it in a block, and leave further improvements
196-
;; for other passes.
192+
;; The local.tee receives a $B and flows out an $A. We will ReFinalize here as
193+
;; we remove the tee, making the struct.get operate on $B.
197194
(struct.get $A 0
198195
(local.tee $a
199196
(local.get $b)
@@ -202,10 +199,8 @@
202199
)
203200

204201
;; CHECK: (func $remove-tee-refinalize-2 (type $5) (param $0 (ref null $A)) (param $1 (ref null $B)) (result structref)
205-
;; CHECK-NEXT: (struct.get $A 0
206-
;; CHECK-NEXT: (block (result (ref null $A))
207-
;; CHECK-NEXT: (local.get $1)
208-
;; CHECK-NEXT: )
202+
;; CHECK-NEXT: (struct.get $B 0
203+
;; CHECK-NEXT: (local.get $1)
209204
;; CHECK-NEXT: )
210205
;; CHECK-NEXT: )
211206
(func $remove-tee-refinalize-2
@@ -311,9 +306,9 @@
311306
;; CHECK-NEXT: )
312307
;; CHECK-NEXT: )
313308
;; CHECK-NEXT: (global.set $nn-tuple-global
314-
;; CHECK-NEXT: (block (type $1) (result (ref any) i32)
309+
;; CHECK-NEXT: (block (type $0) (result (ref any) i32)
315310
;; CHECK-NEXT: (local.set $1
316-
;; CHECK-NEXT: (if (type $1) (result (ref any) i32)
311+
;; CHECK-NEXT: (if (type $0) (result (ref any) i32)
317312
;; CHECK-NEXT: (i32.const 0)
318313
;; CHECK-NEXT: (then
319314
;; CHECK-NEXT: (tuple.make 2

0 commit comments

Comments
 (0)