24
24
#define OUTLINING_DEBUG 0
25
25
26
26
#if OUTLINING_DEBUG
27
- #define DBG (statement ) statement
27
+ #define ODBG (statement ) statement
28
28
#else
29
- #define DBG (statement )
29
+ #define ODBG (statement )
30
30
#endif
31
31
32
32
// Check a Result or MaybeResult for error and call Fatal() if the error exists.
37
37
38
38
namespace wasm {
39
39
40
+ struct OutliningSequence {
41
+ unsigned startIdx;
42
+ unsigned endIdx;
43
+ Name func;
44
+ bool endsTypeUnreachable;
45
+ #if OUTLINING_DEBUG
46
+ unsigned programIdx;
47
+ #endif
48
+
49
+ OutliningSequence (unsigned startIdx,
50
+ unsigned endIdx,
51
+ Name func,
52
+ bool endsTypeUnreachable
53
+ #if OUTLINING_DEBUG
54
+ ,
55
+ unsigned programIdx
56
+ #endif
57
+ )
58
+ : startIdx(startIdx), endIdx(endIdx), func(func),
59
+ endsTypeUnreachable (endsTypeUnreachable)
60
+ #if OUTLINING_DEBUG
61
+ ,
62
+ programIdx (programIdx)
63
+ #endif
64
+ {
65
+ }
66
+ };
67
+
40
68
// Instances of this walker are intended to walk a function at a time, at the
41
69
// behest of the owner of the instance.
42
70
struct ReconstructStringifyWalker
@@ -45,8 +73,8 @@ struct ReconstructStringifyWalker
45
73
ReconstructStringifyWalker (Module* wasm, Function* func)
46
74
: existingBuilder(*wasm), outlinedBuilder(*wasm), func(func) {
47
75
this ->setModule (wasm);
48
- DBG (std::cerr << " \n existingBuilder: " << &existingBuilder
49
- << " outlinedBuilder: " << &outlinedBuilder << " \n " );
76
+ ODBG (std::cerr << " \n existingBuilder: " << &existingBuilder
77
+ << " outlinedBuilder: " << &outlinedBuilder << " \n " );
50
78
}
51
79
52
80
// As we reconstruct the IR during outlining, we need to know what
@@ -91,25 +119,26 @@ struct ReconstructStringifyWalker
91
119
// starting a new function, as that resets the counters back to 0.
92
120
instrCounter++;
93
121
94
- DBG (std::string desc);
122
+ ODBG (std::string desc);
95
123
if (auto curr = reason.getBlockStart ()) {
124
+ ODBG (desc = " Block Start at " );
96
125
ASSERT_OK (existingBuilder.visitBlockStart (curr->block ));
97
- DBG (desc = " Block Start at " );
98
126
} else if (auto curr = reason.getIfStart ()) {
99
127
// IR builder needs the condition of the If pushed onto the builder before
100
128
// visitIfStart(), which will expect to be able to pop the condition.
101
129
// This is always okay to do because the correct condition was installed
102
130
// onto the If when the outer scope was visited.
103
131
existingBuilder.push (curr->iff ->condition );
132
+ ODBG (desc = " If Start at " );
104
133
ASSERT_OK (existingBuilder.visitIfStart (curr->iff ));
105
- DBG (desc = " If Start at " );
106
134
} else if (reason.getElseStart ()) {
135
+ ODBG (desc = " Else Start at " );
107
136
ASSERT_OK (existingBuilder.visitElse ());
108
- DBG (desc = " Else Start at " );
109
137
} else if (auto curr = reason.getLoopStart ()) {
138
+ ODBG (desc = " Loop Start at " );
110
139
ASSERT_OK (existingBuilder.visitLoopStart (curr->loop ));
111
- DBG (desc = " Loop Start at " );
112
140
} else if (reason.getEnd ()) {
141
+ ODBG (desc = " End at " );
113
142
ASSERT_OK (existingBuilder.visitEnd ());
114
143
// Reset the function in case we just ended the function scope.
115
144
existingBuilder.setFunction (func);
@@ -122,12 +151,11 @@ struct ReconstructStringifyWalker
122
151
// its expressions off the stack, so we must call build() after visitEnd()
123
152
// to clear the internal stack IRBuilder manages.
124
153
ASSERT_OK (existingBuilder.build ());
125
- DBG (desc = " End at " );
126
154
} else {
127
- DBG (desc = " addUniqueSymbol for unimplemented control flow " );
155
+ ODBG (desc = " addUniqueSymbol for unimplemented control flow " );
128
156
WASM_UNREACHABLE (" unimplemented control flow" );
129
157
}
130
- DBG (printAddUniqueSymbol (desc));
158
+ ODBG (printAddUniqueSymbol (desc));
131
159
}
132
160
133
161
void visitExpression (Expression* curr) {
@@ -151,7 +179,7 @@ struct ReconstructStringifyWalker
151
179
ASSERT_OK (builder->visit (curr));
152
180
}
153
181
}
154
- DBG (printVisitExpression (curr));
182
+ ODBG (printVisitExpression (curr));
155
183
156
184
if (state == InSeq || state == InSkipSeq) {
157
185
maybeEndSeq ();
@@ -165,9 +193,9 @@ struct ReconstructStringifyWalker
165
193
instrCounter = 0 ;
166
194
seqCounter = 0 ;
167
195
state = NotInSeq;
168
- DBG (std::cerr << " \n "
169
- << " Func Start to $" << func->name << " at "
170
- << &existingBuilder << " \n " );
196
+ ODBG (std::cerr << " \n "
197
+ << " Func Start to $" << func->name << " at "
198
+ << &existingBuilder << " \n " );
171
199
}
172
200
173
201
ReconstructState getCurrState () {
@@ -209,29 +237,41 @@ struct ReconstructStringifyWalker
209
237
getModule ()->getFunction (sequences[seqCounter].func );
210
238
ASSERT_OK (outlinedBuilder.visitFunctionStart (outlinedFunc));
211
239
212
- // Add a local.get instruction for every parameter of the outlined function.
213
- Signature sig = outlinedFunc->type .getSignature ();
214
- for (Index i = 0 ; i < sig.params .size (); i++) {
215
- ASSERT_OK (outlinedBuilder.makeLocalGet (i));
216
- }
217
-
218
240
// Make a call from the existing function to the outlined function. This
219
241
// call will replace the instructions moved to the outlined function.
242
+ ODBG (std::cerr << " \n adding call " << outlinedFunc->name << " to "
243
+ << &existingBuilder << " \n " );
220
244
ASSERT_OK (existingBuilder.makeCall (outlinedFunc->name , false ));
221
- DBG (std::cerr << " \n created outlined fn: " << outlinedFunc->name << " \n " );
222
245
223
246
// If the last instruction of the outlined sequence is unreachable, insert
224
247
// an unreachable instruction immediately after the call to the outlined
225
248
// function. This maintains the unreachable type in the original scope
226
249
// of the outlined sequence.
227
250
if (sequences[seqCounter].endsTypeUnreachable ) {
251
+ ODBG (std::cerr << " \n adding endsUnreachable to " << &existingBuilder
252
+ << " \n " );
228
253
ASSERT_OK (existingBuilder.makeUnreachable ());
229
254
}
255
+
256
+ // Add a local.get instruction for every parameter of the outlined function.
257
+ Signature sig = outlinedFunc->type .getSignature ();
258
+ ODBG (std::cerr << outlinedFunc->name << " takes " << sig.params .size ()
259
+ << " parameters\n " );
260
+ for (Index i = 0 ; i < sig.params .size (); i++) {
261
+ ODBG (std::cerr << " adding local.get $" << i << " to " << &outlinedBuilder
262
+ << " \n " );
263
+ ASSERT_OK (outlinedBuilder.makeLocalGet (i));
264
+ }
230
265
}
231
266
232
267
void transitionToInSkipSeq () {
233
268
Function* outlinedFunc =
234
269
getModule ()->getFunction (sequences[seqCounter].func );
270
+ ODBG (std::cerr << " \n starting to skip instructions "
271
+ << sequences[seqCounter].startIdx << " - "
272
+ << sequences[seqCounter].endIdx - 1 << " to "
273
+ << sequences[seqCounter].func
274
+ << " and adding call() instead\n " );
235
275
ASSERT_OK (existingBuilder.makeCall (outlinedFunc->name , false ));
236
276
// If the last instruction of the outlined sequence is unreachable, insert
237
277
// an unreachable instruction immediately after the call to the outlined
@@ -240,11 +280,6 @@ struct ReconstructStringifyWalker
240
280
if (sequences[seqCounter].endsTypeUnreachable ) {
241
281
ASSERT_OK (existingBuilder.makeUnreachable ());
242
282
}
243
- DBG (std::cerr << " \n starting to skip instructions "
244
- << sequences[seqCounter].startIdx << " - "
245
- << sequences[seqCounter].endIdx - 1 << " to "
246
- << sequences[seqCounter].func
247
- << " and adding call() instead\n " );
248
283
}
249
284
250
285
void maybeEndSeq () {
@@ -255,12 +290,12 @@ struct ReconstructStringifyWalker
255
290
}
256
291
257
292
void transitionToNotInSeq () {
258
- DBG (std::cerr << " End of sequence " );
293
+ ODBG (std::cerr << " End of sequence " );
259
294
if (state == InSeq) {
295
+ ODBG (std::cerr << " to " << &outlinedBuilder);
260
296
ASSERT_OK (outlinedBuilder.visitEnd ());
261
- DBG (std::cerr << " to " << &outlinedBuilder);
262
297
}
263
- DBG (std::cerr << " \n\n " );
298
+ ODBG (std::cerr << " \n\n " );
264
299
// Completed a sequence so increase the seqCounter and reset the state.
265
300
seqCounter++;
266
301
}
@@ -288,11 +323,11 @@ struct Outlining : public Pass {
288
323
HashStringifyWalker stringify;
289
324
// Walk the module and create a "string representation" of the program.
290
325
stringify.walkModule (module);
326
+ ODBG (printHashString (stringify.hashString , stringify.exprs ));
291
327
// Collect all of the substrings of the string representation that appear
292
328
// more than once in the program.
293
329
auto substrings =
294
330
StringifyProcessor::repeatSubstrings (stringify.hashString );
295
- DBG (printHashString (stringify.hashString , stringify.exprs ));
296
331
// Remove substrings that are substrings of longer repeat substrings.
297
332
substrings = StringifyProcessor::dedupe (substrings);
298
333
// Remove substrings with overlapping indices.
@@ -317,7 +352,13 @@ struct Outlining : public Pass {
317
352
// are relative to the enclosing function while substrings have indices
318
353
// relative to the entire program.
319
354
auto sequences = makeSequences (module, substrings, stringify);
320
- outline (module, sequences);
355
+ outline (module,
356
+ sequences
357
+ #if OUTLINING_DEBUG
358
+ ,
359
+ stringify
360
+ #endif
361
+ );
321
362
// Position the outlined functions first in the functions vector to make
322
363
// the outlining lit tests far more readable.
323
364
moveOutlinedFunctions (module, substrings.size ());
@@ -371,14 +412,25 @@ struct Outlining : public Pass {
371
412
relativeIdx + substring.Length ,
372
413
func,
373
414
stringify.exprs [seqIdx + substring.Length - 1 ]->type ==
374
- Type::unreachable);
415
+ Type::unreachable
416
+ #if OUTLINING_DEBUG
417
+ ,
418
+ seqIdx
419
+ #endif
420
+ );
375
421
seqByFunc[existingFunc].push_back (seq);
376
422
}
377
423
}
378
424
return seqByFunc;
379
425
}
380
426
381
- void outline (Module* module, Sequences seqByFunc) {
427
+ void outline (Module* module,
428
+ Sequences seqByFunc
429
+ #if OUTLINING_DEBUG
430
+ ,
431
+ const HashStringifyWalker& stringify
432
+ #endif
433
+ ) {
382
434
// TODO: Make this a function-parallel sub-pass.
383
435
std::vector<Name> keys (seqByFunc.size ());
384
436
std::transform (seqByFunc.begin (),
@@ -398,6 +450,11 @@ struct Outlining : public Pass {
398
450
});
399
451
ReconstructStringifyWalker reconstruct (module, module->getFunction (func));
400
452
reconstruct.sequences = std::move (seqByFunc[func]);
453
+ ODBG (printReconstruct (module,
454
+ stringify.hashString ,
455
+ stringify.exprs ,
456
+ func,
457
+ reconstruct.sequences ));
401
458
reconstruct.doWalkFunction (module->getFunction (func));
402
459
}
403
460
}
@@ -433,6 +490,32 @@ struct Outlining : public Pass {
433
490
}
434
491
}
435
492
}
493
+ void printReconstruct (Module* module,
494
+ const std::vector<uint32_t >& hashString,
495
+ const std::vector<Expression*>& exprs,
496
+ Name existingFunc,
497
+ const std::vector<OutliningSequence>& seqs) {
498
+ std::cerr << " \n\n Reconstructing existing fn: " << existingFunc << " \n " ;
499
+ std::cerr << " moving sequences: "
500
+ << " \n " ;
501
+ for (auto & seq : seqs) {
502
+ for (Index idx = seq.programIdx ;
503
+ idx < seq.programIdx + (seq.endIdx - seq.startIdx );
504
+ idx++) {
505
+ Expression* expr = exprs[idx];
506
+ if (expr == nullptr ) {
507
+ std::cerr << " unique symbol\n " ;
508
+ } else {
509
+ std::cerr << idx << " - " << hashString[idx] << " - " << seq.startIdx
510
+ << " : " << ShallowExpression{expr} << " \n " ;
511
+ }
512
+ }
513
+ std::cerr << " to outlined function: " << seq.func << " \n " ;
514
+ auto outlinedFunction = module->getFunction (seq.func );
515
+ std::cerr << " with signature: " << outlinedFunction->type .toString ()
516
+ << " \n " ;
517
+ }
518
+ }
436
519
#endif
437
520
};
438
521
0 commit comments