Skip to content

Commit 8470f1b

Browse files
authored
[Custom Descriptors] Update MinimizeRecGroups (#7671)
Take descriptor and described types into account when comparing rec group structures. Also take the constraint that described types must appear before their descriptors when generating permutations of rec groups.
1 parent 6ea7fc2 commit 8470f1b

File tree

4 files changed

+262
-33
lines changed

4 files changed

+262
-33
lines changed

scripts/test/fuzzing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
'unsubtyping-desc.wast',
123123
'type-merging-desc.wast',
124124
'heap2local-desc.wast',
125+
'minimize-rec-groups-desc.wast',
125126
# TODO: fix split_wast() on tricky escaping situations like a string ending
126127
# in \\" (the " is not escaped - there is an escaped \ before it)
127128
'string-lifting-section.wast',

src/passes/MinimizeRecGroups.cpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
// permutations, fall back to keeping the types distinct by adding distinct
3434
// brand types to the recursion groups to ensure they have different shapes.
3535
//
36-
// There are several possible algorithmic design for detecting when to generate
36+
// There are several possible algorithmic designs for detecting when to generate
3737
// permutations and determining what permutations to generate. They trade off
3838
// the amount of "wasted" work spent generating shapes that have already been
3939
// used with the amount of work spent trying to avoid the wasted work and with
@@ -161,23 +161,30 @@ struct BrandTypeIterator {
161161
}
162162
};
163163

