MLIR 22.0.0git
Pass.cpp
Go to the documentation of this file.
1//===- Pass.cpp - Pass infrastructure implementation ----------------------===//
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// This file implements common pass infrastructure.
10//
11//===----------------------------------------------------------------------===//
12
13#include "mlir/Pass/Pass.h"
14#include "PassDetail.h"
15#include "mlir/IR/Diagnostics.h"
17#include "mlir/IR/Threading.h"
18#include "mlir/IR/Verifier.h"
21#include "llvm/ADT/Hashing.h"
22#include "llvm/ADT/STLExtras.h"
23#include "llvm/ADT/ScopeExit.h"
24#include "llvm/Support/DebugLog.h"
25#include "llvm/Support/Mutex.h"
26#include "llvm/Support/Signals.h"
27#include "llvm/Support/Threading.h"
28#include <optional>
29
30#define DEBUG_TYPE "pass-manager"
31
32using namespace mlir;
33using namespace mlir::detail;
34
35//===----------------------------------------------------------------------===//
36// PassExecutionAction
37//===----------------------------------------------------------------------===//
38
42
44 os << llvm::formatv("`{0}` running `{1}` on Operation `{2}`", tag,
45 pass.getName(), getOp()->getName());
46}
47
50 return irUnits.empty() ? nullptr
51 : llvm::dyn_cast_if_present<Operation *>(irUnits[0]);
52}
53
55
56//===----------------------------------------------------------------------===//
57// Pass
58//===----------------------------------------------------------------------===//
59
60/// Out of line virtual method to ensure vtables and metadata are emitted to a
61/// single .o file.
62void Pass::anchor() {}
63
64/// Attempt to initialize the options of this pass from the given string.
66 StringRef options,
67 function_ref<LogicalResult(const Twine &)> errorHandler) {
68 std::string errStr;
69 llvm::raw_string_ostream os(errStr);
70 if (failed(passOptions.parseFromString(options, os))) {
71 return errorHandler(errStr);
72 }
73 return success();
74}
75
76/// Copy the option values from 'other', which is another instance of this
77/// pass.
78void Pass::copyOptionValuesFrom(const Pass *other) {
79 passOptions.copyOptionValuesFrom(other->passOptions);
80}
81
82/// Prints out the pass in the textual representation of pipelines. If this is
83/// an adaptor pass, print its pass managers. When `pretty` is true, the
84/// printed pipeline is formatted for readability.
86 // Special case for adaptors to print its pass managers.
87 if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(this)) {
88 llvm::interleave(
89 adaptor->getPassManagers(),
90 [&](OpPassManager &pm) { pm.printAsTextualPipeline(os, pretty); },
91 [&] {
92 os << ",";
93 if (pretty)
94 os << "\n";
95 });
96 return;
97 }
98 // Otherwise, print the pass argument followed by its options. If the pass
99 // doesn't have an argument, print the name of the pass to give some indicator
100 // of what pass was run.
101 StringRef argument = getArgument();
102 if (!argument.empty())
103 os << argument;
104 else
105 os << "unknown<" << getName() << ">";
106 passOptions.print(os);
107}
108
109//===----------------------------------------------------------------------===//
110// OpPassManagerImpl
111//===----------------------------------------------------------------------===//
112
113namespace mlir {
114namespace detail {
120 : name(name == OpPassManager::getAnyOpAnchorName() ? "" : name.str()),
128 for (const std::unique_ptr<Pass> &pass : rhs.passes) {
129 std::unique_ptr<Pass> newPass = pass->clone();
130 newPass->threadingSibling = pass.get();
131 passes.push_back(std::move(newPass));
132 }
133 }
134
135 /// Merge the passes of this pass manager into the one provided.
137
138 /// Nest a new operation pass manager for the given operation kind under this
139 /// pass manager.
141 return nest(OpPassManager(nestedName, nesting));
142 }
143 OpPassManager &nest(StringRef nestedName) {
144 return nest(OpPassManager(nestedName, nesting));
145 }
147
148 /// Nest the given pass manager under this pass manager.
150
151 /// Add the given pass to this pass manager. If this pass has a concrete
152 /// operation type, it must be the same type as this pass manager.
153 void addPass(std::unique_ptr<Pass> pass);
154
155 /// Clear the list of passes in this pass manager, other options are
156 /// preserved.
157 void clear();
158
159 /// Finalize the pass list in preparation for execution. This includes
160 /// coalescing adjacent pass managers when possible, verifying scheduled
161 /// passes, etc.
162 LogicalResult finalizePassList(MLIRContext *ctx);
163
164 /// Return the operation name of this pass manager.
165 std::optional<OperationName> getOpName(MLIRContext &context) {
166 if (!name.empty() && !opName)
167 opName = OperationName(name, &context);
168 return opName;
169 }
170 std::optional<StringRef> getOpName() const {
171 return name.empty() ? std::optional<StringRef>()
172 : std::optional<StringRef>(name);
173 }
174
175 /// Return the name used to anchor this pass manager. This is either the name
176 /// of an operation, or the result of `getAnyOpAnchorName()` in the case of an
177 /// op-agnostic pass manager.
178 StringRef getOpAnchorName() const {
179 return getOpName().value_or(OpPassManager::getAnyOpAnchorName());
180 }
181
182 /// Indicate if the current pass manager can be scheduled on the given
183 /// operation type.
185
186 /// The name of the operation that passes of this pass manager operate on.
187 std::string name;
188
189 /// The cached OperationName (internalized in the context) for the name of the
190 /// operation that passes of this pass manager operate on.
191 std::optional<OperationName> opName;
192
193 /// The set of passes to run as part of this pass manager.
194 std::vector<std::unique_ptr<Pass>> passes;
195
196 /// The current initialization generation of this pass manager. This is used
197 /// to indicate when a pass manager should be reinitialized.
199
200 /// Control the implicit nesting of passes that mismatch the name set for this
201 /// OpPassManager.
203};
204} // namespace detail
205} // namespace mlir
206
208 assert(name == rhs.name && "merging unrelated pass managers");
209 for (auto &pass : passes)
210 rhs.passes.push_back(std::move(pass));
211 passes.clear();
212}
213
215 auto *adaptor = new OpToOpPassAdaptor(std::move(nested));
216 addPass(std::unique_ptr<Pass>(adaptor));
217 return adaptor->getPassManagers().front();
218}
219
220void OpPassManagerImpl::addPass(std::unique_ptr<Pass> pass) {
221 // If this pass runs on a different operation than this pass manager, then
222 // implicitly nest a pass manager for this operation if enabled.
223 std::optional<StringRef> pmOpName = getOpName();
224 std::optional<StringRef> passOpName = pass->getOpName();
225 if (pmOpName && passOpName && *pmOpName != *passOpName) {
227 return nest(*passOpName).addPass(std::move(pass));
228 llvm::report_fatal_error(llvm::Twine("Can't add pass '") + pass->getName() +
229 "' restricted to '" + *passOpName +
230 "' on a PassManager intended to run on '" +
231 getOpAnchorName() + "', did you intend to nest?");
232 }
233
234 passes.emplace_back(std::move(pass));
235}
236
238
240 auto finalizeAdaptor = [ctx](OpToOpPassAdaptor *adaptor) {
241 for (auto &pm : adaptor->getPassManagers())
242 if (failed(pm.getImpl().finalizePassList(ctx)))
243 return failure();
244 return success();
245 };
246
247 // Walk the pass list and merge adjacent adaptors.
248 LDBG(3) << "Merging adjacent adaptors in pass list";
249 OpToOpPassAdaptor *lastAdaptor = nullptr;
250 for (auto &pass : passes) {
251 // Check to see if this pass is an adaptor.
252 if (auto *currentAdaptor = dyn_cast<OpToOpPassAdaptor>(pass.get())) {
253 // If it is the first adaptor in a possible chain, remember it and
254 // continue.
255 if (!lastAdaptor) {
256 LDBG(3) << "Found first adaptor in chain";
257 lastAdaptor = currentAdaptor;
258 continue;
259 }
260
261 // Otherwise, try to merge into the existing adaptor and delete the
262 // current one. If merging fails, just remember this as the last adaptor.
263 LDBG(3) << "Attempting to merge adaptor with "
264 << currentAdaptor->getPassManagers().size()
265 << " managers into previous adaptor";
266 if (succeeded(currentAdaptor->tryMergeInto(ctx, *lastAdaptor))) {
267 LDBG(3) << "Successfully merged adaptors, removing current one";
268 pass.reset();
269 } else {
270 LDBG(3) << "Failed to merge adaptors, keeping current as last";
271 lastAdaptor = currentAdaptor;
272 }
273 } else if (lastAdaptor) {
274 // If this pass isn't an adaptor, finalize it and forget the last adaptor.
275 LDBG(3) << "Finalizing adaptor chain before non-adaptor pass";
276 if (failed(finalizeAdaptor(lastAdaptor)))
277 return failure();
278 lastAdaptor = nullptr;
279 }
280 }
281
282 // If there was an adaptor at the end of the manager, finalize it as well.
283 if (lastAdaptor && failed(finalizeAdaptor(lastAdaptor)))
284 return failure();
285
286 // Now that the adaptors have been merged, erase any empty slots corresponding
287 // to the merged adaptors that were nulled-out in the loop above.
288 size_t beforeErase = passes.size();
289 llvm::erase_if(passes, std::logical_not<std::unique_ptr<Pass>>());
290 if (beforeErase != passes.size()) {
291 LDBG(3) << "Removed " << (beforeErase - passes.size())
292 << " merged adaptor slots from pass list";
293 }
294
295 // If this is a op-agnostic pass manager, there is nothing left to do.
296 std::optional<OperationName> rawOpName = getOpName(*ctx);
297 if (!rawOpName) {
298 LDBG(3)
299 << "Op-agnostic pass manager, skipping operation-specific verification";
300 return success();
301 }
302
303 // Otherwise, verify that all of the passes are valid for the current
304 // operation anchor.
305 LDBG(3) << "Verifying " << passes.size() << " passes for operation '"
306 << getOpAnchorName() << "'";
307
308 std::optional<RegisteredOperationName> opName =
309 rawOpName->getRegisteredInfo();
310 for (std::unique_ptr<Pass> &pass : passes) {
311 if (opName && !pass->canScheduleOn(*opName)) {
312 return emitError(UnknownLoc::get(ctx))
313 << "unable to schedule pass '" << pass->getName()
314 << "' on a PassManager intended to run on '" << getOpAnchorName()
315 << "'!";
316 }
317 }
318
319 LDBG(3) << "Pass list finalization completed successfully";
320 return success();
321}
322
325 // If this pass manager is op-specific, we simply check if the provided
326 // operation name is the same as this one.
327 std::optional<OperationName> pmOpName = getOpName(context);
328 if (pmOpName)
329 return pmOpName == opName;
330
331 // Otherwise, this is an op-agnostic pass manager. Check that the operation
332 // can be scheduled on all passes within the manager.
333 std::optional<RegisteredOperationName> registeredInfo =
334 opName.getRegisteredInfo();
335 if (!registeredInfo ||
336 !registeredInfo->hasTrait<OpTrait::IsIsolatedFromAbove>())
337 return false;
338 return llvm::all_of(passes, [&](const std::unique_ptr<Pass> &pass) {
339 return pass->canScheduleOn(*registeredInfo);
340 });
341}
342
343//===----------------------------------------------------------------------===//
344// OpPassManager
345//===----------------------------------------------------------------------===//
346
349OpPassManager::OpPassManager(StringRef name, Nesting nesting)
350 : impl(new OpPassManagerImpl(name, nesting)) {}
352 : impl(new OpPassManagerImpl(name, nesting)) {}
356 impl = std::make_unique<OpPassManagerImpl>(*rhs.impl);
357 return *this;
358}
360 impl = std::move(rhs.impl);
361 return *this;
362}
363
365
372
379
380/// Nest a new operation pass manager for the given operation kind under this
381/// pass manager.
383 return impl->nest(nestedName);
384}
385OpPassManager &OpPassManager::nest(StringRef nestedName) {
386 return impl->nest(nestedName);
387}
389
390/// Add the given pass to this pass manager. If this pass has a concrete
391/// operation type, it must be the same type as this pass manager.
392void OpPassManager::addPass(std::unique_ptr<Pass> pass) {
393 impl->addPass(std::move(pass));
394}
395
396void OpPassManager::clear() { impl->clear(); }
397
398/// Returns the number of passes held by this manager.
399size_t OpPassManager::size() const { return impl->passes.size(); }
400
401/// Returns the internal implementation instance.
403
404/// Return the operation name that this pass manager operates on.
405std::optional<StringRef> OpPassManager::getOpName() const {
406 return impl->getOpName();
407}
408
409/// Return the operation name that this pass manager operates on.
410std::optional<OperationName>
412 return impl->getOpName(context);
413}
414
416 return impl->getOpAnchorName();
417}
418
419/// Prints out the passes of the pass manager as the textual representation
420/// of pipelines. When `pretty` is true, the printed pipeline is formatted for
421/// readability.
423 raw_indented_ostream &os, StringRef anchorName,
425 bool pretty = false) {
426 os << anchorName << "(";
427 if (pretty) {
428 os << "\n";
429 os.indent();
430 }
431 llvm::interleave(
432 passes,
433 [&](mlir::Pass &pass) { pass.printAsTextualPipeline(os, pretty); },
434 [&]() {
435 os << ",";
436 if (pretty)
437 os << "\n";
438 });
439 if (pretty) {
440 os << "\n";
441 os.unindent();
442 }
443 os << ")";
444}
446 raw_ostream &os, StringRef anchorName,
448 bool pretty) {
449 raw_indented_ostream indentedOS(os);
450 printAsTextualPipeline(indentedOS, anchorName, passes, pretty);
451}
453 StringRef anchorName = getOpAnchorName();
454 raw_indented_ostream indentedOS(os);
456 indentedOS, anchorName,
459 pretty);
460}
461
463 llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes:\n";
464 printAsTextualPipeline(llvm::errs(), /*pretty=*/true);
465 llvm::errs() << "\n";
466}
467
469 DialectRegistry &dialects) {
470 for (const Pass &pass : pm.getPasses())
471 pass.getDependentDialects(dialects);
472}
473
475 registerDialectsForPipeline(*this, dialects);
476}
477
478void OpPassManager::setNesting(Nesting nesting) { impl->nesting = nesting; }
479
481
482LogicalResult OpPassManager::initialize(MLIRContext *context,
483 unsigned newInitGeneration) {
484
485 if (impl->initializationGeneration == newInitGeneration) {
486 LDBG(2) << "Pass manager already initialized "
487 << "' (generation " << newInitGeneration << ") with " << size()
488 << " passes";
489 return success();
490 }
491
492 LDBG(2) << "Initializing pass manager '" << getOpAnchorName()
493 << "' (generation " << newInitGeneration << ") with " << size()
494 << " passes";
495 impl->initializationGeneration = newInitGeneration;
496
497 for (Pass &pass : getPasses()) {
498 // If this pass isn't an adaptor, directly initialize it.
499 auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
500 if (!adaptor) {
501 LDBG(2) << "Initializing pass '" << pass.getName() << "'";
502 if (failed(pass.initialize(context))) {
503 LDBG(2) << "Failed to initialize pass '" << pass.getName() << "'";
504 return failure();
505 }
506 continue;
507 }
508
509 // Otherwise, initialize each of the adaptors pass managers.
510 LDBG(3) << "Initializing adaptor pass with "
511 << adaptor->getPassManagers().size() << " nested managers";
512 for (OpPassManager &adaptorPM : adaptor->getPassManagers())
513 if (failed(adaptorPM.initialize(context, newInitGeneration))) {
514 LDBG(2) << "Failed to initialize nested pass manager";
515 return failure();
516 }
517 }
518
519 LDBG_OS([&](raw_ostream &os) {
520 os << "Pass manager initialization completed successfully: ";
521 printAsTextualPipeline(os, /*pretty=*/false);
522 });
523 return success();
524}
525
526llvm::hash_code OpPassManager::hash() {
527 llvm::hash_code hashCode{};
528 for (Pass &pass : getPasses()) {
529 // If this pass isn't an adaptor, directly hash it.
530 auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
531 if (!adaptor) {
532 hashCode = llvm::hash_combine(hashCode, &pass);
533 continue;
534 }
535 // Otherwise, hash recursively each of the adaptors pass managers.
536 for (OpPassManager &adaptorPM : adaptor->getPassManagers())
537 llvm::hash_combine(hashCode, adaptorPM.hash());
538 }
539 return hashCode;
540}
541
542//===----------------------------------------------------------------------===//
543// OpToOpPassAdaptor
544//===----------------------------------------------------------------------===//
545
546LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op,
547 AnalysisManager am, bool verifyPasses,
548 unsigned parentInitGeneration) {
549 LDBG() << "Running pass '" << pass->getName() << "' on operation '"
550 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "' at "
551 << op->getLoc();
552
553 std::optional<RegisteredOperationName> opInfo = op->getRegisteredInfo();
554 if (!opInfo) {
555 return op->emitOpError()
556 << "trying to schedule a pass on an unregistered operation";
557 }
558 if (!opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
559 return op->emitOpError() << "trying to schedule a pass on an operation not "
560 "marked as 'IsolatedFromAbove'";
561 }
562 if (!pass->canScheduleOn(op)) {
563 return op->emitOpError() << "trying to schedule pass '" << pass->getName()
564 << "' on an unsupported operation";
565 }
566
567 // Initialize the pass state with a callback for the pass to dynamically
568 // execute a pipeline on the currently visited operation.
570 PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
571 pass};
572 auto dynamicPipelineCallback = [&](OpPassManager &pipeline,
573 Operation *root) -> LogicalResult {
574 if (!op->isAncestor(root))
575 return root->emitOpError()
576 << "Trying to schedule a dynamic pipeline on an "
577 "operation that isn't "
578 "nested under the current operation the pass is processing";
579 assert(
580 pipeline.getImpl().canScheduleOn(*op->getContext(), root->getName()));
581
582 // Before running, finalize the passes held by the pipeline.
583 if (failed(pipeline.getImpl().finalizePassList(root->getContext()))) {
584 LDBG() << "Failed to finalize pass list for pipeline";
585 return failure();
586 }
587
588 // Initialize the user provided pipeline and execute the pipeline.
589 if (failed(pipeline.initialize(root->getContext(), parentInitGeneration)))
590 return failure();
591 AnalysisManager nestedAm = root == op ? am : am.nest(root);
592 return OpToOpPassAdaptor::runPipeline(pipeline, root, nestedAm,
593 verifyPasses, parentInitGeneration,
594 pi, &parentInfo);
595 };
596 pass->passState.emplace(op, am, dynamicPipelineCallback);
597
598 // Instrument before the pass has run.
599 if (pi)
600 pi->runBeforePass(pass, op);
601
602 // Pass instrumentation can use pass failure to flag unmet invariants
603 // (preconditions) of the pass. Skip running pass if in failure state.
604 bool passFailed = pass->passState->irAndPassFailed.getInt();
605 if (!passFailed) {
607 [&]() {
608 // Invoke the virtual runOnOperation method.
609 if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass))
610 adaptor->runOnOperation(verifyPasses);
611 else
612 pass->runOnOperation();
613 passFailed = pass->passState->irAndPassFailed.getInt();
614 },
615 {op}, *pass);
616 }
617
618 // Invalidate any non preserved analyses.
619 am.invalidate(pass->passState->preservedAnalyses);
620
621 // When verifyPasses is specified, we run the verifier (unless the pass
622 // failed).
623 if (!passFailed && verifyPasses) {
624 bool runVerifierNow = true;
625
626 // If the pass is an adaptor pass, we don't run the verifier recursively
627 // because the nested operations should have already been verified after
628 // nested passes had run.
629 bool runVerifierRecursively = !isa<OpToOpPassAdaptor>(pass);
630
631 // Reduce compile time by avoiding running the verifier if the pass didn't
632 // change the IR since the last time the verifier was run:
633 //
634 // 1) If the pass said that it preserved all analyses then it can't have
635 // permuted the IR.
636 //
637 // We run these checks in EXPENSIVE_CHECKS mode out of caution.
638#ifndef EXPENSIVE_CHECKS
639 runVerifierNow = !pass->passState->preservedAnalyses.isAll();
640#endif
641 if (runVerifierNow)
642 passFailed = failed(verify(op, runVerifierRecursively));
643 }
644
645 // Instrument after the pass has run.
646 if (pi) {
647 if (passFailed) {
648 pi->runAfterPassFailed(pass, op);
649 } else {
650 pi->runAfterPass(pass, op);
651 passFailed = passFailed || pass->passState->irAndPassFailed.getInt();
652 }
653 }
654
655 // Return if the pass signaled a failure.
656 return failure(passFailed);
657}
658
659/// Run the given operation and analysis manager on a provided op pass manager.
660LogicalResult OpToOpPassAdaptor::runPipeline(
661 OpPassManager &pm, Operation *op, AnalysisManager am, bool verifyPasses,
662 unsigned parentInitGeneration, PassInstrumentor *instrumentor,
663 const PassInstrumentation::PipelineParentInfo *parentInfo) {
664 LDBG_OS([&](raw_ostream &os) {
665 os << "Running pipeline on operation '"
666 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "' with "
667 << pm.size() << " passes, verifyPasses=" << verifyPasses
668 << " pipeline: ";
669 pm.printAsTextualPipeline(os, /*pretty=*/false);
670 });
671 assert((!instrumentor || parentInfo) &&
672 "expected parent info if instrumentor is provided");
673 auto scopeExit = llvm::make_scope_exit([&] {
674 // Clear out any computed operation analyses. These analyses won't be used
675 // any more in this pipeline, and this helps reduce the current working set
676 // of memory. If preserving these analyses becomes important in the future
677 // we can re-evaluate this.
678 am.clear();
679 });
680
681 // Run the pipeline over the provided operation.
682 if (instrumentor) {
683 instrumentor->runBeforePipeline(pm.getOpName(*op->getContext()),
684 *parentInfo);
685 }
686
687 for (Pass &pass : pm.getPasses()) {
688 if (failed(run(&pass, op, am, verifyPasses, parentInitGeneration))) {
689 LDBG() << "Pipeline failed for pass '" << pass.getName()
690 << "' on operation '"
691 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "'";
692 return failure();
693 }
694 }
695
696 if (instrumentor) {
697 instrumentor->runAfterPipeline(pm.getOpName(*op->getContext()),
698 *parentInfo);
699 }
700 return success();
701}
702
703/// Find an operation pass manager with the given anchor name, or nullptr if one
704/// does not exist.
705static OpPassManager *
707 LDBG(3) << "Looking for pass manager with anchor name '" << name << "' among "
708 << mgrs.size() << " managers";
709
710 auto *it = llvm::find_if(
711 mgrs, [&](OpPassManager &mgr) { return mgr.getOpAnchorName() == name; });
712
713 if (it == mgrs.end()) {
714 LDBG(2) << "No pass manager found with anchor name '" << name << "'";
715 return nullptr;
716 }
717
718 LDBG(2) << "Found pass manager with anchor name '" << name << "'";
719 return &*it;
720}
721
722/// Find an operation pass manager that can operate on an operation of the given
723/// type, or nullptr if one does not exist.
725 OperationName name,
726 MLIRContext &context) {
727 LDBG(4) << "Looking for pass manager that can handle operation '" << name
728 << "' among " << mgrs.size() << " managers";
729
730 auto *it = llvm::find_if(mgrs, [&](OpPassManager &mgr) {
731 return mgr.getImpl().canScheduleOn(context, name);
732 });
733
734 if (it == mgrs.end()) {
735 LDBG(4) << "No pass manager found that can handle operation '" << name
736 << "'";
737 return nullptr;
738 }
739
740 LDBG(4) << "Found pass manager '" << it->getOpAnchorName()
741 << "' that can handle operation '" << name << "'";
742 return &*it;
743}
744
746 mgrs.emplace_back(std::move(mgr));
747}
748
750 for (auto &pm : mgrs)
751 pm.getDependentDialects(dialects);
752}
753
756 LDBG(3) << "Attempting to merge pass adaptor with " << mgrs.size()
757 << " managers into rhs with " << rhs.mgrs.size() << " managers";
758
759 // Functor used to check if a pass manager is generic, i.e. op-agnostic.
760 auto isGenericPM = [&](OpPassManager &pm) { return !pm.getOpName(); };
761
762 // Functor used to detect if the given generic pass manager will have a
763 // potential schedule conflict with the given `otherPMs`.
764 auto hasScheduleConflictWith = [&](OpPassManager &genericPM,
766 return llvm::any_of(otherPMs, [&](OpPassManager &pm) {
767 // If this is a non-generic pass manager, a conflict will arise if a
768 // non-generic pass manager's operation name can be scheduled on the
769 // generic passmanager.
770 if (std::optional<OperationName> pmOpName = pm.getOpName(*ctx))
771 return genericPM.getImpl().canScheduleOn(*ctx, *pmOpName);
772 // Otherwise, this is a generic pass manager. We current can't determine
773 // when generic pass managers can be merged, so conservatively assume they
774 // conflict.
775 return true;
776 });
777 };
778
779 // Check that if either adaptor has a generic pass manager, that pm is
780 // compatible within any non-generic pass managers.
781 //
782 // Check the current adaptor.
783 auto *lhsGenericPMIt = llvm::find_if(mgrs, isGenericPM);
784 if (lhsGenericPMIt != mgrs.end()) {
785 LDBG(4) << "Found generic pass manager on LHS, checking for conflicts";
786 if (hasScheduleConflictWith(*lhsGenericPMIt, rhs.mgrs)) {
787 LDBG(4)
788 << "Merge failed: LHS generic pass manager has conflicts with RHS";
789 return failure();
790 }
791 }
792 // Check the rhs adaptor.
793 auto *rhsGenericPMIt = llvm::find_if(rhs.mgrs, isGenericPM);
794 if (rhsGenericPMIt != rhs.mgrs.end()) {
795 LDBG(4) << "Found generic pass manager on RHS, checking for conflicts";
796 if (hasScheduleConflictWith(*rhsGenericPMIt, mgrs)) {
797 LDBG(4)
798 << "Merge failed: RHS generic pass manager has conflicts with LHS";
799 return failure();
800 }
801 }
802
803 for (auto &pm : mgrs) {
804 // If an existing pass manager exists, then merge the given pass manager
805 // into it.
806 if (auto *existingPM =
808 pm.getImpl().mergeInto(existingPM->getImpl());
809 } else {
810 // Otherwise, add the given pass manager to the list.
811 rhs.mgrs.emplace_back(std::move(pm));
812 }
813 }
814 mgrs.clear();
815
816 // After coalescing, sort the pass managers within rhs by name.
817 auto compareFn = [](const OpPassManager &lhs, const OpPassManager &rhs) {
818 // Order op-specific pass managers first and op-agnostic pass managers last.
819 if (std::optional<StringRef> lhsName = lhs.getOpName()) {
820 if (std::optional<StringRef> rhsName = rhs.getOpName())
821 return *lhsName < *rhsName;
822 return true; // lhs(op-specific) < rhs(op-agnostic)
823 }
824 return false; // lhs(op-agnostic) > rhs(op-specific)
825 };
826 llvm::sort(rhs.mgrs, compareFn);
827 return success();
828}
829
830/// Returns the adaptor pass name.
832 std::string name = "Pipeline Collection : [";
833 llvm::raw_string_ostream os(name);
834 llvm::interleaveComma(getPassManagers(), os, [&](OpPassManager &pm) {
835 os << '\'' << pm.getOpAnchorName() << '\'';
836 });
837 os << ']';
838 return name;
839}
840
842 llvm_unreachable(
843 "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor");
844}
845
846/// Run the held pipeline over all nested operations.
847void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) {
848 if (getContext().isMultithreadingEnabled())
849 runOnOperationAsyncImpl(verifyPasses);
850 else
851 runOnOperationImpl(verifyPasses);
852}
853
854/// Run this pass adaptor synchronously.
855void OpToOpPassAdaptor::runOnOperationImpl(bool verifyPasses) {
856 LDBG_OS([&](raw_ostream &os) {
857 os << "Running pass adaptor synchronously on operation '"
858 << OpWithFlags(getOperation(), OpPrintingFlags().skipRegions())
859 << "' with " << mgrs.size()
860 << " pass managers, verifyPasses=" << verifyPasses << " pipeline: ";
861 printAsTextualPipeline(os, /*pretty=*/false);
862 });
863
864 auto am = getAnalysisManager();
865 PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
866 this};
867 auto *instrumentor = am.getPassInstrumentor();
868
869 unsigned processedOps = 0;
870 for (auto &region : getOperation()->getRegions()) {
871 for (auto &block : region) {
872 for (auto &op : block) {
873 auto *mgr = findPassManagerFor(mgrs, op.getName(), *op.getContext());
874 if (!mgr) {
875 LDBG(2) << "Skipping operation '"
876 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
877 << "': no suitable pass manager found";
878 continue;
879 }
880
881 // Run the held pipeline over the current operation.
882 LDBG(2) << "Processing operation '"
883 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
884 << "' with pass manager '" << mgr->getOpAnchorName() << "'";
885
886 unsigned initGeneration = mgr->impl->initializationGeneration;
887 if (failed(runPipeline(*mgr, &op, am.nest(&op), verifyPasses,
888 initGeneration, instrumentor, &parentInfo))) {
889 LDBG(2) << "Pipeline failed for operation '"
890 << OpWithFlags(&op, OpPrintingFlags().skipRegions()) << "'";
891 signalPassFailure();
892 } else {
893 processedOps++;
894 }
895 }
896 }
897 }
898
899 LDBG() << "Completed synchronous pass adaptor run, processed " << processedOps
900 << " operations";
901}
902
903/// Utility functor that checks if the two ranges of pass managers have a size
904/// mismatch.
907 return lhs.size() != rhs.size() ||
908 llvm::any_of(llvm::seq<size_t>(0, lhs.size()),
909 [&](size_t i) { return lhs[i].size() != rhs[i].size(); });
910}
911
912/// Run this pass adaptor synchronously.
913void OpToOpPassAdaptor::runOnOperationAsyncImpl(bool verifyPasses) {
914 LDBG_OS([&](raw_ostream &os) {
915 os << "Running pass adaptor asynchronously on operation '"
916 << OpWithFlags(getOperation(), OpPrintingFlags().skipRegions())
917 << "' with " << mgrs.size()
918 << " pass managers, verifyPasses=" << verifyPasses << " pipeline: ";
919 printAsTextualPipeline(os, /*pretty=*/false);
920 });
921
922 AnalysisManager am = getAnalysisManager();
923 MLIRContext *context = &getContext();
924
925 // Create the async executors if they haven't been created, or if the main
926 // pipeline has changed.
927 if (asyncExecutors.empty() || hasSizeMismatch(asyncExecutors.front(), mgrs)) {
928 LDBG(2) << "Creating " << context->getThreadPool().getMaxConcurrency()
929 << " async executors";
930 asyncExecutors.assign(context->getThreadPool().getMaxConcurrency(), mgrs);
931 }
932
933 // This struct represents the information for a single operation to be
934 // scheduled on a pass manager.
935 struct OpPMInfo {
936 OpPMInfo(unsigned passManagerIdx, Operation *op, AnalysisManager am)
937 : passManagerIdx(passManagerIdx), op(op), am(am) {}
938
939 /// The index of the pass manager to schedule the operation on.
940 unsigned passManagerIdx;
941 /// The operation to schedule.
942 Operation *op;
943 /// The analysis manager for the operation.
944 AnalysisManager am;
945 };
946
947 // Run a prepass over the operation to collect the nested operations to
948 // execute over. This ensures that an analysis manager exists for each
949 // operation, as well as providing a queue of operations to execute over.
950 std::vector<OpPMInfo> opInfos;
952
953 LDBG(2) << "Collecting operations for async execution";
954 for (auto &region : getOperation()->getRegions()) {
955 for (Operation &op : region.getOps()) {
956 // Get the pass manager index for this operation type.
957 auto pmIdxIt = knownOpPMIdx.try_emplace(op.getName(), std::nullopt);
958 if (pmIdxIt.second) {
959 if (auto *mgr = findPassManagerFor(mgrs, op.getName(), *context)) {
960 pmIdxIt.first->second = std::distance(mgrs.begin(), mgr);
961 LDBG(2) << "Operation '"
962 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
963 << "' will use pass manager '" << mgr->getOpAnchorName()
964 << "'";
965 }
966 }
967
968 // If this operation can be scheduled, add it to the list.
969 if (pmIdxIt.first->second) {
970 opInfos.emplace_back(*pmIdxIt.first->second, &op, am.nest(&op));
971 } else {
972 LDBG(2) << "Operation '"
973 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
974 << "' skipped: no suitable pass manager";
975 }
976 }
977 }
978
979 LDBG(2) << "Collected " << opInfos.size()
980 << " operations for async execution";
981
982 // Get the current thread for this adaptor.
983 PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
984 this};
985 auto *instrumentor = am.getPassInstrumentor();
986
987 // An atomic failure variable for the async executors.
988 std::vector<std::atomic<bool>> activePMs(asyncExecutors.size());
989 llvm::fill(activePMs, false);
990 std::atomic<bool> hasFailure = false;
991 parallelForEach(context, opInfos, [&](OpPMInfo &opInfo) {
992 // Find an executor for this operation.
993 auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
994 bool expectedInactive = false;
995 return isActive.compare_exchange_strong(expectedInactive, true);
996 });
997 unsigned pmIndex = it - activePMs.begin();
998
999 // Get the pass manager for this operation and execute it.
1000 OpPassManager &pm = asyncExecutors[pmIndex][opInfo.passManagerIdx];
1001 LogicalResult pipelineResult = runPipeline(
1002 pm, opInfo.op, opInfo.am, verifyPasses,
1003 pm.impl->initializationGeneration, instrumentor, &parentInfo);
1004 if (failed(pipelineResult))
1005 hasFailure.store(true);
1006
1007 // Reset the active bit for this pass manager.
1008 activePMs[pmIndex].store(false);
1009 });
1010
1011 // Signal a failure if any of the executors failed.
1012 if (hasFailure)
1013 signalPassFailure();
1014}
1015
1016//===----------------------------------------------------------------------===//
1017// PassManager
1018//===----------------------------------------------------------------------===//
1019
1020PassManager::PassManager(MLIRContext *ctx, StringRef operationName,
1021 Nesting nesting)
1022 : OpPassManager(operationName, nesting), context(ctx), passTiming(false),
1023 verifyPasses(true) {}
1024
1026 : OpPassManager(operationName, nesting),
1027 context(operationName.getContext()), passTiming(false),
1028 verifyPasses(true) {}
1029
1030PassManager::~PassManager() = default;
1031
1032void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; }
1033
1034/// Run the passes within this manager on the provided operation.
1035LogicalResult PassManager::run(Operation *op) {
1036 LDBG_OS([&](raw_ostream &os) {
1037 os << "Starting PassManager run on operation '"
1038 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "' with "
1039 << size() << " passes, verifyPasses=" << verifyPasses << " pipeline: ";
1040 printAsTextualPipeline(os, /*pretty=*/false);
1041 });
1042
1043 MLIRContext *context = getContext();
1044 std::optional<OperationName> anchorOp = getOpName(*context);
1045 if (anchorOp && anchorOp != op->getName()) {
1046 return emitError(op->getLoc())
1047 << "can't run '" << getOpAnchorName() << "' pass manager on '"
1048 << op->getName() << "' op";
1049 }
1050
1051 // Register all dialects for the current pipeline.
1052 LDBG(2) << "Registering dependent dialects for pipeline";
1053 DialectRegistry dependentDialects;
1054 getDependentDialects(dependentDialects);
1055 context->appendDialectRegistry(dependentDialects);
1056 for (StringRef name : dependentDialects.getDialectNames()) {
1057 LDBG(2) << "Loading dialect: " << name;
1058 context->getOrLoadDialect(name);
1059 }
1060
1061 // Before running, make sure to finalize the pipeline pass list.
1062 if (failed(getImpl().finalizePassList(context))) {
1063 LDBG(2) << "Pass list finalization failed";
1064 return failure();
1065 }
1066
1067 // Notify the context that we start running a pipeline for bookkeeping.
1068 context->enterMultiThreadedExecution();
1069
1070 // Initialize all of the passes within the pass manager with a new generation.
1071 llvm::hash_code newInitKey = context->getRegistryHash();
1072 llvm::hash_code pipelineKey = hash();
1073 if (newInitKey != initializationKey ||
1074 pipelineKey != pipelineInitializationKey) {
1075 LDBG(2) << "Initializing passes with new generation: "
1076 << (impl->initializationGeneration + 1);
1077 if (failed(initialize(context, impl->initializationGeneration + 1))) {
1078 LDBG(2) << "Pass initialization failed";
1079 return failure();
1080 }
1081 initializationKey = newInitKey;
1082 pipelineInitializationKey = pipelineKey;
1083 } else {
1084 LDBG(2) << "Using existing pass initialization (generation: "
1085 << impl->initializationGeneration << ")";
1086 }
1087
1088 // Construct a top level analysis manager for the pipeline.
1089 LDBG(2) << "Constructing analysis manager for pipeline execution";
1090 ModuleAnalysisManager am(op, instrumentor.get());
1091
1092 // If reproducer generation is enabled, run the pass manager with crash
1093 // handling enabled.
1094 LDBG(2) << "Executing pipeline with "
1095 << (crashReproGenerator ? "crash recovery" : "normal execution");
1096 LogicalResult result =
1097 crashReproGenerator ? runWithCrashRecovery(op, am) : runPasses(op, am);
1098
1099 // Notify the context that the run is done.
1100 context->exitMultiThreadedExecution();
1101
1102 // Dump all of the pass statistics if necessary.
1103 if (passStatisticsMode) {
1104 LDBG(2) << "Dumping pass statistics";
1105 dumpStatistics();
1106 }
1107
1108 LDBG(2) << "PassManager run completed with result: "
1109 << (succeeded(result) ? "success" : "failure");
1110 return result;
1111}
1112
1113/// Add the provided instrumentation to the pass manager.
1114void PassManager::addInstrumentation(std::unique_ptr<PassInstrumentation> pi) {
1115 if (!instrumentor)
1116 instrumentor = std::make_unique<PassInstrumentor>();
1117
1118 instrumentor->addInstrumentation(std::move(pi));
1119}
1120
1121LogicalResult PassManager::runPasses(Operation *op, AnalysisManager am) {
1122 LDBG(2) << "Executing passes using OpToOpPassAdaptor pipeline";
1123 return OpToOpPassAdaptor::runPipeline(*this, op, am, verifyPasses,
1124 impl->initializationGeneration);
1125}
1126
1127//===----------------------------------------------------------------------===//
1128// AnalysisManager
1129//===----------------------------------------------------------------------===//
1130
1131/// Get an analysis manager for the given operation, which must be a proper
1132/// descendant of the current operation represented by this analysis manager.
1133AnalysisManager AnalysisManager::nest(Operation *op) {
1134 Operation *currentOp = impl->getOperation();
1135 assert(currentOp->isProperAncestor(op) &&
1136 "expected valid descendant operation");
1137
1138 // Check for the base case where the provided operation is immediately nested.
1139 if (currentOp == op->getParentOp())
1140 return nestImmediate(op);
1141
1142 // Otherwise, we need to collect all ancestors up to the current operation.
1143 SmallVector<Operation *, 4> opAncestors;
1144 do {
1145 opAncestors.push_back(op);
1146 op = op->getParentOp();
1147 } while (op != currentOp);
1148
1149 AnalysisManager result = *this;
1150 for (Operation *op : llvm::reverse(opAncestors))
1151 result = result.nestImmediate(op);
1152 return result;
1153}
1154
1155/// Get an analysis manager for the given immediately nested child operation.
1156AnalysisManager AnalysisManager::nestImmediate(Operation *op) {
1157 assert(impl->getOperation() == op->getParentOp() &&
1158 "expected immediate child operation");
1159
1160 auto [it, inserted] = impl->childAnalyses.try_emplace(op);
1161 if (inserted)
1162 it->second = std::make_unique<NestedAnalysisMap>(op, impl);
1163 return {it->second.get()};
1164}
1165
1166/// Invalidate any non preserved analyses.
1168 const detail::PreservedAnalyses &pa) {
1169 // If all analyses were preserved, then there is nothing to do here.
1170 if (pa.isAll())
1171 return;
1172
1173 // Invalidate the analyses for the current operation directly.
1174 analyses.invalidate(pa);
1175
1176 // If no analyses were preserved, then just simply clear out the child
1177 // analysis results.
1178 if (pa.isNone()) {
1179 childAnalyses.clear();
1180 return;
1181 }
1182
1183 // Otherwise, invalidate each child analysis map.
1184 SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this);
1185 while (!mapsToInvalidate.empty()) {
1186 auto *map = mapsToInvalidate.pop_back_val();
1187 for (auto &analysisPair : map->childAnalyses) {
1188 analysisPair.second->invalidate(pa);
1189 if (!analysisPair.second->childAnalyses.empty())
1190 mapsToInvalidate.push_back(analysisPair.second.get());
1191 }
1192 }
1193}
1194
1195//===----------------------------------------------------------------------===//
1196// PassInstrumentation
1197//===----------------------------------------------------------------------===//
1198
1200
1202 std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1203
1205 std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1206
1210
1211//===----------------------------------------------------------------------===//
1212// PassInstrumentor
1213//===----------------------------------------------------------------------===//
1214
1215namespace mlir {
1216namespace detail {
1218 /// Mutex to keep instrumentation access thread-safe.
1220
1221 /// Set of registered instrumentations.
1222 std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;
1223};
1224} // namespace detail
1225} // namespace mlir
1226
1229
1230/// See PassInstrumentation::runBeforePipeline for details.
1232 std::optional<OperationName> name,
1233 const PassInstrumentation::PipelineParentInfo &parentInfo) {
1234 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1235 for (auto &instr : impl->instrumentations)
1236 instr->runBeforePipeline(name, parentInfo);
1237}
1238
1239/// See PassInstrumentation::runAfterPipeline for details.
1241 std::optional<OperationName> name,
1242 const PassInstrumentation::PipelineParentInfo &parentInfo) {
1243 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1244 for (auto &instr : llvm::reverse(impl->instrumentations))
1245 instr->runAfterPipeline(name, parentInfo);
1246}
1247
1248/// See PassInstrumentation::runBeforePass for details.
1250 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1251 for (auto &instr : impl->instrumentations)
1252 instr->runBeforePass(pass, op);
1253}
1254
1255/// See PassInstrumentation::runAfterPass for details.
1257 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1258 for (auto &instr : llvm::reverse(impl->instrumentations))
1259 instr->runAfterPass(pass, op);
1260}
1261
1262/// See PassInstrumentation::runAfterPassFailed for details.
1264 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1265 for (auto &instr : llvm::reverse(impl->instrumentations))
1266 instr->runAfterPassFailed(pass, op);
1267}
1268
1269/// See PassInstrumentation::runBeforeAnalysis for details.
1271 Operation *op) {
1272 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1273 for (auto &instr : impl->instrumentations)
1274 instr->runBeforeAnalysis(name, id, op);
1275}
1276
1277/// See PassInstrumentation::runAfterAnalysis for details.
1279 Operation *op) {
1280 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1281 for (auto &instr : llvm::reverse(impl->instrumentations))
1282 instr->runAfterAnalysis(name, id, op);
1283}
1284
1285/// Add the given instrumentation to the collection.
1287 std::unique_ptr<PassInstrumentation> pi) {
1288 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1289 impl->instrumentations.emplace_back(std::move(pi));
1290}
return success()
true
Given two iterators into the same block, return "true" if a is before `b.
lhs
b getContext())
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
false
Parses a map_entries map type from a string format back into its numeric value.
static llvm::ManagedStatic< PassManagerOptions > options
void printAsTextualPipeline(raw_indented_ostream &os, StringRef anchorName, const llvm::iterator_range< OpPassManager::pass_iterator > &passes, bool pretty=false)
Prints out the passes of the pass manager as the textual representation of pipelines.
Definition Pass.cpp:422
static void registerDialectsForPipeline(const OpPassManager &pm, DialectRegistry &dialects)
Definition Pass.cpp:468
static bool hasSizeMismatch(ArrayRef< OpPassManager > lhs, ArrayRef< OpPassManager > rhs)
Utility functor that checks if the two ranges of pass managers have a size mismatch.
Definition Pass.cpp:905
static OpPassManager * findPassManagerFor(MutableArrayRef< OpPassManager > mgrs, OperationName name, MLIRContext &context)
Find an operation pass manager that can operate on an operation of the given type,...
Definition Pass.cpp:724
static OpPassManager * findPassManagerWithAnchor(MutableArrayRef< OpPassManager > mgrs, StringRef name)
Find an operation pass manager with the given anchor name, or nullptr if one does not exist.
Definition Pass.cpp:706
#define MLIR_DEFINE_EXPLICIT_TYPE_ID(CLASS_NAME)
Definition TypeID.h:323
This class represents an analysis manager for a particular operation instance.
void clear()
Clear any held analyses.
void invalidate(const PreservedAnalyses &pa)
Invalidate any non preserved analyses,.
AnalysisManager nest(Operation *op)
Get an analysis manager for the given operation, which must be a proper descendant of the current ope...
Definition Pass.cpp:1133
PassInstrumentor * getPassInstrumentor() const
Returns a pass instrumentation object for the current operation.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
auto getDialectNames() const
Return the names of dialects known to this registry.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
void executeAction(function_ref< void()> actionFn, const tracing::Action &action)
Dispatch the provided action to the handler if any, or just execute it.
llvm::ThreadPoolInterface & getThreadPool()
Return the thread pool used by this context.
An analysis manager class specifically for the top-level operation.
This class represents a pass manager that runs passes on either a specific operation type,...
Definition PassManager.h:46
void printAsTextualPipeline(raw_ostream &os, bool pretty=false) const
Prints out the passes of the pass manager as the textual representation of pipelines.
Definition Pass.cpp:452
OpPassManager & operator=(const OpPassManager &rhs)
Definition Pass.cpp:355
friend class PassManager
Allow access to the constructor.
OpPassManager(Nesting nesting=Nesting::Explicit)
Construct a new op-agnostic ("any") pass manager with the given operation type and nesting behavior.
Definition Pass.cpp:347
friend class Pass
std::optional< OperationName > getOpName(MLIRContext &context) const
Return the operation name that this pass manager operates on, or std::nullopt if this is an op-agnost...
Definition Pass.cpp:411
void setNesting(Nesting nesting)
Enable or disable the implicit nesting on this particular PassManager.
Definition Pass.cpp:478
size_t size() const
Returns the number of passes held by this manager.
Definition Pass.cpp:399
detail::OpPassManagerImpl & getImpl()
Returns the internal implementation instance.
Definition Pass.cpp:402
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition Pass.cpp:392
Nesting getNesting()
Return the current nesting mode.
Definition Pass.cpp:480
Nesting
This enum represents the nesting behavior of the pass manager.
Definition PassManager.h:49
@ Implicit
Implicit nesting behavior.
Definition PassManager.h:53
void dump()
Raw dump of the pass manager to llvm::errs().
Definition Pass.cpp:462
llvm::pointee_iterator< MutableArrayRef< std::unique_ptr< Pass > >::iterator > pass_iterator
Iterator over the passes in this pass manager.
Definition PassManager.h:75
void getDependentDialects(DialectRegistry &dialects) const
Register dependent dialects for the current pass manager.
Definition Pass.cpp:474
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
Definition Pass.cpp:415
std::optional< StringRef > getOpName() const
Return the operation name that this pass manager operates on, or std::nullopt if this is an op-agnost...
Definition Pass.cpp:405
iterator_range< pass_iterator > getPasses()
Definition PassManager.h:79
OpPassManager & nestAny()
Nest a new op-agnostic ("any") pass manager under this pass manager.
Definition Pass.cpp:388
OpPassManager & nest()
Definition PassManager.h:97
llvm::pointee_iterator< ArrayRef< std::unique_ptr< Pass > >::const_iterator > const_pass_iterator
Definition PassManager.h:81
static StringRef getAnyOpAnchorName()
Return the string name used to anchor op-agnostic pass managers that operate generically on any viabl...
void clear()
Clear the pipeline, but not the other options set on this OpPassManager.
Definition Pass.cpp:396
pass_iterator begin()
Definition Pass.cpp:366
pass_iterator end()
Definition Pass.cpp:369
Set of flags used to control the behavior of the various IR print methods (e.g.
This class provides the API for ops that are known to be isolated from above.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Definition Operation.h:1111
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:223
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:234
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Definition Operation.h:123
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:119
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
Definition Operation.h:263
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:216
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
This class encapsulates the "action" of executing a single pass.
Definition Pass.h:505
void print(raw_ostream &os) const override
Print a textual version of this action to os.
Definition Pass.cpp:43
PassExecutionAction(ArrayRef< IRUnit > irUnits, const Pass &pass)
Construct a PassExecutionAction.
Definition Pass.cpp:39
Operation * getOp() const
Get the operation that is the base of this pass.
Definition Pass.cpp:48
static constexpr StringLiteral tag
The tag required by ActionImpl to identify this action.
Definition Pass.h:514
const Pass & pass
Reference to the pass being run.
Definition Pass.h:531
virtual void runAfterPipeline(std::optional< OperationName > name, const PipelineParentInfo &parentInfo)
A callback to run after a pass pipeline has executed.
Definition Pass.cpp:1204
void signalPassFailure(Pass *pass)
Helper method to enable analysis to signal pass failure.
Definition Pass.cpp:1207
virtual ~PassInstrumentation()=0
virtual void runBeforePipeline(std::optional< OperationName > name, const PipelineParentInfo &parentInfo)
A callback to run before a pass pipeline is executed.
Definition Pass.cpp:1201
This class holds a collection of PassInstrumentation objects, and invokes their respective call backs...
void runAfterPassFailed(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPassFailed for details.
Definition Pass.cpp:1263
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the given instrumentation to the collection.
Definition Pass.cpp:1286
void runBeforeAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runBeforeAnalysis for details.
Definition Pass.cpp:1270
void runAfterPass(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPass for details.
Definition Pass.cpp:1256
void runAfterAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runAfterAnalysis for details.
Definition Pass.cpp:1278
void runBeforePass(Pass *pass, Operation *op)
See PassInstrumentation::runBeforePass for details.
Definition Pass.cpp:1249
void runBeforePipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runBeforePipeline for details.
Definition Pass.cpp:1231
void runAfterPipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runAfterPipeline for details.
Definition Pass.cpp:1240
MLIRContext * getContext() const
Return an instance of the context.
LogicalResult run(Operation *op)
Run the passes within this manager on the provided operation.
Definition Pass.cpp:1035
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
Definition Pass.cpp:1114
void enableVerifier(bool enabled=true)
Runs the verifier after each individual pass.
Definition Pass.cpp:1032
The abstract base pass class.
Definition Pass.h:52
void copyOptionValuesFrom(const Pass *other)
Copy the option values from 'other', which is another instance of this pass.
Definition Pass.cpp:78
virtual LogicalResult initializeOptions(StringRef options, function_ref< LogicalResult(const Twine &)> errorHandler)
Attempt to initialize the options of this pass from the given string.
Definition Pass.cpp:65
virtual bool canScheduleOn(RegisteredOperationName opName) const =0
Indicate if the current pass can be scheduled on the given operation type.
Pass(TypeID passID, std::optional< StringRef > opName=std::nullopt)
Definition Pass.h:164
void printAsTextualPipeline(raw_ostream &os, bool pretty=false)
Prints out the pass in the textual representation of pipelines.
Definition Pass.cpp:85
virtual void runOnOperation()=0
The polymorphic API that runs the pass over the currently held operation.
friend class OpPassManager
Allow access to 'clone'.
Definition Pass.h:335
virtual StringRef getName() const =0
Returns the derived pass name.
void signalPassFailure()
Signal that some invariant was broken when running.
Definition Pass.h:226
virtual StringRef getArgument() const
Return the command line argument used when registering this pass.
Definition Pass.h:76
This class provides an efficient unique identifier for a specific C++ type.
Definition TypeID.h:107
An adaptor pass used to run operation passes over nested operations.
Definition PassDetail.h:26
void getDependentDialects(DialectRegistry &dialects) const override
Populate the set of dependent dialects for the passes in the current adaptor.
Definition Pass.cpp:749
MutableArrayRef< OpPassManager > getPassManagers()
Returns the pass managers held by this adaptor.
Definition PassDetail.h:47
void runOnOperation() override
The polymorphic API that runs the pass over the currently held operation.
Definition Pass.cpp:841
std::string getAdaptorName()
Returns the adaptor pass name.
Definition Pass.cpp:831
LogicalResult tryMergeInto(MLIRContext *ctx, OpToOpPassAdaptor &rhs)
Try to merge the current pass adaptor into 'rhs'.
Definition Pass.cpp:754
OpToOpPassAdaptor(OpPassManager &&mgr)
Definition Pass.cpp:745
A utility class to represent the analyses that are known to be preserved.
bool isAll() const
Returns true if all analyses were marked preserved.
bool isNone() const
Returns true if no analyses were marked preserved.
raw_ostream subclass that simplifies indention a sequence of code.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
raw_indented_ostream & unindent()
Decreases the indent and returning this raw_indented_ostream.
ArrayRef< IRUnit > irUnits
Set of IR units (operations, regions, blocks, values) that are associated with this action.
Definition Action.h:66
virtual ArrayRef< IRUnit > getContextIRUnits() const
Return the set of IR units that are associated with this action.
Definition Action.h:55
AttrTypeReplacer.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:573
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void parallelForEach(MLIRContext *context, IteratorT begin, IteratorT end, FuncT &&func)
Invoke the given function on the elements between [begin, end) asynchronously.
Definition Threading.h:117
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:126
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition Verifier.cpp:423
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152
This struct represents information related to the parent pass of pipeline.
detail::AnalysisMap analyses
The analyses for the owning operation.
DenseMap< Operation *, std::unique_ptr< NestedAnalysisMap > > childAnalyses
The cached analyses for nested operations.
void invalidate(const PreservedAnalyses &pa)
Invalidate any non preserved analyses.
Definition Pass.cpp:1167
void clear()
Clear the list of passes in this pass manager, other options are preserved.
Definition Pass.cpp:237
OpPassManagerImpl(const OpPassManagerImpl &rhs)
Definition Pass.cpp:124
std::string name
The name of the operation that passes of this pass manager operate on.
Definition Pass.cpp:187
OpPassManager::Nesting nesting
Control the implicit nesting of passes that mismatch the name set for this OpPassManager.
Definition Pass.cpp:202
std::optional< StringRef > getOpName() const
Definition Pass.cpp:170
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition Pass.cpp:220
unsigned initializationGeneration
The current initialization generation of this pass manager.
Definition Pass.cpp:198
OpPassManagerImpl(OperationName opName, OpPassManager::Nesting nesting)
Definition Pass.cpp:116
bool canScheduleOn(MLIRContext &context, OperationName opName)
Indicate if the current pass manager can be scheduled on the given operation type.
Definition Pass.cpp:323
OpPassManagerImpl(OpPassManager::Nesting nesting)
Definition Pass.cpp:122
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
Definition Pass.cpp:178
std::optional< OperationName > getOpName(MLIRContext &context)
Return the operation name of this pass manager.
Definition Pass.cpp:165
OpPassManager & nest(OperationName nestedName)
Nest a new operation pass manager for the given operation kind under this pass manager.
Definition Pass.cpp:140
OpPassManager & nestAny()
Definition Pass.cpp:146
std::vector< std::unique_ptr< Pass > > passes
The set of passes to run as part of this pass manager.
Definition Pass.cpp:194
void mergeInto(OpPassManagerImpl &rhs)
Merge the passes of this pass manager into the one provided.
Definition Pass.cpp:207
LogicalResult finalizePassList(MLIRContext *ctx)
Finalize the pass list in preparation for execution.
Definition Pass.cpp:239
OpPassManager & nest(StringRef nestedName)
Definition Pass.cpp:143
std::optional< OperationName > opName
The cached OperationName (internalized in the context) for the name of the operation that passes of t...
Definition Pass.cpp:191
OpPassManagerImpl(StringRef name, OpPassManager::Nesting nesting)
Definition Pass.cpp:119
std::vector< std::unique_ptr< PassInstrumentation > > instrumentations
Set of registered instrumentations.
Definition Pass.cpp:1222
llvm::sys::SmartMutex< true > mutex
Mutex to keep instrumentation access thread-safe.
Definition Pass.cpp:1219