@@ -53,6 +53,16 @@ namespace llvm {
53
53
// Forward declarations of an update tracking API used in the pass manager.
54
54
class LPMUpdater ;
55
55
56
+ namespace {
57
+
58
+ template <typename PassT>
59
+ using HasRunOnLoopT = decltype (std::declval<PassT>().run(
60
+ std::declval<Loop &>(), std::declval<LoopAnalysisManager &>(),
61
+ std::declval<LoopStandardAnalysisResults &>(),
62
+ std::declval<LPMUpdater &>()));
63
+
64
+ } // namespace
65
+
56
66
// Explicit specialization and instantiation declarations for the pass manager.
57
67
// See the comments on the definition of the specialization for details on how
58
68
// it differs from the primary template.
@@ -62,13 +72,6 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
62
72
: public PassInfoMixin<
63
73
PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
64
74
LPMUpdater &>> {
65
- private:
66
- template <typename PassT>
67
- using HasRunOnLoopT = decltype (std::declval<PassT>().run(
68
- std::declval<Loop &>(), std::declval<LoopAnalysisManager &>(),
69
- std::declval<LoopStandardAnalysisResults &>(),
70
- std::declval<LPMUpdater &>()));
71
-
72
75
public:
73
76
// / Construct a pass manager.
74
77
// /
@@ -154,6 +157,9 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
154
157
155
158
static bool isRequired () { return true ; }
156
159
160
+ size_t getNumLoopPasses () const { return LoopPasses.size (); }
161
+ size_t getNumLoopNestPasses () const { return LoopNestPasses.size (); }
162
+
157
163
protected:
158
164
using LoopPassConceptT =
159
165
detail::PassConcept<Loop, LoopAnalysisManager,
@@ -227,6 +233,13 @@ class FunctionToLoopPassAdaptor;
227
233
// / A reference to an instance of this class is passed as an argument to each
228
234
// / Loop pass, and Loop passes should use it to update LPM infrastructure if
229
235
// / they modify the loop nest structure.
236
+ // /
237
+ // / \c LPMUpdater comes with two modes: the loop mode and the loop-nest mode. In
238
+ // / loop mode, all the loops in the function will be pushed into the worklist
239
+ // / and when new loops are added to the pipeline, their subloops are also
240
+ // / inserted recursively. On the other hand, in loop-nest mode, only top-level
241
+ // / loops are contained in the worklist and the addition of new (top-level)
242
+ // / loops will not trigger the addition of their subloops.
230
243
class LPMUpdater {
231
244
public:
232
245
// / This can be queried by loop passes which run other loop passes (like pass
@@ -248,6 +261,8 @@ class LPMUpdater {
248
261
// / state, this routine will mark that the current loop should be skipped by
249
262
// / the rest of the pass management infrastructure.
250
263
void markLoopAsDeleted (Loop &L, llvm::StringRef Name) {
264
+ assert ((!LoopNestMode || L.isOutermost ()) &&
265
+ " L should be a top-level loop in loop-nest mode." );
251
266
LAM.clear (L, Name);
252
267
assert ((&L == CurrentL || CurrentL->contains (&L)) &&
253
268
" Cannot delete a loop outside of the "
@@ -263,6 +278,8 @@ class LPMUpdater {
263
278
// / loops within them will be visited in postorder as usual for the loop pass
264
279
// / manager.
265
280
void addChildLoops (ArrayRef<Loop *> NewChildLoops) {
281
+ assert (!LoopNestMode &&
282
+ " Child loops should not be pushed in loop-nest mode." );
266
283
// Insert ourselves back into the worklist first, as this loop should be
267
284
// revisited after all the children have been processed.
268
285
Worklist.insert (CurrentL);
@@ -294,7 +311,10 @@ class LPMUpdater {
294
311
" All of the new loops must be siblings of the current loop!" );
295
312
#endif
296
313
297
- appendLoopsToWorklist (NewSibLoops, Worklist);
314
+ if (LoopNestMode)
315
+ Worklist.insert (NewSibLoops);
316
+ else
317
+ appendLoopsToWorklist (NewSibLoops, Worklist);
298
318
299
319
// No need to skip the current loop or revisit it, as sibling loops
300
320
// shouldn't impact anything.
@@ -324,6 +344,7 @@ class LPMUpdater {
324
344
325
345
Loop *CurrentL;
326
346
bool SkipCurrentLoop;
347
+ const bool LoopNestMode;
327
348
328
349
#ifndef NDEBUG
329
350
// In debug builds we also track the parent loop to implement asserts even in
@@ -332,8 +353,8 @@ class LPMUpdater {
332
353
#endif
333
354
334
355
LPMUpdater (SmallPriorityWorklist<Loop *, 4 > &Worklist,
335
- LoopAnalysisManager &LAM)
336
- : Worklist(Worklist), LAM(LAM) {}
356
+ LoopAnalysisManager &LAM, bool LoopNestMode = false )
357
+ : Worklist(Worklist), LAM(LAM), LoopNestMode(LoopNestMode) {}
337
358
};
338
359
339
360
template <typename IRUnitT, typename PassT>
@@ -366,6 +387,15 @@ Optional<PreservedAnalyses> LoopPassManager::runSinglePass(
366
387
// / FunctionAnalysisManager it will run the \c LoopAnalysisManagerFunctionProxy
367
388
// / analysis prior to running the loop passes over the function to enable a \c
368
389
// / LoopAnalysisManager to be used within this run safely.
390
+ // /
391
+ // / The adaptor comes with two modes: the loop mode and the loop-nest mode, and
392
+ // / the worklist updater lived inside will be in the same mode as the adaptor
393
+ // / (refer to the documentation of \c LPMUpdater for more detailed explanation).
394
+ // / Specifically, in loop mode, all loops in the funciton will be pushed into
395
+ // / the worklist and processed by \p Pass, while only top-level loops are
396
+ // / processed in loop-nest mode. Please refer to the various specializations of
397
+ // / \fn createLoopFunctionToLoopPassAdaptor to see when loop mode and loop-nest
398
+ // / mode are used.
369
399
class FunctionToLoopPassAdaptor
370
400
: public PassInfoMixin<FunctionToLoopPassAdaptor> {
371
401
public:
@@ -376,10 +406,12 @@ class FunctionToLoopPassAdaptor
376
406
explicit FunctionToLoopPassAdaptor (std::unique_ptr<PassConceptT> Pass,
377
407
bool UseMemorySSA = false ,
378
408
bool UseBlockFrequencyInfo = false ,
379
- bool DebugLogging = false )
409
+ bool DebugLogging = false ,
410
+ bool LoopNestMode = false )
380
411
: Pass(std::move(Pass)), LoopCanonicalizationFPM(DebugLogging),
381
412
UseMemorySSA(UseMemorySSA),
382
- UseBlockFrequencyInfo(UseBlockFrequencyInfo) {
413
+ UseBlockFrequencyInfo(UseBlockFrequencyInfo),
414
+ LoopNestMode(LoopNestMode) {
383
415
LoopCanonicalizationFPM.addPass (LoopSimplifyPass ());
384
416
LoopCanonicalizationFPM.addPass (LCSSAPass ());
385
417
}
@@ -389,19 +421,25 @@ class FunctionToLoopPassAdaptor
389
421
390
422
static bool isRequired () { return true ; }
391
423
424
+ bool isLoopNestMode () const { return LoopNestMode; }
425
+
392
426
private:
393
427
std::unique_ptr<PassConceptT> Pass;
394
428
395
429
FunctionPassManager LoopCanonicalizationFPM;
396
430
397
431
bool UseMemorySSA = false ;
398
432
bool UseBlockFrequencyInfo = false ;
433
+ const bool LoopNestMode;
399
434
};
400
435
401
436
// / A function to deduce a loop pass type and wrap it in the templated
402
437
// / adaptor.
438
+ // /
439
+ // / If \p Pass is a loop pass, the returned adaptor will be in loop mode.
403
440
template <typename LoopPassT>
404
- FunctionToLoopPassAdaptor
441
+ inline std::enable_if_t <is_detected<HasRunOnLoopT, LoopPassT>::value,
442
+ FunctionToLoopPassAdaptor>
405
443
createFunctionToLoopPassAdaptor (LoopPassT Pass, bool UseMemorySSA = false ,
406
444
bool UseBlockFrequencyInfo = false ,
407
445
bool DebugLogging = false ) {
@@ -410,7 +448,46 @@ createFunctionToLoopPassAdaptor(LoopPassT Pass, bool UseMemorySSA = false,
410
448
LoopStandardAnalysisResults &, LPMUpdater &>;
411
449
return FunctionToLoopPassAdaptor (
412
450
std::make_unique<PassModelT>(std::move (Pass)), UseMemorySSA,
413
- UseBlockFrequencyInfo, DebugLogging);
451
+ UseBlockFrequencyInfo, DebugLogging, false );
452
+ }
453
+
454
+ // / If \p Pass is a loop-nest pass, \p Pass will first be wrapped into a
455
+ // / \c LoopPassManager and the returned adaptor will be in loop-nest mode.
456
+ template <typename LoopNestPassT>
457
+ inline std::enable_if_t <!is_detected<HasRunOnLoopT, LoopNestPassT>::value,
458
+ FunctionToLoopPassAdaptor>
459
+ createFunctionToLoopPassAdaptor (LoopNestPassT Pass, bool UseMemorySSA = false ,
460
+ bool UseBlockFrequencyInfo = false ,
461
+ bool DebugLogging = false ) {
462
+ LoopPassManager LPM (DebugLogging);
463
+ LPM.addPass (std::move (Pass));
464
+ using PassModelT =
465
+ detail::PassModel<Loop, LoopPassManager, PreservedAnalyses,
466
+ LoopAnalysisManager, LoopStandardAnalysisResults &,
467
+ LPMUpdater &>;
468
+ return FunctionToLoopPassAdaptor (std::make_unique<PassModelT>(std::move (LPM)),
469
+ UseMemorySSA, UseBlockFrequencyInfo,
470
+ DebugLogging, true );
471
+ }
472
+
473
+ // / If \p Pass is an instance of \c LoopPassManager, the returned adaptor will
474
+ // / be in loop-nest mode if the pass manager contains only loop-nest passes.
475
+ template <>
476
+ inline FunctionToLoopPassAdaptor
477
+ createFunctionToLoopPassAdaptor<LoopPassManager>(LoopPassManager LPM,
478
+ bool UseMemorySSA,
479
+ bool UseBlockFrequencyInfo,
480
+ bool DebugLogging) {
481
+ // Check if LPM contains any loop pass and if it does not, returns an adaptor
482
+ // in loop-nest mode.
483
+ using PassModelT =
484
+ detail::PassModel<Loop, LoopPassManager, PreservedAnalyses,
485
+ LoopAnalysisManager, LoopStandardAnalysisResults &,
486
+ LPMUpdater &>;
487
+ bool LoopNestMode = (LPM.getNumLoopPasses () == 0 );
488
+ return FunctionToLoopPassAdaptor (std::make_unique<PassModelT>(std::move (LPM)),
489
+ UseMemorySSA, UseBlockFrequencyInfo,
490
+ DebugLogging, LoopNestMode);
414
491
}
415
492
416
493
// / Pass for printing a loop's contents as textual IR.
0 commit comments