LLVM 23.0.0git
LoopPassManager.h
Go to the documentation of this file.
1//===- LoopPassManager.h - Loop pass management -----------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9///
10/// This header provides classes for managing a pipeline of passes over loops
11/// in LLVM IR.
12///
13/// The primary loop pass pipeline is managed in a very particular way to
14/// provide a set of core guarantees:
15/// 1) Loops are, where possible, in simplified form.
16/// 2) Loops are *always* in LCSSA form.
17/// 3) A collection of Loop-specific analysis results are available:
18/// - LoopInfo
19/// - DominatorTree
20/// - ScalarEvolution
21/// - AAManager
22/// 4) All loop passes preserve #1 (where possible), #2, and #3.
23/// 5) Loop passes run over each loop in the loop nest from the innermost to
24/// the outermost. Specifically, all inner loops are processed before
25/// passes run over outer loops. When running the pipeline across an inner
26/// loop creates new inner loops, those are added and processed in this
27/// order as well.
28///
29/// This process is designed to facilitate transformations which simplify,
30/// reduce, and remove loops. For passes which are more oriented towards
31/// optimizing loops, especially optimizing loop *nests* instead of single
32/// loops in isolation, this framework is less interesting.
33///
34//===----------------------------------------------------------------------===//
35
36#ifndef LLVM_TRANSFORMS_SCALAR_LOOPPASSMANAGER_H
37#define LLVM_TRANSFORMS_SCALAR_LOOPPASSMANAGER_H
38
44#include "llvm/IR/PassManager.h"
49#include <memory>
50
51namespace llvm {
52
53// Forward declarations of an update tracking API used in the pass manager.
54class LPMUpdater;
56
57namespace {
58
59template <typename PassT>
60using HasRunOnLoopT = decltype(std::declval<PassT>().run(
61 std::declval<Loop &>(), std::declval<LoopAnalysisManager &>(),
62 std::declval<LoopStandardAnalysisResults &>(),
63 std::declval<LPMUpdater &>()));
64
65} // namespace
66
67// Explicit specialization and instantiation declarations for the pass manager.
68// See the comments on the definition of the specialization for details on how
69// it differs from the primary template.
70template <>
72 LPMUpdater &>
73 : public RequiredPassInfoMixin<
75 LPMUpdater &>> {
76public:
77 explicit PassManager() = default;
78
79 // FIXME: These are equivalent to the default move constructor/move
80 // assignment. However, using = default triggers linker errors due to the
81 // explicit instantiations below. Find a way to use the default and remove the
82 // duplicated code here.
84 : IsLoopNestPass(std::move(Arg.IsLoopNestPass)),
85 LoopPasses(std::move(Arg.LoopPasses)),
86 LoopNestPasses(std::move(Arg.LoopNestPasses)) {}
87
88 PassManager &operator=(PassManager &&RHS) {
89 IsLoopNestPass = std::move(RHS.IsLoopNestPass);
90 LoopPasses = std::move(RHS.LoopPasses);
91 LoopNestPasses = std::move(RHS.LoopNestPasses);
92 return *this;
93 }
94
97 LPMUpdater &U);
98
99 LLVM_ABI void
100 printPipeline(raw_ostream &OS,
101 function_ref<StringRef(StringRef)> MapClassName2PassName);
102 /// Add either a loop pass or a loop-nest pass to the pass manager. Append \p
103 /// Pass to the list of loop passes if it has a dedicated \fn run() method for
104 /// loops and to the list of loop-nest passes if the \fn run() method is for
105 /// loop-nests instead. Also append whether \p Pass is loop-nest pass or not
106 /// to the end of \var IsLoopNestPass so we can easily identify the types of
107 /// passes in the pass manager later.
108 template <typename PassT> LLVM_ATTRIBUTE_MINSIZE void addPass(PassT &&Pass) {
110 using LoopPassModelT =
113 IsLoopNestPass.push_back(false);
114 // Do not use make_unique or emplace_back, they cause too many template
115 // instantiations, causing terrible compile times.
116 LoopPasses.push_back(std::unique_ptr<LoopPassConceptT>(
117 new LoopPassModelT(std::forward<PassT>(Pass))));
118 } else {
119 using LoopNestPassModelT =
122 IsLoopNestPass.push_back(true);
123 // Do not use make_unique or emplace_back, they cause too many template
124 // instantiations, causing terrible compile times.
125 LoopNestPasses.push_back(std::unique_ptr<LoopNestPassConceptT>(
126 new LoopNestPassModelT(std::forward<PassT>(Pass))));
127 }
128 }
129
130 bool isEmpty() const { return LoopPasses.empty() && LoopNestPasses.empty(); }
131
132 size_t getNumLoopPasses() const { return LoopPasses.size(); }
133 size_t getNumLoopNestPasses() const { return LoopNestPasses.size(); }
134
135protected:
136 using LoopPassConceptT =
139 using LoopNestPassConceptT =
142
143 // BitVector that identifies whether the passes are loop passes or loop-nest
144 // passes (true for loop-nest passes).
145 BitVector IsLoopNestPass;
146 std::vector<std::unique_ptr<LoopPassConceptT>> LoopPasses;
147 std::vector<std::unique_ptr<LoopNestPassConceptT>> LoopNestPasses;
148
149 /// Run either a loop pass or a loop-nest pass. Returns `std::nullopt` if
150 /// PassInstrumentation's BeforePass returns false. Otherwise, returns the
151 /// preserved analyses of the pass.
152 template <typename IRUnitT, typename PassT>
153 std::optional<PreservedAnalyses>
154 runSinglePass(IRUnitT &IR, PassT &Pass, LoopAnalysisManager &AM,
157
159 runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM,
162 runWithoutLoopNestPasses(Loop &L, LoopAnalysisManager &AM,
164
165private:
166 static const Loop &getLoopFromIR(Loop &L) { return L; }
167 static const Loop &getLoopFromIR(LoopNest &LN) {
168 return LN.getOutermostLoop();
169 }
170};
171
172/// The Loop pass manager.
173///
174/// See the documentation for the PassManager template for details. It runs
175/// a sequence of Loop passes over each Loop that the manager is run over. This
176/// typedef serves as a convenient way to refer to this construct.
178 LPMUpdater &>
180
181/// A partial specialization of the require analysis template pass to forward
182/// the extra parameters from a transformation's run method to the
183/// AnalysisManager's getResult.
184template <typename AnalysisT>
192 (void)AM.template getResult<AnalysisT>(L, AR);
193 return PreservedAnalyses::all();
194 }
195 void printPipeline(raw_ostream &OS,
196 function_ref<StringRef(StringRef)> MapClassName2PassName) {
197 auto ClassName = AnalysisT::name();
198 auto PassName = MapClassName2PassName(ClassName);
199 OS << "require<" << PassName << '>';
200 }
201};
202
203/// An alias template to easily name a require analysis loop pass.
204template <typename AnalysisT>
208
210
211/// This class provides an interface for updating the loop pass manager based
212/// on mutations to the loop nest.
213///
214/// A reference to an instance of this class is passed as an argument to each
215/// Loop pass, and Loop passes should use it to update LPM infrastructure if
216/// they modify the loop nest structure.
217///
218/// \c LPMUpdater comes with two modes: the loop mode and the loop-nest mode. In
219/// loop mode, all the loops in the function will be pushed into the worklist
220/// and when new loops are added to the pipeline, their subloops are also
221/// inserted recursively. On the other hand, in loop-nest mode, only top-level
222/// loops are contained in the worklist and the addition of new (top-level)
223/// loops will not trigger the addition of their subloops.
224class LPMUpdater {
225public:
226 /// This can be queried by loop passes which run other loop passes (like pass
227 /// managers) to know whether the loop needs to be skipped due to updates to
228 /// the loop nest.
229 ///
230 /// If this returns true, the loop object may have been deleted, so passes
231 /// should take care not to touch the object.
232 bool skipCurrentLoop() const { return SkipCurrentLoop; }
233
234 /// Loop passes should use this method to indicate they have deleted a loop
235 /// from the nest.
236 ///
237 /// Note that this loop must either be the current loop or a subloop of the
238 /// current loop. This routine must be called prior to removing the loop from
239 /// the loop nest.
240 ///
241 /// If this is called for the current loop, in addition to clearing any
242 /// state, this routine will mark that the current loop should be skipped by
243 /// the rest of the pass management infrastructure.
245 LAM.clear(L, Name);
246 assert((&L == CurrentL || CurrentL->contains(&L)) &&
247 "Cannot delete a loop outside of the "
248 "subloop tree currently being processed.");
249 if (&L == CurrentL)
250 SkipCurrentLoop = true;
251 }
252
254#if LLVM_ENABLE_ABI_BREAKING_CHECKS
255 ParentL = L;
256#endif
257 }
258
259 /// Loop passes should use this method to indicate they have added new child
260 /// loops of the current loop.
261 ///
262 /// \p NewChildLoops must contain only the immediate children. Any nested
263 /// loops within them will be visited in postorder as usual for the loop pass
264 /// manager.
265 void addChildLoops(ArrayRef<Loop *> NewChildLoops) {
266 assert(!LoopNestMode &&
267 "Child loops should not be pushed in loop-nest mode.");
268 // Insert ourselves back into the worklist first, as this loop should be
269 // revisited after all the children have been processed.
270 Worklist.insert(CurrentL);
271
272#ifndef NDEBUG
273 for (Loop *NewL : NewChildLoops)
274 assert(NewL->getParentLoop() == CurrentL && "All of the new loops must "
275 "be immediate children of "
276 "the current loop!");
277#endif
278
279 appendLoopsToWorklist(NewChildLoops, Worklist);
280
281 // Also skip further processing of the current loop--it will be revisited
282 // after all of its newly added children are accounted for.
283 SkipCurrentLoop = true;
284 }
285
286 /// Loop passes should use this method to indicate they have added new
287 /// sibling loops to the current loop.
288 ///
289 /// \p NewSibLoops must only contain the immediate sibling loops. Any nested
290 /// loops within them will be visited in postorder as usual for the loop pass
291 /// manager.
293#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
294 for (Loop *NewL : NewSibLoops)
295 assert(NewL->getParentLoop() == ParentL &&
296 "All of the new loops must be siblings of the current loop!");
297#endif
298
299 if (LoopNestMode)
300 Worklist.insert(NewSibLoops);
301 else
302 appendLoopsToWorklist(NewSibLoops, Worklist);
303
304 // No need to skip the current loop or revisit it, as sibling loops
305 // shouldn't impact anything.
306 }
307
308 /// Restart the current loop.
309 ///
310 /// Loop passes should call this method to indicate the current loop has been
311 /// sufficiently changed that it should be re-visited from the begining of
312 /// the loop pass pipeline rather than continuing.
314 // Tell the currently in-flight pipeline to stop running.
315 SkipCurrentLoop = true;
316
317 // And insert ourselves back into the worklist.
318 Worklist.insert(CurrentL);
319 }
320
321 bool isLoopNestChanged() const {
322 return LoopNestChanged;
323 }
324
325 /// Loopnest passes should use this method to indicate if the
326 /// loopnest has been modified.
328 LoopNestChanged = Changed;
329 }
330
331private:
333
334 /// The \c FunctionToLoopPassAdaptor's worklist of loops to process.
336
337 /// The analysis manager for use in the current loop nest.
339
340 Loop *CurrentL;
341 bool SkipCurrentLoop;
342 const bool LoopNestMode;
343 bool LoopNestChanged;
344
345#if LLVM_ENABLE_ABI_BREAKING_CHECKS
346 // In debug builds we also track the parent loop to implement asserts even in
347 // the face of loop deletion.
348 Loop *ParentL;
349#endif
350
351 LPMUpdater(SmallPriorityWorklist<Loop *, 4> &Worklist,
352 LoopAnalysisManager &LAM, bool LoopNestMode = false,
353 bool LoopNestChanged = false)
354 : Worklist(Worklist), LAM(LAM), LoopNestMode(LoopNestMode),
355 LoopNestChanged(LoopNestChanged) {}
356};
357
358template <typename IRUnitT, typename PassT>
359std::optional<PreservedAnalyses> LoopPassManager::runSinglePass(
360 IRUnitT &IR, PassT &Pass, LoopAnalysisManager &AM,
361 LoopStandardAnalysisResults &AR, LPMUpdater &U, PassInstrumentation &PI) {
362 // Get the loop in case of Loop pass and outermost loop in case of LoopNest
363 // pass which is to be passed to BeforePass and AfterPass call backs.
364 const Loop &L = getLoopFromIR(IR);
365 // Check the PassInstrumentation's BeforePass callbacks before running the
366 // pass, skip its execution completely if asked to (callback returns false).
367 if (!PI.runBeforePass<Loop>(*Pass, L))
368 return std::nullopt;
369
370 PreservedAnalyses PA = Pass->run(IR, AM, AR, U);
371
372 // do not pass deleted Loop into the instrumentation
373 if (U.skipCurrentLoop())
374 PI.runAfterPassInvalidated<IRUnitT>(*Pass, PA);
375 else
376 PI.runAfterPass<Loop>(*Pass, L, PA);
377 return PA;
378}
379
380/// Adaptor that maps from a function to its loops.
381///
382/// Designed to allow composition of a LoopPass(Manager) and a
383/// FunctionPassManager. Note that if this pass is constructed with a \c
384/// FunctionAnalysisManager it will run the \c LoopAnalysisManagerFunctionProxy
385/// analysis prior to running the loop passes over the function to enable a \c
386/// LoopAnalysisManager to be used within this run safely.
387///
388/// The adaptor comes with two modes: the loop mode and the loop-nest mode, and
389/// the worklist updater lived inside will be in the same mode as the adaptor
390/// (refer to the documentation of \c LPMUpdater for more detailed explanation).
391/// Specifically, in loop mode, all loops in the function will be pushed into
392/// the worklist and processed by \p Pass, while only top-level loops are
393/// processed in loop-nest mode. Please refer to the various specializations of
394/// \fn createLoopFunctionToLoopPassAdaptor to see when loop mode and loop-nest
395/// mode are used.
397 : public RequiredPassInfoMixin<FunctionToLoopPassAdaptor> {
398public:
402
403 explicit FunctionToLoopPassAdaptor(std::unique_ptr<PassConceptT> Pass,
404 bool UseMemorySSA = false,
405 bool LoopNestMode = false)
406 : Pass(std::move(Pass)), UseMemorySSA(UseMemorySSA),
407 LoopNestMode(LoopNestMode) {
408 LoopCanonicalizationFPM.addPass(LoopSimplifyPass());
409 LoopCanonicalizationFPM.addPass(LCSSAPass());
410 }
411
412 /// Runs the loop passes across every loop in the function.
414 LLVM_ABI void
416 function_ref<StringRef(StringRef)> MapClassName2PassName);
417
418 bool isLoopNestMode() const { return LoopNestMode; }
419
420private:
421 std::unique_ptr<PassConceptT> Pass;
422
423 FunctionPassManager LoopCanonicalizationFPM;
424
425 bool UseMemorySSA = false;
426 const bool LoopNestMode;
427};
428
429/// A function to deduce a loop pass type and wrap it in the templated
430/// adaptor.
431///
432/// If \p Pass is a loop pass, the returned adaptor will be in loop mode.
433///
434/// If \p Pass is a loop-nest pass, \p Pass will first be wrapped into a
435/// \c LoopPassManager and the returned adaptor will be in loop-nest mode.
436template <typename LoopPassT>
437inline FunctionToLoopPassAdaptor
438createFunctionToLoopPassAdaptor(LoopPassT &&Pass, bool UseMemorySSA = false) {
440 using PassModelT =
443 // Do not use make_unique, it causes too many template instantiations,
444 // causing terrible compile times.
446 std::unique_ptr<FunctionToLoopPassAdaptor::PassConceptT>(
447 new PassModelT(std::forward<LoopPassT>(Pass))),
448 UseMemorySSA, false);
449 } else {
450 LoopPassManager LPM;
451 LPM.addPass(std::forward<LoopPassT>(Pass));
452 using PassModelT =
455 // Do not use make_unique, it causes too many template instantiations,
456 // causing terrible compile times.
458 std::unique_ptr<FunctionToLoopPassAdaptor::PassConceptT>(
459 new PassModelT(std::move(LPM))),
460 UseMemorySSA, true);
461 }
462}
463
464/// If \p Pass is an instance of \c LoopPassManager, the returned adaptor will
465/// be in loop-nest mode if the pass manager contains only loop-nest passes.
466template <>
469 bool UseMemorySSA) {
470 // Check if LPM contains any loop pass and if it does not, returns an adaptor
471 // in loop-nest mode.
472 using PassModelT =
475 bool LoopNestMode = (LPM.getNumLoopPasses() == 0);
476 // Do not use make_unique, it causes too many template instantiations,
477 // causing terrible compile times.
479 std::unique_ptr<FunctionToLoopPassAdaptor::PassConceptT>(
480 new PassModelT(std::move(LPM))),
481 UseMemorySSA, LoopNestMode);
482}
483
484/// Pass for printing a loop's contents as textual IR.
485class PrintLoopPass : public RequiredPassInfoMixin<PrintLoopPass> {
486 raw_ostream &OS;
487 std::string Banner;
488
489public:
491 LLVM_ABI PrintLoopPass(raw_ostream &OS, const std::string &Banner = "");
492
495};
496}
497
498#endif // LLVM_TRANSFORMS_SCALAR_LOOPPASSMANAGER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_ABI
Definition Compiler.h:213
#define LLVM_ATTRIBUTE_MINSIZE
Definition Compiler.h:328
This header defines various interfaces for pass management in LLVM.
Legalize the Machine IR a function s Machine IR
Definition Legalizer.cpp:81
This header provides classes for managing per-loop analyses.
This file defines the interface for the loop nest analysis.
#define F(x, y, z)
Definition MD5.cpp:54
print mir2vec MIR2Vec Vocabulary Printer Pass
Definition MIR2Vec.cpp:598
This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...
This file provides a priority worklist.
static const char PassName[]
Value * RHS
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
FunctionToLoopPassAdaptor(std::unique_ptr< PassConceptT > Pass, bool UseMemorySSA=false, bool LoopNestMode=false)
LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
detail::PassConcept< Loop, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater & > PassConceptT
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Runs the loop passes across every loop in the function.
Converts loops into loop-closed SSA form.
Definition LCSSA.h:38
This class provides an interface for updating the loop pass manager based on mutations to the loop ne...
void markLoopNestChanged(bool Changed)
Loopnest passes should use this method to indicate if the loopnest has been modified.
void setParentLoop(Loop *L)
bool isLoopNestChanged() const
void revisitCurrentLoop()
Restart the current loop.
bool skipCurrentLoop() const
This can be queried by loop passes which run other loop passes (like pass managers) to know whether t...
void addChildLoops(ArrayRef< Loop * > NewChildLoops)
Loop passes should use this method to indicate they have added new child loops of the current loop.
void markLoopAsDeleted(Loop &L, llvm::StringRef Name)
Loop passes should use this method to indicate they have deleted a loop from the nest.
void addSiblingLoops(ArrayRef< Loop * > NewSibLoops)
Loop passes should use this method to indicate they have added new sibling loops to the current loop.
const LoopT * getOutermostLoop() const
Get the outermost loop in which this loop is contained.
This class represents a loop nest and can be used to query its properties.
This pass is responsible for loop canonicalization.
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
This class provides instrumentation entry points for the Pass Manager, doing calls to callbacks regis...
Manages a sequence of passes over a particular unit of IR.
Pass interface - Implemented by all 'passes'.
Definition Pass.h:99
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
LLVM_ABI PreservedAnalyses run(Loop &L, LoopAnalysisManager &, LoopStandardAnalysisResults &, LPMUpdater &)
A version of PriorityWorklist that selects small size optimized data structures for the vector and ma...
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
Changed
DXILDebugInfoMap run(Module &M)
This is an optimization pass for GlobalISel generic memory operations.
AnalysisManager< Loop, LoopStandardAnalysisResults & > LoopAnalysisManager
The loop analysis manager.
PassManager< Loop, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater & > LoopPassManager
The Loop pass manager.
FunctionToLoopPassAdaptor createFunctionToLoopPassAdaptor(LoopPassT &&Pass, bool UseMemorySSA=false)
A function to deduce a loop pass type and wrap it in the templated adaptor.
LLVM_TEMPLATE_ABI void appendLoopsToWorklist(RangeT &&, SmallPriorityWorklist< Loop *, 4 > &)
Utility that implements appending of loops onto a worklist given a range.
PassManager< Function > FunctionPassManager
Convenience typedef for a pass manager over functions.
typename detail::detector< void, Op, Args... >::value_t is_detected
Detects if a given trait holds for some set of arguments 'Args'.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1916
FunctionToLoopPassAdaptor createFunctionToLoopPassAdaptor< LoopPassManager >(LoopPassManager &&LPM, bool UseMemorySSA)
If Pass is an instance of LoopPassManager, the returned adaptor will be in loop-nest mode if the pass...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
RequireAnalysisPass< AnalysisT, Loop, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater & > RequireAnalysisLoopPass
An alias template to easily name a require analysis loop pass.
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:874
The adaptor from a function pass to a loop pass computes these analyses and makes them available to t...
A CRTP mix-in for passes that can be skipped.
A utility pass template to force an analysis result to be available.
A CRTP mix-in for passes that should not be skipped.
Template for the abstract base class used to dispatch polymorphically over pass objects.
A template wrapper used to implement the polymorphic API.