1//===- PassManager.h - Pass Management Interface ----------------*- 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
9#ifndef MLIR_PASS_PASSMANAGER_H
10#define MLIR_PASS_PASSMANAGER_H
11
12#include "mlir/IR/Dialect.h"
13#include "mlir/IR/OperationSupport.h"
14#include "mlir/Support/LogicalResult.h"
15#include "mlir/Support/Timing.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/iterator.h"
18#include "llvm/Support/raw_ostream.h"
19
20#include <functional>
21#include <vector>
22#include <optional>
23
24namespace mlir {
25class AnalysisManager;
26class MLIRContext;
27class Operation;
28class Pass;
29class PassInstrumentation;
30class PassInstrumentor;
31
32namespace detail {
33struct OpPassManagerImpl;
34class OpToOpPassAdaptor;
35class PassCrashReproducerGenerator;
36struct PassExecutionState;
37} // namespace detail
38
39//===----------------------------------------------------------------------===//
40// OpPassManager
41//===----------------------------------------------------------------------===//
42
43/// This class represents a pass manager that runs passes on either a specific
44/// operation type, or any isolated operation. This pass manager can not be run
45/// on an operation directly, but must be run either as part of a top-level
46/// `PassManager`(e.g. when constructed via `nest` calls), or dynamically within
47/// a pass by using the `Pass::runPipeline` API.
48class OpPassManager {
49public:
50 /// This enum represents the nesting behavior of the pass manager.
51 enum class Nesting {
52 /// Implicit nesting behavior. This allows for adding passes operating on
53 /// operations different from this pass manager, in which case a new pass
54 /// manager is implicitly nested for the operation type of the new pass.
55 Implicit,
56 /// Explicit nesting behavior. This requires that any passes added to this
57 /// pass manager support its operation type.
58 Explicit
59 };
60
61 /// Construct a new op-agnostic ("any") pass manager with the given operation
62 /// type and nesting behavior. This is the same as invoking:
63 /// `OpPassManager(getAnyOpAnchorName(), nesting)`.
64 OpPassManager(Nesting nesting = Nesting::Explicit);
65
66 /// Construct a new pass manager with the given anchor operation type and
67 /// nesting behavior.
68 OpPassManager(StringRef name, Nesting nesting = Nesting::Explicit);
69 OpPassManager(OperationName name, Nesting nesting = Nesting::Explicit);
70 OpPassManager(OpPassManager &&rhs);
71 OpPassManager(const OpPassManager &rhs);
72 ~OpPassManager();
73 OpPassManager &operator=(const OpPassManager &rhs);
74 OpPassManager &operator=(OpPassManager &&rhs);
75
76 /// Iterator over the passes in this pass manager.
77 using pass_iterator =
78 llvm::pointee_iterator<MutableArrayRef<std::unique_ptr<Pass>>::iterator>;
79 pass_iterator begin();
80 pass_iterator end();
81 iterator_range<pass_iterator> getPasses() { return {begin(), end()}; }
82
83 using const_pass_iterator =
84 llvm::pointee_iterator<ArrayRef<std::unique_ptr<Pass>>::const_iterator>;
85 const_pass_iterator begin() const;
86 const_pass_iterator end() const;
87 iterator_range<const_pass_iterator> getPasses() const {
88 return {begin(), end()};
89 }
90
91 /// Returns true if the pass manager has no passes.
92 bool empty() const { return begin() == end(); }
93
94 /// Nest a new operation pass manager for the given operation kind under this
95 /// pass manager.
96 OpPassManager &nest(OperationName nestedName);
97 OpPassManager &nest(StringRef nestedName);
98 template <typename OpT>
99 OpPassManager &nest() {
100 return nest(OpT::getOperationName());
101 }
102
103 /// Nest a new op-agnostic ("any") pass manager under this pass manager.
104 /// Note: This is the same as invoking `nest(getAnyOpAnchorName())`.
105 OpPassManager &nestAny();
106
107 /// Add the given pass to this pass manager. If this pass has a concrete
108 /// operation type, it must be the same type as this pass manager.
109 void addPass(std::unique_ptr<Pass> pass);
110
111 /// Clear the pipeline, but not the other options set on this OpPassManager.
112 void clear();
113
114 /// Add the given pass to a nested pass manager for the given operation kind
115 /// `OpT`.
116 template <typename OpT>
117 void addNestedPass(std::unique_ptr<Pass> pass) {
118 nest<OpT>().addPass(std::move(pass));
119 }
120
121 /// Returns the number of passes held by this manager.
122 size_t size() const;
123
124 /// Return the operation name that this pass manager operates on, or
125 /// std::nullopt if this is an op-agnostic pass manager.
126 std::optional<OperationName> getOpName(MLIRContext &context) const;
127
128 /// Return the operation name that this pass manager operates on, or
129 /// std::nullopt if this is an op-agnostic pass manager.
130 std::optional<StringRef> getOpName() const;
131
132 /// Return the name used to anchor this pass manager. This is either the name
133 /// of an operation, or the result of `getAnyOpAnchorName()` in the case of an
134 /// op-agnostic pass manager.
135 StringRef getOpAnchorName() const;
136
137 /// Return the string name used to anchor op-agnostic pass managers that
138 /// operate generically on any viable operation.
139 static StringRef getAnyOpAnchorName() { return "any"; }
140
141 /// Returns the internal implementation instance.
142 detail::OpPassManagerImpl &getImpl();
143
144 /// Prints out the passes of the pass manager as the textual representation
145 /// of pipelines.
146 /// Note: The quality of the string representation depends entirely on the
147 /// the correctness of per-pass overrides of Pass::printAsTextualPipeline.
148 void printAsTextualPipeline(raw_ostream &os) const;
149
150 /// Raw dump of the pass manager to llvm::errs().
151 void dump();
152
153 /// Merge the pass statistics of this class into 'other'.
154 void mergeStatisticsInto(OpPassManager &other);
155
156 /// Register dependent dialects for the current pass manager.
157 /// This is forwarding to every pass in this PassManager, see the
158 /// documentation for the same method on the Pass class.
159 void getDependentDialects(DialectRegistry &dialects) const;
160
161 /// Enable or disable the implicit nesting on this particular PassManager.
162 /// This will also apply to any newly nested PassManager built from this
163 /// instance.
164 void setNesting(Nesting nesting);
165
166 /// Return the current nesting mode.
167 Nesting getNesting();
168
169private:
170 /// Initialize all of the passes within this pass manager with the given
171 /// initialization generation. The initialization generation is used to detect
172 /// if a pass manager has already been initialized.
173 LogicalResult initialize(MLIRContext *context, unsigned newInitGeneration);
174
175 /// Compute a hash of the pipeline, so that we can detect changes (a pass is
176 /// added...).
177 llvm::hash_code hash();
178
179 /// A pointer to an internal implementation instance.
180 std::unique_ptr<detail::OpPassManagerImpl> impl;
181
182 /// Allow access to initialize.
183 friend detail::OpToOpPassAdaptor;
184
185 /// Allow access to the constructor.
186 friend class PassManager;
187 friend class Pass;
188
189 /// Allow access.
190 friend detail::OpPassManagerImpl;
191};
192
193//===----------------------------------------------------------------------===//
194// PassManager
195//===----------------------------------------------------------------------===//
196
197/// An enum describing the different display modes for the information within
198/// the pass manager.
199enum class PassDisplayMode {
200 // In this mode the results are displayed in a list sorted by total,
201 // with each pass/analysis instance aggregated into one unique result.
202 List,
203
204 // In this mode the results are displayed in a nested pipeline view that
205 // mirrors the internal pass pipeline that is being executed in the pass
206 // manager.
207 Pipeline,
208};
209
210/// Streams on which to output crash reproducer.
211struct ReproducerStream {
212 virtual ~ReproducerStream() = default;
213
214 /// Description of the reproducer stream.
215 virtual StringRef description() = 0;
216
217 /// Stream on which to output reproducer.
218 virtual raw_ostream &os() = 0;
219};
220
221/// Method type for constructing ReproducerStream.
222using ReproducerStreamFactory =
223 std::function<std::unique_ptr<ReproducerStream>(std::string &error)>;
224
225std::string
226makeReproducer(StringRef anchorName,
227 const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
228 Operation *op, StringRef outputFile, bool disableThreads = false,
229 bool verifyPasses = false);
230
231/// The main pass manager and pipeline builder.
232class PassManager : public OpPassManager {
233public:
234 /// Create a new pass manager under the given context with a specific nesting
235 /// style. The created pass manager can schedule operations that match
236 /// `operationName`.
237 PassManager(MLIRContext *ctx,
238 StringRef operationName = PassManager::getAnyOpAnchorName(),
239 Nesting nesting = Nesting::Explicit);
240 PassManager(OperationName operationName, Nesting nesting = Nesting::Explicit);
241 ~PassManager();
242
243 /// Create a new pass manager under the given context with a specific nesting
244 /// style. The created pass manager can schedule operations that match
245 /// `OperationTy`.
246 template <typename OperationTy>
247 static PassManager on(MLIRContext *ctx, Nesting nesting = Nesting::Explicit) {
248 return PassManager(ctx, OperationTy::getOperationName(), nesting);
249 }
250
251 /// Run the passes within this manager on the provided operation. The
252 /// specified operation must have the same name as the one provided the pass
253 /// manager on construction.
254 LogicalResult run(Operation *op);
255
256 /// Return an instance of the context.
257 MLIRContext *getContext() const { return context; }
258
259 /// Enable support for the pass manager to generate a reproducer on the event
260 /// of a crash or a pass failure. `outputFile` is a .mlir filename used to
261 /// write the generated reproducer. If `genLocalReproducer` is true, the pass
262 /// manager will attempt to generate a local reproducer that contains the
263 /// smallest pipeline.
264 void enableCrashReproducerGeneration(StringRef outputFile,
265 bool genLocalReproducer = false);
266
267 /// Enable support for the pass manager to generate a reproducer on the event
268 /// of a crash or a pass failure. `factory` is used to construct the streams
269 /// to write the generated reproducer to. If `genLocalReproducer` is true, the
270 /// pass manager will attempt to generate a local reproducer that contains the
271 /// smallest pipeline.
272 void enableCrashReproducerGeneration(ReproducerStreamFactory factory,
273 bool genLocalReproducer = false);
274
275 /// Runs the verifier after each individual pass.
276 void enableVerifier(bool enabled = true);
277
278 //===--------------------------------------------------------------------===//
279 // Instrumentations
280 //===--------------------------------------------------------------------===//
281
282 /// Add the provided instrumentation to the pass manager.
283 void addInstrumentation(std::unique_ptr<PassInstrumentation> pi);
284
285 //===--------------------------------------------------------------------===//
286 // IR Printing
287
288 /// A configuration struct provided to the IR printer instrumentation.
289 class IRPrinterConfig {
290 public:
291 using PrintCallbackFn = function_ref<void(raw_ostream &)>;
292
293 /// Initialize the configuration.
294 /// * 'printModuleScope' signals if the top-level module IR should always be
295 /// printed. This should only be set to true when multi-threading is
296 /// disabled, otherwise we may try to print IR that is being modified
297 /// asynchronously.
298 /// * 'printAfterOnlyOnChange' signals that when printing the IR after a
299 /// pass, in the case of a non-failure, we should first check if any
300 /// potential mutations were made. This allows for reducing the number of
301 /// logs that don't contain meaningful changes.
302 /// * 'printAfterOnlyOnFailure' signals that when printing the IR after a
303 /// pass, we only print in the case of a failure.
304 /// - This option should *not* be used with the other `printAfter` flags
305 /// above.
306 /// * 'opPrintingFlags' sets up the printing flags to use when printing the
307 /// IR.
308 explicit IRPrinterConfig(
309 bool printModuleScope = false, bool printAfterOnlyOnChange = false,
310 bool printAfterOnlyOnFailure = false,
311 OpPrintingFlags opPrintingFlags = OpPrintingFlags());
312 virtual ~IRPrinterConfig();
313
314 /// A hook that may be overridden by a derived config that checks if the IR
315 /// of 'operation' should be dumped *before* the pass 'pass' has been
316 /// executed. If the IR should be dumped, 'printCallback' should be invoked
317 /// with the stream to dump into.
318 virtual void printBeforeIfEnabled(Pass *pass, Operation *operation,
319 PrintCallbackFn printCallback);
320
321 /// A hook that may be overridden by a derived config that checks if the IR
322 /// of 'operation' should be dumped *after* the pass 'pass' has been
323 /// executed. If the IR should be dumped, 'printCallback' should be invoked
324 /// with the stream to dump into.
325 virtual void printAfterIfEnabled(Pass *pass, Operation *operation,
326 PrintCallbackFn printCallback);
327
328 /// Returns true if the IR should always be printed at the top-level scope.
329 bool shouldPrintAtModuleScope() const { return printModuleScope; }
330
331 /// Returns true if the IR should only printed after a pass if the IR
332 /// "changed".
333 bool shouldPrintAfterOnlyOnChange() const { return printAfterOnlyOnChange; }
334
335 /// Returns true if the IR should only printed after a pass if the pass
336 /// "failed".
337 bool shouldPrintAfterOnlyOnFailure() const {
338 return printAfterOnlyOnFailure;
339 }
340
341 /// Returns the printing flags to be used to print the IR.
342 OpPrintingFlags getOpPrintingFlags() const { return opPrintingFlags; }
343
344 private:
345 /// A flag that indicates if the IR should be printed at module scope.
346 bool printModuleScope;
347
348 /// A flag that indicates that the IR after a pass should only be printed if
349 /// a change is detected.
350 bool printAfterOnlyOnChange;
351
352 /// A flag that indicates that the IR after a pass should only be printed if
353 /// the pass failed.
354 bool printAfterOnlyOnFailure;
355
356 /// Flags to control printing behavior.
357 OpPrintingFlags opPrintingFlags;
358 };
359
360 /// Add an instrumentation to print the IR before and after pass execution,
361 /// using the provided configuration.
362 void enableIRPrinting(std::unique_ptr<IRPrinterConfig> config);
363
364 /// Add an instrumentation to print the IR before and after pass execution,
365 /// using the provided fields to generate a default configuration:
366 /// * 'shouldPrintBeforePass' and 'shouldPrintAfterPass' correspond to filter
367 /// functions that take a 'Pass *' and `Operation *`. These function should
368 /// return true if the IR should be printed or not.
369 /// * 'printModuleScope' signals if the module IR should be printed, even
370 /// for non module passes.
371 /// * 'printAfterOnlyOnChange' signals that when printing the IR after a
372 /// pass, in the case of a non-failure, we should first check if any
373 /// potential mutations were made.
374 /// * 'printAfterOnlyOnFailure' signals that when printing the IR after a
375 /// pass, we only print in the case of a failure.
376 /// - This option should *not* be used with the other `printAfter` flags
377 /// above.
378 /// * 'out' corresponds to the stream to output the printed IR to.
379 /// * 'opPrintingFlags' sets up the printing flags to use when printing the
380 /// IR.
381 void enableIRPrinting(
382 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass =
383 [](Pass *, Operation *) { return true; },
384 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass =
385 [](Pass *, Operation *) { return true; },
386 bool printModuleScope = true, bool printAfterOnlyOnChange = true,
387 bool printAfterOnlyOnFailure = false, raw_ostream &out = llvm::errs(),
388 OpPrintingFlags opPrintingFlags = OpPrintingFlags());
389
390 //===--------------------------------------------------------------------===//
391 // Pass Timing
392
393 /// Add an instrumentation to time the execution of passes and the computation
394 /// of analyses. Timing will be reported by nesting timers into the provided
395 /// `timingScope`.
396 ///
397 /// Note: Timing should be enabled after all other instrumentations to avoid
398 /// any potential "ghost" timing from other instrumentations being
399 /// unintentionally included in the timing results.
400 void enableTiming(TimingScope &timingScope);
401
402 /// Add an instrumentation to time the execution of passes and the computation
403 /// of analyses. The pass manager will take ownership of the timing manager
404 /// passed to the function and timing will be reported by nesting timers into
405 /// the timing manager's root scope.
406 ///
407 /// Note: Timing should be enabled after all other instrumentations to avoid
408 /// any potential "ghost" timing from other instrumentations being
409 /// unintentionally included in the timing results.
410 void enableTiming(std::unique_ptr<TimingManager> tm);
411
412 /// Add an instrumentation to time the execution of passes and the computation
413 /// of analyses. Creates a temporary TimingManager owned by this PassManager
414 /// which will be used to report timing.
415 ///
416 /// Note: Timing should be enabled after all other instrumentations to avoid
417 /// any potential "ghost" timing from other instrumentations being
418 /// unintentionally included in the timing results.
419 void enableTiming();
420
421 //===--------------------------------------------------------------------===//
422 // Pass Statistics
423
424 /// Prompts the pass manager to print the statistics collected for each of the
425 /// held passes after each call to 'run'.
426 void
427 enableStatistics(PassDisplayMode displayMode = PassDisplayMode::Pipeline);
428
429private:
430 /// Dump the statistics of the passes within this pass manager.
431 void dumpStatistics();
432
433 /// Run the pass manager with crash recovery enabled.
434 LogicalResult runWithCrashRecovery(Operation *op, AnalysisManager am);
435
436 /// Run the passes of the pass manager, and return the result.
437 LogicalResult runPasses(Operation *op, AnalysisManager am);
438
439 /// Context this PassManager was initialized with.
440 MLIRContext *context;
441
442 /// Flag that specifies if pass statistics should be dumped.
443 std::optional<PassDisplayMode> passStatisticsMode;
444
445 /// A manager for pass instrumentations.
446 std::unique_ptr<PassInstrumentor> instrumentor;
447
448 /// An optional crash reproducer generator, if this pass manager is setup to
449 /// generate reproducers.
450 std::unique_ptr<detail::PassCrashReproducerGenerator> crashReproGenerator;
451
452 /// Hash keys used to detect when reinitialization is necessary.
453 llvm::hash_code initializationKey =
454 DenseMapInfo<llvm::hash_code>::getTombstoneKey();
455 llvm::hash_code pipelineInitializationKey =
456 DenseMapInfo<llvm::hash_code>::getTombstoneKey();
457
458 /// Flag that specifies if pass timing is enabled.
459 bool passTiming : 1;
460
461 /// A flag that indicates if the IR should be verified in between passes.
462 bool verifyPasses : 1;
463};
464
465/// Register a set of useful command-line options that can be used to configure
466/// a pass manager. The values of these options can be applied via the
467/// 'applyPassManagerCLOptions' method below.
468void registerPassManagerCLOptions();
469
470/// Apply any values provided to the pass manager options that were registered
471/// with 'registerPassManagerOptions'.
472LogicalResult applyPassManagerCLOptions(PassManager &pm);
473
474/// Apply any values provided to the timing manager options that were registered
475/// with `registerDefaultTimingManagerOptions`. This is a handy helper function
476/// if you do not want to bother creating your own timing manager and passing it
477/// to the pass manager.
478void applyDefaultTimingPassManagerCLOptions(PassManager &pm);
479
480} // namespace mlir
481
482#endif // MLIR_PASS_PASSMANAGER_H
483

source code of mlir/include/mlir/Pass/PassManager.h