18
18
// Apply more specific subtypes to type fields where possible, where all the
19
19
// writes to that field in the entire program allow doing so.
20
20
//
21
+ // TODO: handle arrays and not just structs.
22
+ //
23
+ // The GUFA variant of this uses GUFA to infer types, which performs a (slow)
24
+ // whole-program inference, rather than just scan struct/array operations by
25
+ // themselves.
26
+ //
21
27
22
28
#include " ir/lubs.h"
29
+ #include " ir/possible-contents.h"
23
30
#include " ir/struct-utils.h"
24
31
#include " ir/type-updating.h"
25
32
#include " ir/utils.h"
@@ -104,8 +111,16 @@ struct TypeRefining : public Pass {
104
111
// Only affects GC type declarations and struct.gets.
105
112
bool requiresNonNullableLocalFixups () override { return false ; }
106
113
114
+ bool gufa;
115
+
116
+ TypeRefining (bool gufa) : gufa(gufa) {}
117
+
118
+ // The final information we inferred about struct usage, that we then use to
119
+ // optimize.
107
120
StructUtils::StructValuesMap<FieldInfo> finalInfos;
108
121
122
+ using Propagator = StructUtils::TypeHierarchyPropagator<FieldInfo>;
123
+
109
124
void run (Module* module ) override {
110
125
if (!module ->features .hasGC ()) {
111
126
return ;
@@ -115,6 +130,20 @@ struct TypeRefining : public Pass {
115
130
Fatal () << " TypeRefining requires --closed-world" ;
116
131
}
117
132
133
+ Propagator propagator (*module );
134
+
135
+ // Compute our main data structure, finalInfos, either normally or using
136
+ // GUFA.
137
+ if (!gufa) {
138
+ computeFinalInfos (module , propagator);
139
+ } else {
140
+ computeFinalInfosGUFA (module , propagator);
141
+ }
142
+
143
+ useFinalInfos (module , propagator);
144
+ }
145
+
146
+ void computeFinalInfos (Module* module , Propagator& propagator) {
118
147
// Find and analyze struct operations inside each function.
119
148
StructUtils::FunctionStructValuesMap<FieldInfo> functionNewInfos (*module ),
120
149
functionSetGetInfos (*module );
@@ -132,14 +161,39 @@ struct TypeRefining : public Pass {
132
161
// able to contain that type. Propagate things written using set to subtypes
133
162
// as well, as the reference might be to a supertype if the field is present
134
163
// there.
135
- StructUtils::TypeHierarchyPropagator<FieldInfo> propagator (*module );
136
164
propagator.propagateToSuperTypes (combinedNewInfos);
137
165
propagator.propagateToSuperAndSubTypes (combinedSetGetInfos);
138
166
139
167
// Combine everything together.
140
168
combinedNewInfos.combineInto (finalInfos);
141
169
combinedSetGetInfos.combineInto (finalInfos);
170
+ }
171
+
172
+ void computeFinalInfosGUFA (Module* module , Propagator& propagator) {
173
+ // Compute the oracle, then simply apply it.
174
+ // TODO: Consider doing this in GUFA.cpp, where we already computed the
175
+ // oracle. That would require refactoring out the rest of this pass to
176
+ // a shared location. Alternatively, perhaps we can reuse the computed
177
+ // oracle, but any pass that changes anything would need to invalidate
178
+ // it...
179
+ ContentOracle oracle (*module , getPassOptions ());
180
+ auto allTypes = ModuleUtils::collectHeapTypes (*module );
181
+ for (auto type : allTypes) {
182
+ if (type.isStruct ()) {
183
+ auto & fields = type.getStruct ().fields ;
184
+ auto & infos = finalInfos[type];
185
+ for (Index i = 0 ; i < fields.size (); i++) {
186
+ auto gufaType = oracle.getContents (DataLocation{type, i}).getType ();
187
+ infos[i] = LUBFinder (gufaType);
188
+ }
189
+ }
190
+ }
191
+
192
+ // Propagate to supertypes, so no field is less refined than its super.
193
+ propagator.propagateToSuperTypes (finalInfos);
194
+ }
142
195
196
+ void useFinalInfos (Module* module , Propagator& propagator) {
143
197
// While we do the following work, see if we have anything to optimize, so
144
198
// that we can avoid wasteful work later if not.
145
199
bool canOptimize = false ;
@@ -427,6 +481,7 @@ struct TypeRefining : public Pass {
427
481
428
482
} // anonymous namespace
429
483
430
- Pass* createTypeRefiningPass () { return new TypeRefining (); }
484
+ Pass* createTypeRefiningPass () { return new TypeRefining (false ); }
485
+ Pass* createTypeRefiningGUFAPass () { return new TypeRefining (true ); }
431
486
432
487
} // namespace wasm
0 commit comments