1 | //===- Pass.h - Base classes for compiler passes ----------------*- 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_PASS_H |
10 | #define MLIR_PASS_PASS_H |
11 | |
12 | #include "mlir/IR/Action.h" |
13 | #include "mlir/Pass/AnalysisManager.h" |
14 | #include "mlir/Pass/PassRegistry.h" |
15 | #include "mlir/Support/LogicalResult.h" |
16 | #include "llvm/ADT/PointerIntPair.h" |
17 | #include "llvm/ADT/Statistic.h" |
18 | #include <optional> |
19 | |
20 | namespace mlir { |
21 | namespace detail { |
22 | class OpToOpPassAdaptor; |
23 | struct OpPassManagerImpl; |
24 | |
25 | /// The state for a single execution of a pass. This provides a unified |
26 | /// interface for accessing and initializing necessary state for pass execution. |
27 | struct PassExecutionState { |
28 | PassExecutionState(Operation *ir, AnalysisManager analysisManager, |
29 | function_ref<LogicalResult(OpPassManager &, Operation *)> |
30 | pipelineExecutor) |
31 | : irAndPassFailed(ir, false), analysisManager(analysisManager), |
32 | pipelineExecutor(pipelineExecutor) {} |
33 | |
34 | /// The current operation being transformed and a bool for if the pass |
35 | /// signaled a failure. |
36 | llvm::PointerIntPair<Operation *, 1, bool> irAndPassFailed; |
37 | |
38 | /// The analysis manager for the operation. |
39 | AnalysisManager analysisManager; |
40 | |
41 | /// The set of preserved analyses for the current execution. |
42 | detail::PreservedAnalyses preservedAnalyses; |
43 | |
44 | /// This is a callback in the PassManager that allows to schedule dynamic |
45 | /// pipelines that will be rooted at the provided operation. |
46 | function_ref<LogicalResult(OpPassManager &, Operation *)> pipelineExecutor; |
47 | }; |
48 | } // namespace detail |
49 | |
50 | /// The abstract base pass class. This class contains information describing the |
51 | /// derived pass object, e.g its kind and abstract TypeID. |
52 | class Pass { |
53 | public: |
54 | virtual ~Pass() = default; |
55 | |
56 | /// Returns the unique identifier that corresponds to this pass. |
57 | TypeID getTypeID() const { return passID; } |
58 | |
59 | /// Returns the pass info for this pass, or null if unknown. |
60 | const PassInfo *lookupPassInfo() const { |
61 | return PassInfo::lookup(passArg: getArgument()); |
62 | } |
63 | |
64 | /// Returns the derived pass name. |
65 | virtual StringRef getName() const = 0; |
66 | |
67 | /// Register dependent dialects for the current pass. |
68 | /// A pass is expected to register the dialects it will create entities for |
69 | /// (Operations, Types, Attributes), other than dialect that exists in the |
70 | /// input. For example, a pass that converts from Linalg to Affine would |
71 | /// register the Affine dialect but does not need to register Linalg. |
72 | virtual void getDependentDialects(DialectRegistry ®istry) const {} |
73 | |
74 | /// Return the command line argument used when registering this pass. Return |
75 | /// an empty string if one does not exist. |
76 | virtual StringRef getArgument() const { return "" ; } |
77 | |
78 | /// Return the command line description used when registering this pass. |
79 | /// Return an empty string if one does not exist. |
80 | virtual StringRef getDescription() const { return "" ; } |
81 | |
82 | /// Returns the name of the operation that this pass operates on, or |
83 | /// std::nullopt if this is a generic OperationPass. |
84 | std::optional<StringRef> getOpName() const { return opName; } |
85 | |
86 | //===--------------------------------------------------------------------===// |
87 | // Options |
88 | //===--------------------------------------------------------------------===// |
89 | |
90 | /// This class represents a specific pass option, with a provided data type. |
91 | template <typename DataType, |
92 | typename OptionParser = detail::PassOptions::OptionParser<DataType>> |
93 | struct Option : public detail::PassOptions::Option<DataType, OptionParser> { |
94 | template <typename... Args> |
95 | Option(Pass &parent, StringRef arg, Args &&...args) |
96 | : detail::PassOptions::Option<DataType, OptionParser>( |
97 | parent.passOptions, arg, std::forward<Args>(args)...) {} |
98 | using detail::PassOptions::Option<DataType, OptionParser>::operator=; |
99 | }; |
100 | /// This class represents a specific pass option that contains a list of |
101 | /// values of the provided data type. |
102 | template <typename DataType, |
103 | typename OptionParser = detail::PassOptions::OptionParser<DataType>> |
104 | struct ListOption |
105 | : public detail::PassOptions::ListOption<DataType, OptionParser> { |
106 | template <typename... Args> |
107 | ListOption(Pass &parent, StringRef arg, Args &&...args) |
108 | : detail::PassOptions::ListOption<DataType, OptionParser>( |
109 | parent.passOptions, arg, std::forward<Args>(args)...) {} |
110 | using detail::PassOptions::ListOption<DataType, OptionParser>::operator=; |
111 | }; |
112 | |
113 | /// Attempt to initialize the options of this pass from the given string. |
114 | /// Derived classes may override this method to hook into the point at which |
115 | /// options are initialized, but should generally always invoke this base |
116 | /// class variant. |
117 | virtual LogicalResult |
118 | initializeOptions(StringRef options, |
119 | function_ref<LogicalResult(const Twine &)> errorHandler); |
120 | |
121 | /// Prints out the pass in the textual representation of pipelines. If this is |
122 | /// an adaptor pass, print its pass managers. |
123 | void printAsTextualPipeline(raw_ostream &os); |
124 | |
125 | //===--------------------------------------------------------------------===// |
126 | // Statistics |
127 | //===--------------------------------------------------------------------===// |
128 | |
129 | /// This class represents a single pass statistic. This statistic functions |
130 | /// similarly to an unsigned integer value, and may be updated and incremented |
131 | /// accordingly. This class can be used to provide additional information |
132 | /// about the transformations and analyses performed by a pass. |
133 | class Statistic : public llvm::Statistic { |
134 | public: |
135 | /// The statistic is initialized by the pass owner, a name, and a |
136 | /// description. |
137 | Statistic(Pass *owner, const char *name, const char *description); |
138 | |
139 | /// Assign the statistic to the given value. |
140 | Statistic &operator=(unsigned value); |
141 | }; |
142 | |
143 | /// Returns the main statistics for this pass instance. |
144 | ArrayRef<Statistic *> getStatistics() const { return statistics; } |
145 | MutableArrayRef<Statistic *> getStatistics() { return statistics; } |
146 | |
147 | /// Returns the thread sibling of this pass. |
148 | /// |
149 | /// If this pass was cloned by the pass manager for the sake of |
150 | /// multi-threading, this function returns the original pass it was cloned |
151 | /// from. This is useful for diagnostic purposes to distinguish passes that |
152 | /// were replicated for threading purposes from passes instantiated by the |
153 | /// user. Used to collapse passes in timing statistics. |
154 | const Pass *getThreadingSibling() const { return threadingSibling; } |
155 | |
156 | /// Returns the thread sibling of this pass, or the pass itself it has no |
157 | /// sibling. See `getThreadingSibling()` for details. |
158 | const Pass *getThreadingSiblingOrThis() const { |
159 | return threadingSibling ? threadingSibling : this; |
160 | } |
161 | |
162 | protected: |
163 | explicit Pass(TypeID passID, std::optional<StringRef> opName = std::nullopt) |
164 | : passID(passID), opName(opName) {} |
165 | Pass(const Pass &other) : Pass(other.passID, other.opName) {} |
166 | Pass &operator=(const Pass &) = delete; |
167 | Pass(Pass &&) = delete; |
168 | Pass &operator=(Pass &&) = delete; |
169 | |
170 | /// Returns the current pass state. |
171 | detail::PassExecutionState &getPassState() { |
172 | assert(passState && "pass state was never initialized" ); |
173 | return *passState; |
174 | } |
175 | |
176 | /// Return the MLIR context for the current operation being transformed. |
177 | MLIRContext &getContext() { return *getOperation()->getContext(); } |
178 | |
179 | /// The polymorphic API that runs the pass over the currently held operation. |
180 | virtual void runOnOperation() = 0; |
181 | |
182 | /// Initialize any complex state necessary for running this pass. This hook |
183 | /// should not rely on any state accessible during the execution of a pass. |
184 | /// For example, `getContext`/`getOperation`/`getAnalysis`/etc. should not be |
185 | /// invoked within this hook. |
186 | /// This method is invoked after all dependent dialects for the pipeline are |
187 | /// loaded, and is not allowed to load any further dialects (override the |
188 | /// `getDependentDialects()` for this purpose instead). Returns a LogicalResult |
189 | /// to indicate failure, in which case the pass pipeline won't execute. |
190 | virtual LogicalResult initialize(MLIRContext *context) { return success(); } |
191 | |
192 | /// Indicate if the current pass can be scheduled on the given operation type. |
193 | /// This is useful for generic operation passes to add restrictions on the |
194 | /// operations they operate on. |
195 | virtual bool canScheduleOn(RegisteredOperationName opName) const = 0; |
196 | |
197 | /// Schedule an arbitrary pass pipeline on the provided operation. |
198 | /// This can be invoke any time in a pass to dynamic schedule more passes. |
199 | /// The provided operation must be the current one or one nested below. |
200 | LogicalResult runPipeline(OpPassManager &pipeline, Operation *op) { |
201 | return passState->pipelineExecutor(pipeline, op); |
202 | } |
203 | |
204 | /// A clone method to create a copy of this pass. |
205 | std::unique_ptr<Pass> clone() const { |
206 | auto newInst = clonePass(); |
207 | newInst->copyOptionValuesFrom(other: this); |
208 | return newInst; |
209 | } |
210 | |
211 | /// Return the current operation being transformed. |
212 | Operation *getOperation() { |
213 | return getPassState().irAndPassFailed.getPointer(); |
214 | } |
215 | |
216 | /// Signal that some invariant was broken when running. The IR is allowed to |
217 | /// be in an invalid state. |
218 | void signalPassFailure() { getPassState().irAndPassFailed.setInt(true); } |
219 | |
220 | /// Query an analysis for the current ir unit. |
221 | template <typename AnalysisT> |
222 | AnalysisT &getAnalysis() { |
223 | return getAnalysisManager().getAnalysis<AnalysisT>(); |
224 | } |
225 | |
226 | /// Query an analysis for the current ir unit of a specific derived operation |
227 | /// type. |
228 | template <typename AnalysisT, typename OpT> |
229 | AnalysisT &getAnalysis() { |
230 | return getAnalysisManager().getAnalysis<AnalysisT, OpT>(); |
231 | } |
232 | |
233 | /// Query a cached instance of an analysis for the current ir unit if one |
234 | /// exists. |
235 | template <typename AnalysisT> |
236 | std::optional<std::reference_wrapper<AnalysisT>> getCachedAnalysis() { |
237 | return getAnalysisManager().getCachedAnalysis<AnalysisT>(); |
238 | } |
239 | |
240 | /// Mark all analyses as preserved. |
241 | void markAllAnalysesPreserved() { |
242 | getPassState().preservedAnalyses.preserveAll(); |
243 | } |
244 | |
245 | /// Mark the provided analyses as preserved. |
246 | template <typename... AnalysesT> |
247 | void markAnalysesPreserved() { |
248 | getPassState().preservedAnalyses.preserve<AnalysesT...>(); |
249 | } |
250 | void markAnalysesPreserved(TypeID id) { |
251 | getPassState().preservedAnalyses.preserve(id); |
252 | } |
253 | |
254 | /// Returns the analysis for the given parent operation if it exists. |
255 | template <typename AnalysisT> |
256 | std::optional<std::reference_wrapper<AnalysisT>> |
257 | getCachedParentAnalysis(Operation *parent) { |
258 | return getAnalysisManager().getCachedParentAnalysis<AnalysisT>(parent); |
259 | } |
260 | |
261 | /// Returns the analysis for the parent operation if it exists. |
262 | template <typename AnalysisT> |
263 | std::optional<std::reference_wrapper<AnalysisT>> getCachedParentAnalysis() { |
264 | return getAnalysisManager().getCachedParentAnalysis<AnalysisT>( |
265 | getOperation()->getParentOp()); |
266 | } |
267 | |
268 | /// Returns the analysis for the given child operation if it exists. |
269 | template <typename AnalysisT> |
270 | std::optional<std::reference_wrapper<AnalysisT>> |
271 | getCachedChildAnalysis(Operation *child) { |
272 | return getAnalysisManager().getCachedChildAnalysis<AnalysisT>(child); |
273 | } |
274 | |
275 | /// Returns the analysis for the given child operation, or creates it if it |
276 | /// doesn't exist. |
277 | template <typename AnalysisT> |
278 | AnalysisT &getChildAnalysis(Operation *child) { |
279 | return getAnalysisManager().getChildAnalysis<AnalysisT>(child); |
280 | } |
281 | |
282 | /// Returns the analysis for the given child operation of specific derived |
283 | /// operation type, or creates it if it doesn't exist. |
284 | template <typename AnalysisT, typename OpTy> |
285 | AnalysisT &getChildAnalysis(OpTy child) { |
286 | return getAnalysisManager().getChildAnalysis<AnalysisT>(child); |
287 | } |
288 | |
289 | /// Returns the current analysis manager. |
290 | AnalysisManager getAnalysisManager() { |
291 | return getPassState().analysisManager; |
292 | } |
293 | |
294 | /// Create a copy of this pass, ignoring statistics and options. |
295 | virtual std::unique_ptr<Pass> clonePass() const = 0; |
296 | |
297 | /// Copy the option values from 'other', which is another instance of this |
298 | /// pass. |
299 | void copyOptionValuesFrom(const Pass *other); |
300 | |
301 | private: |
302 | /// Out of line virtual method to ensure vtables and metadata are emitted to a |
303 | /// single .o file. |
304 | virtual void anchor(); |
305 | |
306 | /// Represents a unique identifier for the pass. |
307 | TypeID passID; |
308 | |
309 | /// The name of the operation that this pass operates on, or std::nullopt if |
310 | /// this is a generic OperationPass. |
311 | std::optional<StringRef> opName; |
312 | |
313 | /// The current execution state for the pass. |
314 | std::optional<detail::PassExecutionState> passState; |
315 | |
316 | /// The set of statistics held by this pass. |
317 | std::vector<Statistic *> statistics; |
318 | |
319 | /// The pass options registered to this pass instance. |
320 | detail::PassOptions passOptions; |
321 | |
322 | /// A pointer to the pass this pass was cloned from, if the clone was made by |
323 | /// the pass manager for the sake of multi-threading. |
324 | const Pass *threadingSibling = nullptr; |
325 | |
326 | /// Allow access to 'clone'. |
327 | friend class OpPassManager; |
328 | |
329 | /// Allow access to 'canScheduleOn'. |
330 | friend detail::OpPassManagerImpl; |
331 | |
332 | /// Allow access to 'passState'. |
333 | friend detail::OpToOpPassAdaptor; |
334 | |
335 | /// Allow access to 'passOptions'. |
336 | friend class PassInfo; |
337 | }; |
338 | |
339 | //===----------------------------------------------------------------------===// |
340 | // Pass Model Definitions |
341 | //===----------------------------------------------------------------------===// |
342 | |
343 | /// Pass to transform an operation of a specific type. |
344 | /// |
345 | /// Operation passes must not: |
346 | /// - modify any other operations within the parent region, as other threads |
347 | /// may be manipulating them concurrently. |
348 | /// - modify any state within the parent operation, this includes adding |
349 | /// additional operations. |
350 | /// |
351 | /// Derived operation passes are expected to provide the following: |
352 | /// - A 'void runOnOperation()' method. |
353 | /// - A 'StringRef getName() const' method. |
354 | /// - A 'std::unique_ptr<Pass> clonePass() const' method. |
355 | template <typename OpT = void> |
356 | class OperationPass : public Pass { |
357 | public: |
358 | ~OperationPass() override = default; |
359 | |
360 | protected: |
361 | OperationPass(TypeID passID) : Pass(passID, OpT::getOperationName()) {} |
362 | OperationPass(const OperationPass &) = default; |
363 | OperationPass &operator=(const OperationPass &) = delete; |
364 | OperationPass(OperationPass &&) = delete; |
365 | OperationPass &operator=(OperationPass &&) = delete; |
366 | |
367 | /// Support isa/dyn_cast functionality. |
368 | static bool classof(const Pass *pass) { |
369 | return pass->getOpName() == OpT::getOperationName(); |
370 | } |
371 | |
372 | /// Indicate if the current pass can be scheduled on the given operation type. |
373 | bool canScheduleOn(RegisteredOperationName opName) const final { |
374 | return opName.getStringRef() == getOpName(); |
375 | } |
376 | |
377 | /// Return the current operation being transformed. |
378 | OpT getOperation() { return cast<OpT>(Pass::getOperation()); } |
379 | |
380 | /// Query an analysis for the current operation of the specific derived |
381 | /// operation type. |
382 | template <typename AnalysisT> |
383 | AnalysisT &getAnalysis() { |
384 | return Pass::getAnalysis<AnalysisT, OpT>(); |
385 | } |
386 | }; |
387 | |
388 | /// Pass to transform an operation. |
389 | /// |
390 | /// Operation passes must not: |
391 | /// - modify any other operations within the parent region, as other threads |
392 | /// may be manipulating them concurrently. |
393 | /// - modify any state within the parent operation, this includes adding |
394 | /// additional operations. |
395 | /// |
396 | /// Derived operation passes are expected to provide the following: |
397 | /// - A 'void runOnOperation()' method. |
398 | /// - A 'StringRef getName() const' method. |
399 | /// - A 'std::unique_ptr<Pass> clonePass() const' method. |
400 | template <> |
401 | class OperationPass<void> : public Pass { |
402 | public: |
403 | ~OperationPass() override = default; |
404 | |
405 | protected: |
406 | OperationPass(TypeID passID) : Pass(passID) {} |
407 | OperationPass(const OperationPass &) = default; |
408 | OperationPass &operator=(const OperationPass &) = delete; |
409 | OperationPass(OperationPass &&) = delete; |
410 | OperationPass &operator=(OperationPass &&) = delete; |
411 | |
412 | /// Indicate if the current pass can be scheduled on the given operation type. |
413 | /// By default, generic operation passes can be scheduled on any operation. |
414 | bool canScheduleOn(RegisteredOperationName opName) const override { |
415 | return true; |
416 | } |
417 | }; |
418 | |
419 | /// Pass to transform an operation that implements the given interface. |
420 | /// |
421 | /// Interface passes must not: |
422 | /// - modify any other operations within the parent region, as other threads |
423 | /// may be manipulating them concurrently. |
424 | /// - modify any state within the parent operation, this includes adding |
425 | /// additional operations. |
426 | /// |
427 | /// Derived interface passes are expected to provide the following: |
428 | /// - A 'void runOnOperation()' method. |
429 | /// - A 'StringRef getName() const' method. |
430 | /// - A 'std::unique_ptr<Pass> clonePass() const' method. |
431 | template <typename InterfaceT> |
432 | class InterfacePass : public OperationPass<> { |
433 | protected: |
434 | using OperationPass::OperationPass; |
435 | |
436 | /// Indicate if the current pass can be scheduled on the given operation type. |
437 | /// For an InterfacePass, this checks if the operation implements the given |
438 | /// interface. |
439 | bool canScheduleOn(RegisteredOperationName opName) const final { |
440 | return opName.hasInterface<InterfaceT>(); |
441 | } |
442 | |
443 | /// Return the current operation being transformed. |
444 | InterfaceT getOperation() { return cast<InterfaceT>(Pass::getOperation()); } |
445 | |
446 | /// Query an analysis for the current operation. |
447 | template <typename AnalysisT> |
448 | AnalysisT &getAnalysis() { |
449 | return Pass::getAnalysis<AnalysisT, InterfaceT>(); |
450 | } |
451 | }; |
452 | |
453 | /// This class provides a CRTP wrapper around a base pass class to define |
454 | /// several necessary utility methods. This should only be used for passes that |
455 | /// are not suitably represented using the declarative pass specification(i.e. |
456 | /// tablegen backend). |
457 | template <typename PassT, typename BaseT> |
458 | class PassWrapper : public BaseT { |
459 | public: |
460 | /// Support isa/dyn_cast functionality for the derived pass class. |
461 | static bool classof(const Pass *pass) { |
462 | return pass->getTypeID() == TypeID::get<PassT>(); |
463 | } |
464 | ~PassWrapper() override = default; |
465 | |
466 | protected: |
467 | PassWrapper() : BaseT(TypeID::get<PassT>()) {} |
468 | PassWrapper(const PassWrapper &) = default; |
469 | PassWrapper &operator=(const PassWrapper &) = delete; |
470 | PassWrapper(PassWrapper &&) = delete; |
471 | PassWrapper &operator=(PassWrapper &&) = delete; |
472 | |
473 | /// Returns the derived pass name. |
474 | StringRef getName() const override { return llvm::getTypeName<PassT>(); } |
475 | |
476 | /// A clone method to create a copy of this pass. |
477 | std::unique_ptr<Pass> clonePass() const override { |
478 | return std::make_unique<PassT>(*static_cast<const PassT *>(this)); |
479 | } |
480 | }; |
481 | |
482 | /// This class encapsulates the "action" of executing a single pass. This allows |
483 | /// a user of the Action infrastructure to query information about an action in |
484 | /// (for example) a breakpoint context. You could use it like this: |
485 | /// |
486 | /// auto onBreakpoint = [&](const ActionActiveStack *backtrace) { |
487 | /// if (auto passExec = dyn_cast<PassExecutionAction>(anAction)) |
488 | /// record(passExec.getPass()); |
489 | /// return ExecutionContext::Apply; |
490 | /// }; |
491 | /// ExecutionContext exeCtx(onBreakpoint); |
492 | /// |
493 | class PassExecutionAction : public tracing::ActionImpl<PassExecutionAction> { |
494 | using Base = tracing::ActionImpl<PassExecutionAction>; |
495 | |
496 | public: |
497 | /// Define a TypeID for this PassExecutionAction. |
498 | MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(PassExecutionAction) |
499 | /// Construct a PassExecutionAction. This is called by the OpToOpPassAdaptor |
500 | /// when it calls `executeAction`. |
501 | PassExecutionAction(ArrayRef<IRUnit> irUnits, const Pass &pass); |
502 | |
503 | /// The tag required by ActionImpl to identify this action. |
504 | static constexpr StringLiteral tag = "pass-execution" ; |
505 | |
506 | /// Print a textual version of this action to `os`. |
507 | void print(raw_ostream &os) const override; |
508 | |
509 | /// Get the pass that will be executed by this action. This is not a class of |
510 | /// passes, or all instances of a pass kind, this is a single pass. |
511 | const Pass &getPass() const { return pass; } |
512 | |
513 | /// Get the operation that is the base of this pass. For example, an |
514 | /// OperationPass<ModuleOp> would return a ModuleOp. |
515 | Operation *getOp() const; |
516 | |
517 | public: |
518 | /// Reference to the pass being run. Notice that this will *not* extend the |
519 | /// lifetime of the pass, and so this class is therefore unsafe to keep past |
520 | /// the lifetime of the `executeAction` call. |
521 | const Pass &pass; |
522 | |
523 | /// The base op for this pass. For an OperationPass<ModuleOp>, we would have a |
524 | /// ModuleOp here. |
525 | Operation *op; |
526 | }; |
527 | |
528 | } // namespace mlir |
529 | |
530 | #endif // MLIR_PASS_PASS_H |
531 | |