@@ -71,6 +71,11 @@ using CastTypes = SmallUnorderedSet<HeapType, 5>;
71
71
struct CastFinder : public PostWalker <CastFinder> {
72
72
CastTypes castTypes;
73
73
74
+ // For each cast target, record whether there is an exact cast. Exact casts
75
+ // will additionally prevent subtypes from being merged into the cast target.
76
+ // TODO: Use a SmallMap to combine this with `castTypes`.
77
+ CastTypes exactCastTypes;
78
+
74
79
// If traps never happen, then ref.cast and call_indirect can never
75
80
// differentiate between types since they always succeed. Take advantage of
76
81
// that by not having those instructions inhibit merges in TNH mode.
@@ -83,6 +88,9 @@ struct CastFinder : public PostWalker<CastFinder> {
83
88
template <typename T> void visitCast (T* curr) {
84
89
if (auto type = curr->getCastType (); type != Type::unreachable) {
85
90
castTypes.insert (type.getHeapType ());
91
+ if (type.isExact ()) {
92
+ exactCastTypes.insert (type.getHeapType ());
93
+ }
86
94
}
87
95
}
88
96
@@ -126,8 +134,9 @@ struct TypeMerging : public Pass {
126
134
// All private original types.
127
135
std::unordered_set<HeapType> privateTypes;
128
136
129
- // Types that are distinguished by cast instructions .
137
+ // Types that are distinguished by casts and exact casts .
130
138
CastTypes castTypes;
139
+ CastTypes exactCastTypes;
131
140
132
141
// The list of remaining types that have not been merged into other types.
133
142
// Candidates for further merging.
@@ -169,7 +178,8 @@ struct TypeMerging : public Pass {
169
178
std::vector<std::vector<HeapType>>
170
179
splitSupertypePartition (const std::vector<HeapType>&);
171
180
172
- CastTypes findCastTypes ();
181
+ // Return the cast types and the exact cast types.
182
+ std::pair<CastTypes, CastTypes> findCastTypes ();
173
183
std::vector<HeapType> getPublicChildren (HeapType type);
174
184
DFA::State<HeapType> makeDFAState (HeapType type);
175
185
void applyMerges ();
@@ -220,7 +230,9 @@ void TypeMerging::run(Module* module_) {
220
230
mergeable = ModuleUtils::getPrivateHeapTypes (*module);
221
231
privateTypes =
222
232
std::unordered_set<HeapType>(mergeable.begin (), mergeable.end ());
223
- castTypes = findCastTypes ();
233
+ auto casts = findCastTypes ();
234
+ castTypes = std::move (casts.first );
235
+ exactCastTypes = std::move (casts.second );
224
236
225
237
// Merging supertypes or siblings can unlock more sibling merging
226
238
// opportunities, but merging siblings can never unlock more supertype merging
@@ -329,17 +341,18 @@ bool TypeMerging::merge(MergeKind kind) {
329
341
switch (kind) {
330
342
case Supertypes: {
331
343
auto super = type.getDeclaredSuperType ();
332
- if (super && shapeEq (type, *super)) {
333
- // The current type and its supertype have the same top-level
334
- // structure and are not distinguished, so add the current type to its
335
- // supertype's partition.
336
- auto it = ensurePartition (*super);
337
- it->push_back (makeDFAState (type));
338
- typePartitions[type] = it;
339
- } else {
340
- // Otherwise, create a new partition for this type.
344
+ bool superHasExactCast = super && exactCastTypes.count (*super);
345
+ if (!super || !shapeEq (type, *super) || superHasExactCast) {
346
+ // Create a new partition for this type and bail.
341
347
ensurePartition (type);
348
+ break ;
342
349
}
350
+ // The current type and its supertype have the same top-level
351
+ // structure and are not distinguished, so add the current type to its
352
+ // supertype's partition.
353
+ auto it = ensurePartition (*super);
354
+ it->push_back (makeDFAState (type));
355
+ typePartitions[type] = it;
343
356
break ;
344
357
}
345
358
case Siblings: {
@@ -476,17 +489,19 @@ TypeMerging::splitSupertypePartition(const std::vector<HeapType>& types) {
476
489
return partitions;
477
490
}
478
491
479
- CastTypes TypeMerging::findCastTypes () {
480
- ModuleUtils::ParallelFunctionAnalysis<CastTypes> analysis (
481
- *module, [&](Function* func, CastTypes& castTypes) {
482
- if (func->imported ()) {
483
- return ;
484
- }
492
+ std::pair<CastTypes, CastTypes> TypeMerging::findCastTypes () {
493
+ ModuleUtils::ParallelFunctionAnalysis<std::pair<CastTypes, CastTypes>>
494
+ analysis (*module,
495
+ [&](Function* func, std::pair<CastTypes, CastTypes>& castTypes) {
496
+ if (func->imported ()) {
497
+ return ;
498
+ }
485
499
486
- CastFinder finder (getPassOptions ());
487
- finder.walk (func->body );
488
- castTypes = std::move (finder.castTypes );
489
- });
500
+ CastFinder finder (getPassOptions ());
501
+ finder.walk (func->body );
502
+ castTypes = {std::move (finder.castTypes ),
503
+ std::move (finder.exactCastTypes )};
504
+ });
490
505
491
506
// Also find cast types in the module scope (not possible in the current
492
507
// spec, but do it to be future-proof).
@@ -495,12 +510,17 @@ CastTypes TypeMerging::findCastTypes() {
495
510
496
511
// Accumulate all the castTypes.
497
512
auto & allCastTypes = moduleFinder.castTypes ;
498
- for (auto & [k, castTypes] : analysis.map ) {
513
+ auto & allExactCastTypes = moduleFinder.exactCastTypes ;
514
+ for (auto & [k, types] : analysis.map ) {
515
+ auto & [castTypes, exactCastTypes] = types;
499
516
for (auto type : castTypes) {
500
517
allCastTypes.insert (type);
501
518
}
519
+ for (auto type : exactCastTypes) {
520
+ allExactCastTypes.insert (type);
521
+ }
502
522
}
503
- return allCastTypes;
523
+ return { std::move ( allCastTypes), std::move (allExactCastTypes)} ;
504
524
}
505
525
506
526
std::vector<HeapType> TypeMerging::getPublicChildren (HeapType type) {
0 commit comments