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 "llvm/ADT/Optional.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 23 namespace llvm { 24 class Any; 25 } // end namespace llvm 26 27 namespace mlir { 28 class AnalysisManager; 29 class Identifier; 30 class MLIRContext; 31 class Operation; 32 class Pass; 33 class PassInstrumentation; 34 class PassInstrumentor; 35 36 namespace detail { 37 struct OpPassManagerImpl; 38 struct PassExecutionState; 39 } // end namespace detail 40 41 //===----------------------------------------------------------------------===// 42 // OpPassManager 43 //===----------------------------------------------------------------------===// 44 45 /// This class represents a pass manager that runs passes on a specific 46 /// operation type. This class is not constructed directly, but nested within 47 /// other OpPassManagers or the top-level PassManager. 48 class OpPassManager { 49 public: 50 enum class Nesting { Implicit, Explicit }; 51 OpPassManager(Identifier name, Nesting nesting); 52 OpPassManager(StringRef name, Nesting nesting); 53 OpPassManager(OpPassManager &&rhs); 54 OpPassManager(const OpPassManager &rhs); 55 ~OpPassManager(); 56 OpPassManager &operator=(const OpPassManager &rhs); 57 58 /// Iterator over the passes in this pass manager. 59 using pass_iterator = 60 llvm::pointee_iterator<MutableArrayRef<std::unique_ptr<Pass>>::iterator>; 61 pass_iterator begin(); 62 pass_iterator end(); getPasses()63 iterator_range<pass_iterator> getPasses() { return {begin(), end()}; } 64 65 using const_pass_iterator = 66 llvm::pointee_iterator<ArrayRef<std::unique_ptr<Pass>>::const_iterator>; 67 const_pass_iterator begin() const; 68 const_pass_iterator end() const; getPasses()69 iterator_range<const_pass_iterator> getPasses() const { 70 return {begin(), end()}; 71 } 72 73 /// Nest a new operation pass manager for the given operation kind under this 74 /// pass manager. 75 OpPassManager &nest(Identifier nestedName); 76 OpPassManager &nest(StringRef nestedName); nest()77 template <typename OpT> OpPassManager &nest() { 78 return nest(OpT::getOperationName()); 79 } 80 81 /// Add the given pass to this pass manager. If this pass has a concrete 82 /// operation type, it must be the same type as this pass manager. 83 void addPass(std::unique_ptr<Pass> pass); 84 85 /// Add the given pass to a nested pass manager for the given operation kind 86 /// `OpT`. addNestedPass(std::unique_ptr<Pass> pass)87 template <typename OpT> void addNestedPass(std::unique_ptr<Pass> pass) { 88 nest<OpT>().addPass(std::move(pass)); 89 } 90 91 /// Returns the number of passes held by this manager. 92 size_t size() const; 93 94 /// Return the operation name that this pass manager operates on. 95 Identifier getOpName(MLIRContext &context) const; 96 97 /// Return the operation name that this pass manager operates on. 98 StringRef getOpName() const; 99 100 /// Returns the internal implementation instance. 101 detail::OpPassManagerImpl &getImpl(); 102 103 /// Prints out the passes of the pass manager as the textual representation 104 /// of pipelines. 105 /// Note: The quality of the string representation depends entirely on the 106 /// the correctness of per-pass overrides of Pass::printAsTextualPipeline. 107 void printAsTextualPipeline(raw_ostream &os); 108 109 /// Raw dump of the pass manager to llvm::errs(). 110 void dump(); 111 112 /// Merge the pass statistics of this class into 'other'. 113 void mergeStatisticsInto(OpPassManager &other); 114 115 /// Register dependent dialects for the current pass manager. 116 /// This is forwarding to every pass in this PassManager, see the 117 /// documentation for the same method on the Pass class. 118 void getDependentDialects(DialectRegistry &dialects) const; 119 120 /// Enable or disable the implicit nesting on this particular PassManager. 121 /// This will also apply to any newly nested PassManager built from this 122 /// instance. 123 void setNesting(Nesting nesting); 124 125 /// Return the current nesting mode. 126 Nesting getNesting(); 127 128 private: 129 /// A pointer to an internal implementation instance. 130 std::unique_ptr<detail::OpPassManagerImpl> impl; 131 132 /// Allow access to the constructor. 133 friend class PassManager; 134 friend class Pass; 135 136 /// Allow access. 137 friend detail::OpPassManagerImpl; 138 }; 139 140 //===----------------------------------------------------------------------===// 141 // PassManager 142 //===----------------------------------------------------------------------===// 143 144 /// An enum describing the different display modes for the information within 145 /// the pass manager. 146 enum class PassDisplayMode { 147 // In this mode the results are displayed in a list sorted by total, 148 // with each pass/analysis instance aggregated into one unique result. 149 List, 150 151 // In this mode the results are displayed in a nested pipeline view that 152 // mirrors the internal pass pipeline that is being executed in the pass 153 // manager. 154 Pipeline, 155 }; 156 157 /// The main pass manager and pipeline builder. 158 class PassManager : public OpPassManager { 159 public: 160 /// Create a new pass manager under the given context with a specific nesting 161 /// style. The created pass manager can schedule operations that match 162 /// `operationName`. 163 PassManager(MLIRContext *ctx, Nesting nesting = Nesting::Explicit, 164 StringRef operationName = "module"); PassManager(MLIRContext * ctx,StringRef operationName)165 PassManager(MLIRContext *ctx, StringRef operationName) 166 : PassManager(ctx, Nesting::Explicit, operationName) {} 167 ~PassManager(); 168 169 /// Run the passes within this manager on the provided operation. The 170 /// specified operation must have the same name as the one provided the pass 171 /// manager on construction. 172 LLVM_NODISCARD 173 LogicalResult run(Operation *op); 174 175 /// Return an instance of the context. getContext()176 MLIRContext *getContext() const { return context; } 177 178 /// Enable support for the pass manager to generate a reproducer on the event 179 /// of a crash or a pass failure. `outputFile` is a .mlir filename used to 180 /// write the generated reproducer. If `genLocalReproducer` is true, the pass 181 /// manager will attempt to generate a local reproducer that contains the 182 /// smallest pipeline. 183 void enableCrashReproducerGeneration(StringRef outputFile, 184 bool genLocalReproducer = false); 185 186 /// Runs the verifier after each individual pass. 187 void enableVerifier(bool enabled = true); 188 189 //===--------------------------------------------------------------------===// 190 // Instrumentations 191 //===--------------------------------------------------------------------===// 192 193 /// Add the provided instrumentation to the pass manager. 194 void addInstrumentation(std::unique_ptr<PassInstrumentation> pi); 195 196 //===--------------------------------------------------------------------===// 197 // IR Printing 198 199 /// A configuration struct provided to the IR printer instrumentation. 200 class IRPrinterConfig { 201 public: 202 using PrintCallbackFn = function_ref<void(raw_ostream &)>; 203 204 /// Initialize the configuration. 205 /// * 'printModuleScope' signals if the top-level module IR should always be 206 /// printed. This should only be set to true when multi-threading is 207 /// disabled, otherwise we may try to print IR that is being modified 208 /// asynchronously. 209 /// * 'printAfterOnlyOnChange' signals that when printing the IR after a 210 /// pass, in the case of a non-failure, we should first check if any 211 /// potential mutations were made. This allows for reducing the number of 212 /// logs that don't contain meaningful changes. 213 /// * 'opPrintingFlags' sets up the printing flags to use when printing the 214 /// IR. 215 explicit IRPrinterConfig( 216 bool printModuleScope = false, bool printAfterOnlyOnChange = false, 217 OpPrintingFlags opPrintingFlags = OpPrintingFlags()); 218 virtual ~IRPrinterConfig(); 219 220 /// A hook that may be overridden by a derived config that checks if the IR 221 /// of 'operation' should be dumped *before* the pass 'pass' has been 222 /// executed. If the IR should be dumped, 'printCallback' should be invoked 223 /// with the stream to dump into. 224 virtual void printBeforeIfEnabled(Pass *pass, Operation *operation, 225 PrintCallbackFn printCallback); 226 227 /// A hook that may be overridden by a derived config that checks if the IR 228 /// of 'operation' should be dumped *after* the pass 'pass' has been 229 /// executed. If the IR should be dumped, 'printCallback' should be invoked 230 /// with the stream to dump into. 231 virtual void printAfterIfEnabled(Pass *pass, Operation *operation, 232 PrintCallbackFn printCallback); 233 234 /// Returns true if the IR should always be printed at the top-level scope. shouldPrintAtModuleScope()235 bool shouldPrintAtModuleScope() const { return printModuleScope; } 236 237 /// Returns true if the IR should only printed after a pass if the IR 238 /// "changed". shouldPrintAfterOnlyOnChange()239 bool shouldPrintAfterOnlyOnChange() const { return printAfterOnlyOnChange; } 240 241 /// Returns the printing flags to be used to print the IR. getOpPrintingFlags()242 OpPrintingFlags getOpPrintingFlags() const { return opPrintingFlags; } 243 244 private: 245 /// A flag that indicates if the IR should be printed at module scope. 246 bool printModuleScope; 247 248 /// A flag that indicates that the IR after a pass should only be printed if 249 /// a change is detected. 250 bool printAfterOnlyOnChange; 251 252 /// Flags to control printing behavior. 253 OpPrintingFlags opPrintingFlags; 254 }; 255 256 /// Add an instrumentation to print the IR before and after pass execution, 257 /// using the provided configuration. 258 void enableIRPrinting(std::unique_ptr<IRPrinterConfig> config); 259 260 /// Add an instrumentation to print the IR before and after pass execution, 261 /// using the provided fields to generate a default configuration: 262 /// * 'shouldPrintBeforePass' and 'shouldPrintAfterPass' correspond to filter 263 /// functions that take a 'Pass *' and `Operation *`. These function should 264 /// return true if the IR should be printed or not. 265 /// * 'printModuleScope' signals if the module IR should be printed, even 266 /// for non module passes. 267 /// * 'printAfterOnlyOnChange' signals that when printing the IR after a 268 /// pass, in the case of a non-failure, we should first check if any 269 /// potential mutations were made. 270 /// * 'opPrintingFlags' sets up the printing flags to use when printing the 271 /// IR. 272 /// * 'out' corresponds to the stream to output the printed IR to. 273 void enableIRPrinting( 274 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass = 275 [](Pass *, Operation *) { return true; }, 276 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass = 277 [](Pass *, Operation *) { return true; }, 278 bool printModuleScope = true, bool printAfterOnlyOnChange = true, 279 raw_ostream &out = llvm::errs(), 280 OpPrintingFlags opPrintingFlags = OpPrintingFlags()); 281 282 //===--------------------------------------------------------------------===// 283 // Pass Timing 284 285 /// A configuration struct provided to the pass timing feature. 286 class PassTimingConfig { 287 public: 288 using PrintCallbackFn = function_ref<void(raw_ostream &)>; 289 290 /// Initialize the configuration. 291 /// * 'displayMode' switch between list or pipeline display (see the 292 /// `PassDisplayMode` enum documentation). 293 explicit PassTimingConfig( 294 PassDisplayMode displayMode = PassDisplayMode::Pipeline) displayMode(displayMode)295 : displayMode(displayMode) {} 296 297 virtual ~PassTimingConfig(); 298 299 /// A hook that may be overridden by a derived config to control the 300 /// printing. The callback is supplied by the framework and the config is 301 /// responsible to call it back with a stream for the output. 302 virtual void printTiming(PrintCallbackFn printCallback); 303 304 /// Return the `PassDisplayMode` this config was created with. getDisplayMode()305 PassDisplayMode getDisplayMode() { return displayMode; } 306 307 private: 308 PassDisplayMode displayMode; 309 }; 310 311 /// Add an instrumentation to time the execution of passes and the computation 312 /// of analyses. 313 /// Note: Timing should be enabled after all other instrumentations to avoid 314 /// any potential "ghost" timing from other instrumentations being 315 /// unintentionally included in the timing results. 316 void enableTiming(std::unique_ptr<PassTimingConfig> config = nullptr); 317 318 /// Prompts the pass manager to print the statistics collected for each of the 319 /// held passes after each call to 'run'. 320 void 321 enableStatistics(PassDisplayMode displayMode = PassDisplayMode::Pipeline); 322 323 private: 324 /// Dump the statistics of the passes within this pass manager. 325 void dumpStatistics(); 326 327 /// Run the pass manager with crash recover enabled. 328 LogicalResult runWithCrashRecovery(Operation *op, AnalysisManager am); 329 /// Run the given passes with crash recover enabled. 330 LogicalResult 331 runWithCrashRecovery(MutableArrayRef<std::unique_ptr<Pass>> passes, 332 Operation *op, AnalysisManager am); 333 334 /// Context this PassManager was initialized with. 335 MLIRContext *context; 336 337 /// Flag that specifies if pass statistics should be dumped. 338 Optional<PassDisplayMode> passStatisticsMode; 339 340 /// A manager for pass instrumentations. 341 std::unique_ptr<PassInstrumentor> instrumentor; 342 343 /// An optional filename to use when generating a crash reproducer if valid. 344 Optional<std::string> crashReproducerFileName; 345 346 /// Flag that specifies if pass timing is enabled. 347 bool passTiming : 1; 348 349 /// Flag that specifies if the generated crash reproducer should be local. 350 bool localReproducer : 1; 351 352 /// A flag that indicates if the IR should be verified in between passes. 353 bool verifyPasses : 1; 354 }; 355 356 /// Register a set of useful command-line options that can be used to configure 357 /// a pass manager. The values of these options can be applied via the 358 /// 'applyPassManagerCLOptions' method below. 359 void registerPassManagerCLOptions(); 360 361 /// Apply any values provided to the pass manager options that were registered 362 /// with 'registerPassManagerOptions'. 363 void applyPassManagerCLOptions(PassManager &pm); 364 } // end namespace mlir 365 366 #endif // MLIR_PASS_PASSMANAGER_H 367