1919
2020#include " ir/properties.h"
2121#include " ir/subtypes.h"
22+ #include " wasm-type.h"
2223#include " wasm.h"
2324
2425namespace wasm {
@@ -88,19 +89,24 @@ template<typename T> struct StructValues : public std::vector<T> {
8889// Also provides a combineInto() helper that combines one map into another. This
8990// depends on the underlying T defining a combine() method.
9091template <typename T>
91- struct StructValuesMap : public std ::unordered_map<HeapType, StructValues<T>> {
92+ struct StructValuesMap
93+ : public std::unordered_map<std::pair<HeapType, Exactness>, StructValues<T>> {
9294 // When we access an item, if it does not already exist, create it with a
9395 // vector of the right length for that type.
94- StructValues<T>& operator [](HeapType type) {
95- assert (type.isStruct ());
96+ StructValues<T>& operator [](std::pair< HeapType, Exactness> type) {
97+ assert (type.first . isStruct ());
9698 auto inserted = this ->insert ({type, {}});
9799 auto & values = inserted.first ->second ;
98100 if (inserted.second ) {
99- values.resize (type.getStruct ().fields .size ());
101+ values.resize (type.first . getStruct ().fields .size ());
100102 }
101103 return values;
102104 }
103105
106+ StructValues<T>& operator [](HeapType type) {
107+ return (*this )[{type, Inexact}];
108+ }
109+
104110 void combineInto (StructValuesMap<T>& combinedInfos) const {
105111 for (auto & [type, info] : *this ) {
106112 for (Index i = 0 ; i < info.size (); i++) {
@@ -113,7 +119,8 @@ struct StructValuesMap : public std::unordered_map<HeapType, StructValues<T>> {
113119 void dump (std::ostream& o) {
114120 o << " dump " << this << ' \n ' ;
115121 for (auto & [type, vec] : (*this )) {
116- o << " dump " << type << " " << &vec << ' ' ;
122+ o << " dump " << type.first << (type.second == Exact ? " exact " : " " )
123+ << &vec << ' ' ;
117124 for (auto x : vec) {
118125 x.dump (o);
119126 o << " " ;
@@ -203,7 +210,8 @@ struct StructScanner
203210 // Note writes to all the fields of the struct.
204211 auto heapType = type.getHeapType ();
205212 auto & fields = heapType.getStruct ().fields ;
206- auto & infos = functionNewInfos[this ->getFunction ()][heapType];
213+ auto ht = std::make_pair (heapType, Exact);
214+ auto & infos = functionNewInfos[this ->getFunction ()][ht];
207215 for (Index i = 0 ; i < fields.size (); i++) {
208216 if (curr->isWithDefault ()) {
209217 self ().noteDefault (fields[i].type , heapType, i, infos[i]);
@@ -224,11 +232,12 @@ struct StructScanner
224232 }
225233
226234 // Note a write to this field of the struct.
227- noteExpressionOrCopy (curr->value ,
228- type.getHeapType (),
229- curr->index ,
230- functionSetGetInfos[this ->getFunction ()]
231- [type.getHeapType ()][curr->index ]);
235+ auto ht = std::make_pair (type.getHeapType (), type.getExactness ());
236+ noteExpressionOrCopy (
237+ curr->value ,
238+ type.getHeapType (),
239+ curr->index ,
240+ functionSetGetInfos[this ->getFunction ()][ht][curr->index ]);
232241 }
233242
234243 void visitStructGet (StructGet* curr) {
@@ -237,11 +246,11 @@ struct StructScanner
237246 return ;
238247 }
239248
240- auto heapType = type.getHeapType ();
249+ auto ht = std::make_pair ( type.getHeapType (), type. getExactness () );
241250 auto index = curr->index ;
242- self ().noteRead (heapType ,
251+ self ().noteRead (type. getHeapType () ,
243252 index,
244- functionSetGetInfos[this ->getFunction ()][heapType ][index]);
253+ functionSetGetInfos[this ->getFunction ()][ht ][index]);
245254 }
246255
247256 void visitStructRMW (StructRMW* curr) {
@@ -251,9 +260,9 @@ struct StructScanner
251260 }
252261
253262 auto heapType = type.getHeapType ();
263+ auto ht = std::make_pair (heapType, type.getExactness ());
254264 auto index = curr->index ;
255- auto & info =
256- functionSetGetInfos[this ->getFunction ()][type.getHeapType ()][index];
265+ auto & info = functionSetGetInfos[this ->getFunction ()][ht][index];
257266
258267 if (curr->op == RMWXchg) {
259268 // An xchg is really like a read and write combined.
@@ -274,9 +283,9 @@ struct StructScanner
274283 }
275284
276285 auto heapType = type.getHeapType ();
286+ auto ht = std::make_pair (heapType, type.getExactness ());
277287 auto index = curr->index ;
278- auto & info =
279- functionSetGetInfos[this ->getFunction ()][type.getHeapType ()][curr->index ];
288+ auto & info = functionSetGetInfos[this ->getFunction ()][ht][index];
280289
281290 // A cmpxchg is like a read and conditional write.
282291 self ().noteRead (heapType, index, info);
@@ -310,11 +319,12 @@ struct StructScanner
310319 return ;
311320 }
312321 auto heapType = type.getHeapType ();
322+ auto ht = std::make_pair (heapType, type.getExactness ());
313323 if (heapType.isStruct ()) {
314324 // Any subtype of the reference here may be read from.
315325 self ().noteRead (heapType,
316326 DescriptorIndex,
317- functionSetGetInfos[this ->getFunction ()][heapType ].desc );
327+ functionSetGetInfos[this ->getFunction ()][ht ].desc );
318328 return ;
319329 }
320330 }
@@ -372,13 +382,19 @@ template<typename T> class TypeHierarchyPropagator {
372382 // Propagate given a StructValuesMap, which means we need to take into
373383 // account fields.
374384 void propagateToSuperTypes (StructValuesMap<T>& infos) {
375- propagate (infos, false , true );
385+ propagate (infos, false , true , true );
376386 }
377387 void propagateToSubTypes (StructValuesMap<T>& infos) {
378- propagate (infos, true , false );
388+ propagate (infos, true , false , false );
389+ }
390+ void propagateToSubTypesWithExact (StructValuesMap<T>& infos) {
391+ propagate (infos, true , false , true );
379392 }
380393 void propagateToSuperAndSubTypes (StructValuesMap<T>& infos) {
381- propagate (infos, true , true );
394+ propagate (infos, true , true , false );
395+ }
396+ void propagateToSuperAndSubTypesWithExact (StructValuesMap<T>& infos) {
397+ propagate (infos, true , true , true );
382398 }
383399
384400 // Propagate on a simpler map of structs and infos (that is, not using
@@ -398,46 +414,63 @@ template<typename T> class TypeHierarchyPropagator {
398414private:
399415 void propagate (StructValuesMap<T>& combinedInfos,
400416 bool toSubTypes,
401- bool toSuperTypes) {
402- UniqueDeferredQueue<HeapType> work;
403- for (auto & [type, _] : combinedInfos) {
404- work.push (type);
417+ bool toSuperTypes,
418+ bool includeExact) {
419+ UniqueDeferredQueue<std::pair<HeapType, Exactness>> work;
420+ for (auto & [ht, _] : combinedInfos) {
421+ work.push (ht);
405422 }
406423 while (!work.empty ()) {
407- auto type = work.pop ();
408- auto & infos = combinedInfos[type];
424+ auto [ type, exactness] = work.pop ();
425+ auto & infos = combinedInfos[{ type, exactness} ];
409426
410427 if (toSuperTypes) {
411- // Propagate shared fields to the supertype.
412- if (auto superType = type.getDeclaredSuperType ()) {
413- auto & superInfos = combinedInfos[*superType];
414- auto & superFields = superType->getStruct ().fields ;
415- for (Index i = 0 ; i < superFields.size (); i++) {
428+ // Propagate shared fields to the supertype, which may be the inexact
429+ // version of the same type.
430+ std::optional<std::pair<HeapType, Exactness>> super;
431+ if (exactness == Exact) {
432+ super = {type, Inexact};
433+ } else if (auto superType = type.getDeclaredSuperType ()) {
434+ super = {*superType, Inexact};
435+ }
436+ if (super) {
437+ auto & superInfos = combinedInfos[*super];
438+ const auto & superFields = &super->first .getStruct ().fields ;
439+ for (Index i = 0 ; i < superFields->size (); i++) {
416440 if (superInfos[i].combine (infos[i])) {
417- work.push (*superType );
441+ work.push (*super );
418442 }
419443 }
420444 // Propagate the descriptor to the super, if the super has one.
421- if (superType-> getDescriptorType () &&
445+ if (super-> first . getDescriptorType () &&
422446 superInfos.desc .combine (infos.desc )) {
423- work.push (*superType );
447+ work.push (*super );
424448 }
425449 }
426450 }
427451
428452 if (toSubTypes) {
429- // Propagate shared fields to the subtypes.
453+ // Propagate shared fields to the subtypes, which may just be the exact
454+ // version of the same type.
430455 auto numFields = type.getStruct ().fields .size ();
431- for (auto subType : subTypes.getImmediateSubTypes (type)) {
432- auto & subInfos = combinedInfos[subType];
456+ std::vector<std::pair<HeapType, Exactness>> subs;
457+ if (includeExact && exactness == Inexact) {
458+ subs = {{type, Exact}};
459+ } else {
460+ for (auto subType : subTypes.getImmediateSubTypes (type)) {
461+ subs.emplace_back (subType, Inexact);
462+ }
463+ }
464+ for (auto sub : subs) {
465+ auto & subInfos = combinedInfos[sub];
433466 for (Index i = 0 ; i < numFields; i++) {
434467 if (subInfos[i].combine (infos[i])) {
435- work.push (subType );
468+ work.push (sub );
436469 }
437470 }
438471 // Propagate the descriptor.
439472 if (subInfos.desc .combine (infos.desc )) {
440- work.push (subType );
473+ work.push (sub );
441474 }
442475 }
443476 }
0 commit comments