164-
// Create an adjacency list with edges from supertype to subtypes.
164+
// Create an adjacency list with edges from supertype to subtype and from
165+
// described type to descriptor.
165166
std::vector<std::vector<Index>>
166-
createSubtypeGraph(const std::vector<HeapType>& types) {
167+
createTypeOrderGraph(const std::vector<HeapType>& types) {
167168
std::unordered_map<HeapType, Index> indices;
168169
for (auto type : types) {
169170
indices.insert({type, indices.size()});
170171
}
171172

172-
std::vector<std::vector<Index>> subtypeGraph(types.size());
173+
std::vector<std::vector<Index>> typeOrderGraph(types.size());
173174
for (Index i = 0; i < types.size(); ++i) {
174175
if (auto super = types[i].getDeclaredSuperType()) {
175176
if (auto it = indices.find(*super); it != indices.end()) {
176-
subtypeGraph[it->second].push_back(i);
177+
typeOrderGraph[it->second].push_back(i);
177178
}
178179
}
180+
if (auto desc = types[i].getDescribedType()) {
181+
// Described types must be in the same SCC / rec group.
182+
auto it = indices.find(*desc);
183+
assert(it != indices.end());
184+
typeOrderGraph[it->second].push_back(i);
185+
}
179186
}
180-
return subtypeGraph;
187+
return typeOrderGraph;
181188
}
182189

183190
struct RecGroupInfo;
@@ -199,13 +206,13 @@ struct GroupClassInfo {
199206
// group, offset by 1 iff there is a brand type. Used to ensure that we only
200207
// find emit permutations that respect the constraint that supertypes must be
201208
// ordered before subtypes.
202-
std::vector<std::vector<Index>> subtypeGraph;
209+
std::vector<std::vector<Index>> typeOrderGraph;
203210
// A generator of valid permutations of the components in this class.
204211
TopologicalOrders orders;
205212

206-
// Initialize `subtypeGraph` and `orders` based on the canonical ordering
213+
// Initialize `typeOrderGraph` and `orders` based on the canonical ordering
207214
// encoded by the group and permutation in `info`.
208-
static std::vector<std::vector<Index>> initSubtypeGraph(RecGroupInfo& info);
215+
static std::vector<std::vector<Index>> initTypeOrderGraph(RecGroupInfo& info);
209216
GroupClassInfo(RecGroupInfo& info);
210217

211218
void advance(FeatureSet features) {
@@ -222,10 +229,10 @@ struct GroupClassInfo {
222229
brand.emplace();
223230
// Make room in the subtype graph for the brand type, which goes at the
224231
// beginning of the canonical order.
225-
subtypeGraph.insert(subtypeGraph.begin(), {{}});
232+
typeOrderGraph.insert(typeOrderGraph.begin(), {{}});
226233
// Adjust indices.
227-
for (Index i = 1; i < subtypeGraph.size(); ++i) {
228-
for (auto& edge : subtypeGraph[i]) {
234+
for (Index i = 1; i < typeOrderGraph.size(); ++i) {
235+
for (auto& edge : typeOrderGraph[i]) {
229236
++edge;
230237
}
231238
}
@@ -237,7 +244,7 @@ struct GroupClassInfo {
237244
}
238245
// Start back at the initial permutation with the new brand.
239246
orders.~TopologicalOrders();
240-
new (&orders) TopologicalOrders(subtypeGraph);
247+
new (&orders) TopologicalOrders(typeOrderGraph);
241248
}
242249

243250
// Permute the types in the given group to match the current configuration in
@@ -266,7 +273,7 @@ struct RecGroupInfo {
266273
};
267274

268275
std::vector<std::vector<Index>>
269-
GroupClassInfo::initSubtypeGraph(RecGroupInfo& info) {
276+
GroupClassInfo::initTypeOrderGraph(RecGroupInfo& info) {
270277
assert(!info.classInfo);
271278
assert(info.permutation.size() == info.group.size());
272279

@@ -275,19 +282,19 @@ GroupClassInfo::initSubtypeGraph(RecGroupInfo& info) {
275282
canonical[info.permutation[i]] = info.group[i];
276283
}
277284

278-
return createSubtypeGraph(canonical);
285+
return createTypeOrderGraph(canonical);
279286
}
280287

281288
GroupClassInfo::GroupClassInfo(RecGroupInfo& info)
282289
: singletonType(info.group.size() == 1
283290
? std::optional<HeapType>(info.group[0])
284291
: std::nullopt),
285-
brand(std::nullopt), subtypeGraph(initSubtypeGraph(info)),
286-
orders(subtypeGraph) {}
292+
brand(std::nullopt), typeOrderGraph(initTypeOrderGraph(info)),
293+
orders(typeOrderGraph) {}
287294

288295
void GroupClassInfo::permute(RecGroupInfo& info) {
289296
assert(info.group.size() == info.permutation.size());
290-
bool insertingBrand = info.group.size() < subtypeGraph.size();
297+
bool insertingBrand = info.group.size() < typeOrderGraph.size();
291298
// First, un-permute the group to get back to the canonical order, offset by 1
292299
// if we are newly inserting a brand.
293300
std::vector<HeapType> canonical(info.group.size() + insertingBrand);
@@ -422,9 +429,9 @@ struct MinimizeRecGroups : Pass {
422429
groups.emplace_back();
423430

424431
// The SCC is not necessarily topologically sorted to have the supertypes
425-
// come first. Fix that.
432+
// and described types come first. Fix that.
426433
std::vector<HeapType> sccTypes(scc.begin(), scc.end());
427-
auto deps = createSubtypeGraph(sccTypes);
434+
auto deps = createTypeOrderGraph(sccTypes);
428435
auto permutation = *TopologicalOrders(deps).begin();
429436
groups.back().group.resize(sccTypes.size());
430437
for (Index i = 0; i < sccTypes.size(); ++i) {

src/wasm/wasm-type-shape.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,17 @@ template<typename CompareTypes> struct RecGroupComparator {
6464
if (a.isOpen() != b.isOpen()) {
6565
return a.isOpen() < b.isOpen() ? LT : GT;
6666
}
67-
auto aSuper = a.getDeclaredSuperType();
68-
auto bSuper = b.getDeclaredSuperType();
69-
if (aSuper.has_value() != bSuper.has_value()) {
70-
return aSuper.has_value() < bSuper.has_value() ? LT : GT;
67+
if (auto cmp = compare(a.getDeclaredSuperType(), b.getDeclaredSuperType());
68+
cmp != EQ) {
69+
return cmp;
7170
}
72-
if (aSuper) {
73-
if (auto cmp = compare(*aSuper, *bSuper); cmp != EQ) {
74-
return cmp;
75-
}
71+
if (auto cmp = compare(a.getDescriptorType(), b.getDescriptorType());
72+
cmp != EQ) {
73+
return cmp;
74+
}
75+
if (auto cmp = compare(a.getDescribedType(), b.getDescribedType());
76+
cmp != EQ) {
77+
return cmp;
7678
}
7779
auto aKind = a.getKind();
7880
auto bKind = b.getKind();
@@ -202,6 +204,16 @@ template<typename CompareTypes> struct RecGroupComparator {
202204
// comparator.
203205
return compareTypes(a, b);
204206
}
207+
208+
Comparison compare(std::optional<HeapType> a, std::optional<HeapType> b) {
209+
if (a.has_value() != b.has_value()) {
210+
return a.has_value() < b.has_value() ? LT : GT;
211+
}
212+
if (a) {
213+
return compare(*a, *b);
214+
}
215+
return EQ;
216+
}
205217
};
206218

207219
// Deduction guide to satisfy -Wctad-maybe-unsupported.
@@ -227,11 +239,9 @@ struct RecGroupHasher {
227239
size_t hashDefinition(HeapType type) {
228240
size_t digest = wasm::hash(type.isShared());
229241
wasm::rehash(digest, type.isOpen());
230-
auto super = type.getDeclaredSuperType();
231-
wasm::rehash(digest, super.has_value());
232-
if (super) {
233-
hash_combine(digest, hash(*super));
234-
}
242+
hash_combine(digest, hash(type.getDeclaredSuperType()));
243+
hash_combine(digest, hash(type.getDescriptorType()));
244+
hash_combine(digest, hash(type.getDescribedType()));
235245
auto kind = type.getKind();
236246
// Mix in very random numbers to differentiate the kinds.
237247
switch (kind) {
@@ -326,6 +336,14 @@ struct RecGroupHasher {
326336
wasm::rehash(digest, type.getID());
327337
return digest;
328338
}
339+
340+
size_t hash(std::optional<HeapType> type) {
341+
size_t digest = wasm::hash(type.has_value());
342+
if (type) {
343+
hash_combine(digest, hash(*type));
344+
}
345+
return digest;
346+
}
329347
};
330348

331349
Comparison compareComparable(const ComparableRecGroupShape& a,

0 commit comments

Comments
 (0)