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/Timing.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/iterator.h"
17#include "llvm/Support/raw_ostream.h"
18
19#include <functional>
20#include <optional>
21
22namespace mlir {
23class AnalysisManager;
24class MLIRContext;
25class Operation;
26class Pass;
27class PassInstrumentation;
28class PassInstrumentor;
29
30namespace detail {
31struct OpPassManagerImpl;
32class OpToOpPassAdaptor;
33class PassCrashReproducerGenerator;
34struct PassExecutionState;
35} // namespace detail
36
37//===----------------------------------------------------------------------===//
38// OpPassManager
39//===----------------------------------------------------------------------===//
40
41/// This class represents a pass manager that runs passes on either a specific
42/// operation type, or any isolated operation. This pass manager can not be run
43/// on an operation directly, but must be run either as part of a top-level
44/// `PassManager`(e.g. when constructed via `nest` calls), or dynamically within
45/// a pass by using the `Pass::runPipeline` API.
46class OpPassManager {
47public:
48 /// This enum represents the nesting behavior of the pass manager.
49 enum class Nesting {
50 /// Implicit nesting behavior. This allows for adding passes operating on
51 /// operations different from this pass manager, in which case a new pass
52 /// manager is implicitly nested for the operation type of the new pass.
53 Implicit,
54 /// Explicit nesting behavior. This requires that any passes added to this
55 /// pass manager support its operation type.
56 Explicit
57 };
58
59 /// Construct a new op-agnostic ("any") pass manager with the given operation
60 /// type and nesting behavior. This is the same as invoking:
61 /// `OpPassManager(getAnyOpAnchorName(), nesting)`.
62 OpPassManager(Nesting nesting = Nesting::Explicit);
63
64 /// Construct a new pass manager with the given anchor operation type and
65 /// nesting behavior.
66 OpPassManager(StringRef name, Nesting nesting = Nesting::Explicit);
67 OpPassManager(OperationName name, Nesting nesting = Nesting::Explicit);
68 OpPassManager(OpPassManager &&rhs);
69 OpPassManager(const OpPassManager &rhs);
70 ~OpPassManager();
71 OpPassManager &operator=(const OpPassManager &rhs);
72 OpPassManager &operator=(OpPassManager &&rhs);
73
74 /// Iterator over the passes in this pass manager.
75 using pass_iterator =
76 llvm::pointee_iterator<MutableArrayRef<std::unique_ptr<Pass>>::iterator>;
77 pass_iterator begin();
78 pass_iterator end();
79 iterator_range<pass_iterator> getPasses() { return {begin(), end()}; }
80
81 using const_pass_iterator =
82 llvm::pointee_iterator<ArrayRef<std::unique_ptr<Pass>>::const_iterator>;
83 const_pass_iterator begin() const;
84 const_pass_iterator end() const;
85 iterator_range<const_pass_iterator> getPasses() const {
86 return {begin(), end()};
87 }
88
89 /// Returns true if the pass manager has no passes.
90 bool empty() const { return begin() == end(); }
91
92 /// Nest a new operation pass manager for the given operation kind under this
93 /// pass manager.
94 OpPassManager &nest(OperationName nestedName);
95 OpPassManager &nest(StringRef nestedName);
96 template <typename OpT>
97 OpPassManager &nest() {
98 return nest(OpT::getOperationName());
99 }
100
101 /// Nest a new op-agnostic ("any") pass manager under this pass manager.
102 /// Note: This is the same as invoking `nest(getAnyOpAnchorName())`.
103 OpPassManager &nestAny();
104
105 /// Add the given pass to this pass manager. If this pass has a concrete
106 /// operation type, it must be the same type as this pass manager.
107 void addPass(std::unique_ptr<Pass> pass);
108
109 /// Clear the pipeline, but not the other options set on this OpPassManager.
110 void clear();
111
112 /// Add the given pass to a nested pass manager for the given operation kind
113 /// `OpT`.
114 template <typename OpT>
115 void addNestedPass(std::unique_ptr<Pass> pass) {
116 nest<OpT>().addPass(std::move(pass));
117 }
118
119 /// Returns the number of passes held by this manager.
120 size_t size() const;
121
122 /// Return the operation name that this pass manager operates on, or
123 /// std::nullopt if this is an op-agnostic pass manager.
124 std::optional<OperationName> getOpName(MLIRContext &context) const;
125
126 /// Return the operation name that this pass manager operates on, or
127 /// std::nullopt if this is an op-agnostic pass manager.
128 std::optional<StringRef> getOpName() const;
129
130 /// Return the name used to anchor this pass manager. This is either the name
131 /// of an operation, or the result of `getAnyOpAnchorName()` in the case of an
132 /// op-agnostic pass manager.
133 StringRef getOpAnchorName() const;
134
135 /// Return the string name used to anchor op-agnostic pass managers that
136 /// operate generically on any viable operation.
137 static StringRef getAnyOpAnchorName() { return "any"; }
138
139 /// Returns the internal implementation instance.
140 detail::OpPassManagerImpl &getImpl();
141
142 /// Prints out the passes of the pass manager as the textual representation
143 /// of pipelines. When `pretty` is true, the printed pipeline is formatted
144 /// for readability.
145 ///
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, bool pretty = false) 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 /// Similar to `enableIRPrinting` above, except that instead of printing
391 /// the IR to a single output stream, the instrumentation will print the
392 /// output of each pass to a separate file. The files will be organized into a
393 /// directory tree rooted at `printTreeDir`. The directories mirror the
394 /// nesting structure of the IR. For example, if the IR is congruent to the
395 /// pass-pipeline "builtin.module(passA,passB,func.func(passC,passD),passE)",
396 /// and `printTreeDir=/tmp/pipeline_output`, then then the tree file tree
397 /// created will look like:
398 ///
399 /// ```
400 /// /tmp/pass_output
401 /// ├── builtin_module_the_symbol_name
402 /// │ ├── 0_passA.mlir
403 /// │ ├── 1_passB.mlir
404 /// │ ├── 2_passE.mlir
405 /// │ ├── func_func_my_func_name
406 /// │ │ ├── 1_0_passC.mlir
407 /// │ │ ├── 1_1__passD.mlir
408 /// │ ├── func_func_my_other_func_name
409 /// │ │ ├── 1_0_passC.mlir
410 /// │ │ ├── 1_1_passD.mlir
411 /// ```
412 ///
413 /// The subdirectories are given names that reflect the parent operation name
414 /// and symbol name (if present). The output MLIR files are prefixed using an
415 /// atomic counter to indicate the order the passes were printed in and to
416 /// prevent any potential name collisions.
417 void enableIRPrintingToFileTree(
418 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass =
419 [](Pass *, Operation *) { return true; },
420 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass =
421 [](Pass *, Operation *) { return true; },
422 bool printModuleScope = true, bool printAfterOnlyOnChange = true,
423 bool printAfterOnlyOnFailure = false,
424 llvm::StringRef printTreeDir = ".pass_manager_output",
425 OpPrintingFlags opPrintingFlags = OpPrintingFlags());
426
427 //===--------------------------------------------------------------------===//
428 // Pass Timing
429
430 /// Add an instrumentation to time the execution of passes and the computation
431 /// of analyses. Timing will be reported by nesting timers into the provided
432 /// `timingScope`.
433 ///
434 /// Note: Timing should be enabled after all other instrumentations to avoid
435 /// any potential "ghost" timing from other instrumentations being
436 /// unintentionally included in the timing results.
437 void enableTiming(TimingScope &timingScope);
438
439 /// Add an instrumentation to time the execution of passes and the computation
440 /// of analyses. The pass manager will take ownership of the timing manager
441 /// passed to the function and timing will be reported by nesting timers into
442 /// the timing manager's root scope.
443 ///
444 /// Note: Timing should be enabled after all other instrumentations to avoid
445 /// any potential "ghost" timing from other instrumentations being
446 /// unintentionally included in the timing results.
447 void enableTiming(std::unique_ptr<TimingManager> tm);
448
449 /// Add an instrumentation to time the execution of passes and the computation
450 /// of analyses. Creates a temporary TimingManager owned by this PassManager
451 /// which will be used to report timing.
452 ///
453 /// Note: Timing should be enabled after all other instrumentations to avoid
454 /// any potential "ghost" timing from other instrumentations being
455 /// unintentionally included in the timing results.
456 void enableTiming();
457
458 //===--------------------------------------------------------------------===//
459 // Pass Statistics
460
461 /// Prompts the pass manager to print the statistics collected for each of the
462 /// held passes after each call to 'run'.
463 void
464 enableStatistics(PassDisplayMode displayMode = PassDisplayMode::Pipeline);
465
466private:
467 /// Dump the statistics of the passes within this pass manager.
468 void dumpStatistics();
469
470 /// Run the pass manager with crash recovery enabled.
471 LogicalResult runWithCrashRecovery(Operation *op, AnalysisManager am);
472
473 /// Run the passes of the pass manager, and return the result.
474 LogicalResult runPasses(Operation *op, AnalysisManager am);
475
476 /// Context this PassManager was initialized with.
477 MLIRContext *context;
478
479 /// Flag that specifies if pass statistics should be dumped.
480 std::optional<PassDisplayMode> passStatisticsMode;
481
482 /// A manager for pass instrumentations.
483 std::unique_ptr<PassInstrumentor> instrumentor;
484
485 /// An optional crash reproducer generator, if this pass manager is setup to
486 /// generate reproducers.
487 std::unique_ptr<detail::PassCrashReproducerGenerator> crashReproGenerator;
488
489 /// Hash keys used to detect when reinitialization is necessary.
490 llvm::hash_code initializationKey =
491 DenseMapInfo<llvm::hash_code>::getTombstoneKey();
492 llvm::hash_code pipelineInitializationKey =
493 DenseMapInfo<llvm::hash_code>::getTombstoneKey();
494
495 /// Flag that specifies if pass timing is enabled.
496 bool passTiming : 1;
497
498 /// A flag that indicates if the IR should be verified in between passes.
499 bool verifyPasses : 1;
500};
501
502/// Register a set of useful command-line options that can be used to configure
503/// a pass manager. The values of these options can be applied via the
504/// 'applyPassManagerCLOptions' method below.
505void registerPassManagerCLOptions();
506
507/// Apply any values provided to the pass manager options that were registered
508/// with 'registerPassManagerOptions'.
509LogicalResult applyPassManagerCLOptions(PassManager &pm);
510
511/// Apply any values provided to the timing manager options that were registered
512/// with `registerDefaultTimingManagerOptions`. This is a handy helper function
513/// if you do not want to bother creating your own timing manager and passing it
514/// to the pass manager.
515void applyDefaultTimingPassManagerCLOptions(PassManager &pm);
516
517} // namespace mlir
518
519#endif // MLIR_PASS_PASSMANAGER_H
520

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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