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->getName().getRegisteredInfo())) {
563 return op->emitOpError()
564 << "trying to schedule a pass 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 bool passFailed = false;
604 [&]() {
605 // Invoke the virtual runOnOperation method.
606 if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass))
607 adaptor->runOnOperation(verifyPasses);
608 else
609 pass->runOnOperation();
610 passFailed = pass->passState->irAndPassFailed.getInt();
611 },
612 {op}, *pass);
613
614 // Invalidate any non preserved analyses.
615 am.invalidate(pass->passState->preservedAnalyses);
616
617 // When verifyPasses is specified, we run the verifier (unless the pass
618 // failed).
619 if (!passFailed && verifyPasses) {
620 bool runVerifierNow = true;
621
622 // If the pass is an adaptor pass, we don't run the verifier recursively
623 // because the nested operations should have already been verified after
624 // nested passes had run.
625 bool runVerifierRecursively = !isa<OpToOpPassAdaptor>(pass);
626
627 // Reduce compile time by avoiding running the verifier if the pass didn't
628 // change the IR since the last time the verifier was run:
629 //
630 // 1) If the pass said that it preserved all analyses then it can't have
631 // permuted the IR.
632 //
633 // We run these checks in EXPENSIVE_CHECKS mode out of caution.
634#ifndef EXPENSIVE_CHECKS
635 runVerifierNow = !pass->passState->preservedAnalyses.isAll();
636#endif
637 if (runVerifierNow)
638 passFailed = failed(verify(op, runVerifierRecursively));
639 }
640
641 // Instrument after the pass has run.
642 if (pi) {
643 if (passFailed)
644 pi->runAfterPassFailed(pass, op);
645 else
646 pi->runAfterPass(pass, op);
647 }
648
649 // Return if the pass signaled a failure.
650 return failure(passFailed);
651}
652
653/// Run the given operation and analysis manager on a provided op pass manager.
654LogicalResult OpToOpPassAdaptor::runPipeline(
655 OpPassManager &pm, Operation *op, AnalysisManager am, bool verifyPasses,
656 unsigned parentInitGeneration, PassInstrumentor *instrumentor,
657 const PassInstrumentation::PipelineParentInfo *parentInfo) {
658 LDBG_OS([&](raw_ostream &os) {
659 os << "Running pipeline on operation '"
660 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "' with "
661 << pm.size() << " passes, verifyPasses=" << verifyPasses
662 << " pipeline: ";
663 pm.printAsTextualPipeline(os, /*pretty=*/false);
664 });
665 assert((!instrumentor || parentInfo) &&
666 "expected parent info if instrumentor is provided");
667 auto scopeExit = llvm::make_scope_exit([&] {
668 // Clear out any computed operation analyses. These analyses won't be used
669 // any more in this pipeline, and this helps reduce the current working set
670 // of memory. If preserving these analyses becomes important in the future
671 // we can re-evaluate this.
672 am.clear();
673 });
674
675 // Run the pipeline over the provided operation.
676 if (instrumentor) {
677 instrumentor->runBeforePipeline(pm.getOpName(*op->getContext()),
678 *parentInfo);
679 }
680
681 for (Pass &pass : pm.getPasses()) {
682 if (failed(run(&pass, op, am, verifyPasses, parentInitGeneration))) {
683 LDBG() << "Pipeline failed for pass '" << pass.getName()
684 << "' on operation '"
685 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "'";
686 return failure();
687 }
688 }
689
690 if (instrumentor) {
691 instrumentor->runAfterPipeline(pm.getOpName(*op->getContext()),
692 *parentInfo);
693 }
694 return success();
695}
696
697/// Find an operation pass manager with the given anchor name, or nullptr if one
698/// does not exist.
699static OpPassManager *
701 LDBG(3) << "Looking for pass manager with anchor name '" << name << "' among "
702 << mgrs.size() << " managers";
703
704 auto *it = llvm::find_if(
705 mgrs, [&](OpPassManager &mgr) { return mgr.getOpAnchorName() == name; });
706
707 if (it == mgrs.end()) {
708 LDBG(2) << "No pass manager found with anchor name '" << name << "'";
709 return nullptr;
710 }
711
712 LDBG(2) << "Found pass manager with anchor name '" << name << "'";
713 return &*it;
714}
715
716/// Find an operation pass manager that can operate on an operation of the given
717/// type, or nullptr if one does not exist.
719 OperationName name,
720 MLIRContext &context) {
721 LDBG(4) << "Looking for pass manager that can handle operation '" << name
722 << "' among " << mgrs.size() << " managers";
723
724 auto *it = llvm::find_if(mgrs, [&](OpPassManager &mgr) {
725 return mgr.getImpl().canScheduleOn(context, name);
726 });
727
728 if (it == mgrs.end()) {
729 LDBG(4) << "No pass manager found that can handle operation '" << name
730 << "'";
731 return nullptr;
732 }
733
734 LDBG(4) << "Found pass manager '" << it->getOpAnchorName()
735 << "' that can handle operation '" << name << "'";
736 return &*it;
737}
738
740 mgrs.emplace_back(std::move(mgr));
741}
742
744 for (auto &pm : mgrs)
745 pm.getDependentDialects(dialects);
746}
747
750 LDBG(3) << "Attempting to merge pass adaptor with " << mgrs.size()
751 << " managers into rhs with " << rhs.mgrs.size() << " managers";
752
753 // Functor used to check if a pass manager is generic, i.e. op-agnostic.
754 auto isGenericPM = [&](OpPassManager &pm) { return !pm.getOpName(); };
755
756 // Functor used to detect if the given generic pass manager will have a
757 // potential schedule conflict with the given `otherPMs`.
758 auto hasScheduleConflictWith = [&](OpPassManager &genericPM,
760 return llvm::any_of(otherPMs, [&](OpPassManager &pm) {
761 // If this is a non-generic pass manager, a conflict will arise if a
762 // non-generic pass manager's operation name can be scheduled on the
763 // generic passmanager.
764 if (std::optional<OperationName> pmOpName = pm.getOpName(*ctx))
765 return genericPM.getImpl().canScheduleOn(*ctx, *pmOpName);
766 // Otherwise, this is a generic pass manager. We current can't determine
767 // when generic pass managers can be merged, so conservatively assume they
768 // conflict.
769 return true;
770 });
771 };
772
773 // Check that if either adaptor has a generic pass manager, that pm is
774 // compatible within any non-generic pass managers.
775 //
776 // Check the current adaptor.
777 auto *lhsGenericPMIt = llvm::find_if(mgrs, isGenericPM);
778 if (lhsGenericPMIt != mgrs.end()) {
779 LDBG(4) << "Found generic pass manager on LHS, checking for conflicts";
780 if (hasScheduleConflictWith(*lhsGenericPMIt, rhs.mgrs)) {
781 LDBG(4)
782 << "Merge failed: LHS generic pass manager has conflicts with RHS";
783 return failure();
784 }
785 }
786 // Check the rhs adaptor.
787 auto *rhsGenericPMIt = llvm::find_if(rhs.mgrs, isGenericPM);
788 if (rhsGenericPMIt != rhs.mgrs.end()) {
789 LDBG(4) << "Found generic pass manager on RHS, checking for conflicts";
790 if (hasScheduleConflictWith(*rhsGenericPMIt, mgrs)) {
791 LDBG(4)
792 << "Merge failed: RHS generic pass manager has conflicts with LHS";
793 return failure();
794 }
795 }
796
797 for (auto &pm : mgrs) {
798 // If an existing pass manager exists, then merge the given pass manager
799 // into it.
800 if (auto *existingPM =
802 pm.getImpl().mergeInto(existingPM->getImpl());
803 } else {
804 // Otherwise, add the given pass manager to the list.
805 rhs.mgrs.emplace_back(std::move(pm));
806 }
807 }
808 mgrs.clear();
809
810 // After coalescing, sort the pass managers within rhs by name.
811 auto compareFn = [](const OpPassManager &lhs, const OpPassManager &rhs) {
812 // Order op-specific pass managers first and op-agnostic pass managers last.
813 if (std::optional<StringRef> lhsName = lhs.getOpName()) {
814 if (std::optional<StringRef> rhsName = rhs.getOpName())
815 return *lhsName < *rhsName;
816 return true; // lhs(op-specific) < rhs(op-agnostic)
817 }
818 return false; // lhs(op-agnostic) > rhs(op-specific)
819 };
820 llvm::sort(rhs.mgrs, compareFn);
821 return success();
822}
823
824/// Returns the adaptor pass name.
826 std::string name = "Pipeline Collection : [";
827 llvm::raw_string_ostream os(name);
828 llvm::interleaveComma(getPassManagers(), os, [&](OpPassManager &pm) {
829 os << '\'' << pm.getOpAnchorName() << '\'';
830 });
831 os << ']';
832 return name;
833}
834
836 llvm_unreachable(
837 "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor");
838}
839
840/// Run the held pipeline over all nested operations.
841void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) {
842 if (getContext().isMultithreadingEnabled())
843 runOnOperationAsyncImpl(verifyPasses);
844 else
845 runOnOperationImpl(verifyPasses);
846}
847
848/// Run this pass adaptor synchronously.
849void OpToOpPassAdaptor::runOnOperationImpl(bool verifyPasses) {
850 LDBG_OS([&](raw_ostream &os) {
851 os << "Running pass adaptor synchronously on operation '"
852 << OpWithFlags(getOperation(), OpPrintingFlags().skipRegions())
853 << "' with " << mgrs.size()
854 << " pass managers, verifyPasses=" << verifyPasses << " pipeline: ";
855 printAsTextualPipeline(os, /*pretty=*/false);
856 });
857
858 auto am = getAnalysisManager();
859 PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
860 this};
861 auto *instrumentor = am.getPassInstrumentor();
862
863 unsigned processedOps = 0;
864 for (auto &region : getOperation()->getRegions()) {
865 for (auto &block : region) {
866 for (auto &op : block) {
867 auto *mgr = findPassManagerFor(mgrs, op.getName(), *op.getContext());
868 if (!mgr) {
869 LDBG(2) << "Skipping operation '"
870 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
871 << "': no suitable pass manager found";
872 continue;
873 }
874
875 // Run the held pipeline over the current operation.
876 LDBG(2) << "Processing operation '"
877 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
878 << "' with pass manager '" << mgr->getOpAnchorName() << "'";
879
880 unsigned initGeneration = mgr->impl->initializationGeneration;
881 if (failed(runPipeline(*mgr, &op, am.nest(&op), verifyPasses,
882 initGeneration, instrumentor, &parentInfo))) {
883 LDBG(2) << "Pipeline failed for operation '"
884 << OpWithFlags(&op, OpPrintingFlags().skipRegions()) << "'";
885 signalPassFailure();
886 } else {
887 processedOps++;
888 }
889 }
890 }
891 }
892
893 LDBG() << "Completed synchronous pass adaptor run, processed " << processedOps
894 << " operations";
895}
896
897/// Utility functor that checks if the two ranges of pass managers have a size
898/// mismatch.
901 return lhs.size() != rhs.size() ||
902 llvm::any_of(llvm::seq<size_t>(0, lhs.size()),
903 [&](size_t i) { return lhs[i].size() != rhs[i].size(); });
904}
905
906/// Run this pass adaptor synchronously.
907void OpToOpPassAdaptor::runOnOperationAsyncImpl(bool verifyPasses) {
908 LDBG_OS([&](raw_ostream &os) {
909 os << "Running pass adaptor asynchronously on operation '"
910 << OpWithFlags(getOperation(), OpPrintingFlags().skipRegions())
911 << "' with " << mgrs.size()
912 << " pass managers, verifyPasses=" << verifyPasses << " pipeline: ";
913 printAsTextualPipeline(os, /*pretty=*/false);
914 });
915
916 AnalysisManager am = getAnalysisManager();
917 MLIRContext *context = &getContext();
918
919 // Create the async executors if they haven't been created, or if the main
920 // pipeline has changed.
921 if (asyncExecutors.empty() || hasSizeMismatch(asyncExecutors.front(), mgrs)) {
922 LDBG(2) << "Creating " << context->getThreadPool().getMaxConcurrency()
923 << " async executors";
924 asyncExecutors.assign(context->getThreadPool().getMaxConcurrency(), mgrs);
925 }
926
927 // This struct represents the information for a single operation to be
928 // scheduled on a pass manager.
929 struct OpPMInfo {
930 OpPMInfo(unsigned passManagerIdx, Operation *op, AnalysisManager am)
931 : passManagerIdx(passManagerIdx), op(op), am(am) {}
932
933 /// The index of the pass manager to schedule the operation on.
934 unsigned passManagerIdx;
935 /// The operation to schedule.
936 Operation *op;
937 /// The analysis manager for the operation.
938 AnalysisManager am;
939 };
940
941 // Run a prepass over the operation to collect the nested operations to
942 // execute over. This ensures that an analysis manager exists for each
943 // operation, as well as providing a queue of operations to execute over.
944 std::vector<OpPMInfo> opInfos;
946
947 LDBG(2) << "Collecting operations for async execution";
948 for (auto &region : getOperation()->getRegions()) {
949 for (Operation &op : region.getOps()) {
950 // Get the pass manager index for this operation type.
951 auto pmIdxIt = knownOpPMIdx.try_emplace(op.getName(), std::nullopt);
952 if (pmIdxIt.second) {
953 if (auto *mgr = findPassManagerFor(mgrs, op.getName(), *context)) {
954 pmIdxIt.first->second = std::distance(mgrs.begin(), mgr);
955 LDBG(2) << "Operation '"
956 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
957 << "' will use pass manager '" << mgr->getOpAnchorName()
958 << "'";
959 }
960 }
961
962 // If this operation can be scheduled, add it to the list.
963 if (pmIdxIt.first->second) {
964 opInfos.emplace_back(*pmIdxIt.first->second, &op, am.nest(&op));
965 } else {
966 LDBG(2) << "Operation '"
967 << OpWithFlags(&op, OpPrintingFlags().skipRegions())
968 << "' skipped: no suitable pass manager";
969 }
970 }
971 }
972
973 LDBG(2) << "Collected " << opInfos.size()
974 << " operations for async execution";
975
976 // Get the current thread for this adaptor.
977 PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
978 this};
979 auto *instrumentor = am.getPassInstrumentor();
980
981 // An atomic failure variable for the async executors.
982 std::vector<std::atomic<bool>> activePMs(asyncExecutors.size());
983 llvm::fill(activePMs, false);
984 std::atomic<bool> hasFailure = false;
985 parallelForEach(context, opInfos, [&](OpPMInfo &opInfo) {
986 // Find an executor for this operation.
987 auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
988 bool expectedInactive = false;
989 return isActive.compare_exchange_strong(expectedInactive, true);
990 });
991 unsigned pmIndex = it - activePMs.begin();
992
993 // Get the pass manager for this operation and execute it.
994 OpPassManager &pm = asyncExecutors[pmIndex][opInfo.passManagerIdx];
995 LogicalResult pipelineResult = runPipeline(
996 pm, opInfo.op, opInfo.am, verifyPasses,
997 pm.impl->initializationGeneration, instrumentor, &parentInfo);
998 if (failed(pipelineResult))
999 hasFailure.store(true);
1000
1001 // Reset the active bit for this pass manager.
1002 activePMs[pmIndex].store(false);
1003 });
1004
1005 // Signal a failure if any of the executors failed.
1006 if (hasFailure)
1007 signalPassFailure();
1008}
1009
1010//===----------------------------------------------------------------------===//
1011// PassManager
1012//===----------------------------------------------------------------------===//
1013
1014PassManager::PassManager(MLIRContext *ctx, StringRef operationName,
1015 Nesting nesting)
1016 : OpPassManager(operationName, nesting), context(ctx), passTiming(false),
1017 verifyPasses(true) {}
1018
1020 : OpPassManager(operationName, nesting),
1021 context(operationName.getContext()), passTiming(false),
1022 verifyPasses(true) {}
1023
1024PassManager::~PassManager() = default;
1025
1026void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; }
1027
1028/// Run the passes within this manager on the provided operation.
1029LogicalResult PassManager::run(Operation *op) {
1030 LDBG_OS([&](raw_ostream &os) {
1031 os << "Starting PassManager run on operation '"
1032 << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "' with "
1033 << size() << " passes, verifyPasses=" << verifyPasses << " pipeline: ";
1034 printAsTextualPipeline(os, /*pretty=*/false);
1035 });
1036
1037 MLIRContext *context = getContext();
1038 std::optional<OperationName> anchorOp = getOpName(*context);
1039 if (anchorOp && anchorOp != op->getName()) {
1040 return emitError(op->getLoc())
1041 << "can't run '" << getOpAnchorName() << "' pass manager on '"
1042 << op->getName() << "' op";
1043 }
1044
1045 // Register all dialects for the current pipeline.
1046 LDBG(2) << "Registering dependent dialects for pipeline";
1047 DialectRegistry dependentDialects;
1048 getDependentDialects(dependentDialects);
1049 context->appendDialectRegistry(dependentDialects);
1050 for (StringRef name : dependentDialects.getDialectNames()) {
1051 LDBG(2) << "Loading dialect: " << name;
1052 context->getOrLoadDialect(name);
1053 }
1054
1055 // Before running, make sure to finalize the pipeline pass list.
1056 if (failed(getImpl().finalizePassList(context))) {
1057 LDBG(2) << "Pass list finalization failed";
1058 return failure();
1059 }
1060
1061 // Notify the context that we start running a pipeline for bookkeeping.
1062 context->enterMultiThreadedExecution();
1063
1064 // Initialize all of the passes within the pass manager with a new generation.
1065 llvm::hash_code newInitKey = context->getRegistryHash();
1066 llvm::hash_code pipelineKey = hash();
1067 if (newInitKey != initializationKey ||
1068 pipelineKey != pipelineInitializationKey) {
1069 LDBG(2) << "Initializing passes with new generation: "
1070 << (impl->initializationGeneration + 1);
1071 if (failed(initialize(context, impl->initializationGeneration + 1))) {
1072 LDBG(2) << "Pass initialization failed";
1073 return failure();
1074 }
1075 initializationKey = newInitKey;
1076 pipelineInitializationKey = pipelineKey;
1077 } else {
1078 LDBG(2) << "Using existing pass initialization (generation: "
1079 << impl->initializationGeneration << ")";
1080 }
1081
1082 // Construct a top level analysis manager for the pipeline.
1083 LDBG(2) << "Constructing analysis manager for pipeline execution";
1084 ModuleAnalysisManager am(op, instrumentor.get());
1085
1086 // If reproducer generation is enabled, run the pass manager with crash
1087 // handling enabled.
1088 LDBG(2) << "Executing pipeline with "
1089 << (crashReproGenerator ? "crash recovery" : "normal execution");
1090 LogicalResult result =
1091 crashReproGenerator ? runWithCrashRecovery(op, am) : runPasses(op, am);
1092
1093 // Notify the context that the run is done.
1094 context->exitMultiThreadedExecution();
1095
1096 // Dump all of the pass statistics if necessary.
1097 if (passStatisticsMode) {
1098 LDBG(2) << "Dumping pass statistics";
1099 dumpStatistics();
1100 }
1101
1102 LDBG(2) << "PassManager run completed with result: "
1103 << (succeeded(result) ? "success" : "failure");
1104 return result;
1105}
1106
1107/// Add the provided instrumentation to the pass manager.
1108void PassManager::addInstrumentation(std::unique_ptr<PassInstrumentation> pi) {
1109 if (!instrumentor)
1110 instrumentor = std::make_unique<PassInstrumentor>();
1111
1112 instrumentor->addInstrumentation(std::move(pi));
1113}
1114
1115LogicalResult PassManager::runPasses(Operation *op, AnalysisManager am) {
1116 LDBG(2) << "Executing passes using OpToOpPassAdaptor pipeline";
1117 return OpToOpPassAdaptor::runPipeline(*this, op, am, verifyPasses,
1118 impl->initializationGeneration);
1119}
1120
1121//===----------------------------------------------------------------------===//
1122// AnalysisManager
1123//===----------------------------------------------------------------------===//
1124
1125/// Get an analysis manager for the given operation, which must be a proper
1126/// descendant of the current operation represented by this analysis manager.
1127AnalysisManager AnalysisManager::nest(Operation *op) {
1128 Operation *currentOp = impl->getOperation();
1129 assert(currentOp->isProperAncestor(op) &&
1130 "expected valid descendant operation");
1131
1132 // Check for the base case where the provided operation is immediately nested.
1133 if (currentOp == op->getParentOp())
1134 return nestImmediate(op);
1135
1136 // Otherwise, we need to collect all ancestors up to the current operation.
1137 SmallVector<Operation *, 4> opAncestors;
1138 do {
1139 opAncestors.push_back(op);
1140 op = op->getParentOp();
1141 } while (op != currentOp);
1142
1143 AnalysisManager result = *this;
1144 for (Operation *op : llvm::reverse(opAncestors))
1145 result = result.nestImmediate(op);
1146 return result;
1147}
1148
1149/// Get an analysis manager for the given immediately nested child operation.
1150AnalysisManager AnalysisManager::nestImmediate(Operation *op) {
1151 assert(impl->getOperation() == op->getParentOp() &&
1152 "expected immediate child operation");
1153
1154 auto [it, inserted] = impl->childAnalyses.try_emplace(op);
1155 if (inserted)
1156 it->second = std::make_unique<NestedAnalysisMap>(op, impl);
1157 return {it->second.get()};
1158}
1159
1160/// Invalidate any non preserved analyses.
1162 const detail::PreservedAnalyses &pa) {
1163 // If all analyses were preserved, then there is nothing to do here.
1164 if (pa.isAll())
1165 return;
1166
1167 // Invalidate the analyses for the current operation directly.
1168 analyses.invalidate(pa);
1169
1170 // If no analyses were preserved, then just simply clear out the child
1171 // analysis results.
1172 if (pa.isNone()) {
1173 childAnalyses.clear();
1174 return;
1175 }
1176
1177 // Otherwise, invalidate each child analysis map.
1178 SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this);
1179 while (!mapsToInvalidate.empty()) {
1180 auto *map = mapsToInvalidate.pop_back_val();
1181 for (auto &analysisPair : map->childAnalyses) {
1182 analysisPair.second->invalidate(pa);
1183 if (!analysisPair.second->childAnalyses.empty())
1184 mapsToInvalidate.push_back(analysisPair.second.get());
1185 }
1186 }
1187}
1188
1189//===----------------------------------------------------------------------===//
1190// PassInstrumentation
1191//===----------------------------------------------------------------------===//
1192
1194
1196 std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1197
1199 std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1200
1201//===----------------------------------------------------------------------===//
1202// PassInstrumentor
1203//===----------------------------------------------------------------------===//
1204
1205namespace mlir {
1206namespace detail {
1208 /// Mutex to keep instrumentation access thread-safe.
1210
1211 /// Set of registered instrumentations.
1212 std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;
1213};
1214} // namespace detail
1215} // namespace mlir
1216
1219
1220/// See PassInstrumentation::runBeforePipeline for details.
1222 std::optional<OperationName> name,
1223 const PassInstrumentation::PipelineParentInfo &parentInfo) {
1224 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1225 for (auto &instr : impl->instrumentations)
1226 instr->runBeforePipeline(name, parentInfo);
1227}
1228
1229/// See PassInstrumentation::runAfterPipeline for details.
1231 std::optional<OperationName> name,
1232 const PassInstrumentation::PipelineParentInfo &parentInfo) {
1233 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1234 for (auto &instr : llvm::reverse(impl->instrumentations))
1235 instr->runAfterPipeline(name, parentInfo);
1236}
1237
1238/// See PassInstrumentation::runBeforePass for details.
1240 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1241 for (auto &instr : impl->instrumentations)
1242 instr->runBeforePass(pass, op);
1243}
1244
1245/// See PassInstrumentation::runAfterPass for details.
1247 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1248 for (auto &instr : llvm::reverse(impl->instrumentations))
1249 instr->runAfterPass(pass, op);
1250}
1251
1252/// See PassInstrumentation::runAfterPassFailed for details.
1254 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1255 for (auto &instr : llvm::reverse(impl->instrumentations))
1256 instr->runAfterPassFailed(pass, op);
1257}
1258
1259/// See PassInstrumentation::runBeforeAnalysis for details.
1261 Operation *op) {
1262 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1263 for (auto &instr : impl->instrumentations)
1264 instr->runBeforeAnalysis(name, id, op);
1265}
1266
1267/// See PassInstrumentation::runAfterAnalysis for details.
1269 Operation *op) {
1270 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1271 for (auto &instr : llvm::reverse(impl->instrumentations))
1272 instr->runAfterAnalysis(name, id, op);
1273}
1274
1275/// Add the given instrumentation to the collection.
1277 std::unique_ptr<PassInstrumentation> pi) {
1278 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1279 impl->instrumentations.emplace_back(std::move(pi));
1280}
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:899
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:718
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:700
#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:1127
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
std::optional< RegisteredOperationName > getRegisteredInfo() const
If this operation is registered, returns the registered information, std::nullopt otherwise.
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:493
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:502
const Pass & pass
Reference to the pass being run.
Definition Pass.h:519
virtual void runAfterPipeline(std::optional< OperationName > name, const PipelineParentInfo &parentInfo)
A callback to run after a pass pipeline has executed.
Definition Pass.cpp:1198
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:1195
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:1253
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the given instrumentation to the collection.
Definition Pass.cpp:1276
void runBeforeAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runBeforeAnalysis for details.
Definition Pass.cpp:1260
void runAfterPass(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPass for details.
Definition Pass.cpp:1246
void runAfterAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runAfterAnalysis for details.
Definition Pass.cpp:1268
void runBeforePass(Pass *pass, Operation *op)
See PassInstrumentation::runBeforePass for details.
Definition Pass.cpp:1239
void runBeforePipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runBeforePipeline for details.
Definition Pass.cpp:1221
void runAfterPipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runAfterPipeline for details.
Definition Pass.cpp:1230
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:1029
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
Definition Pass.cpp:1108
void enableVerifier(bool enabled=true)
Runs the verifier after each individual pass.
Definition Pass.cpp:1026
The abstract base pass class.
Definition Pass.h:51
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:163
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:327
virtual StringRef getName() const =0
Returns the derived pass name.
virtual StringRef getArgument() const
Return the command line argument used when registering this pass.
Definition Pass.h:75
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:743
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:835
std::string getAdaptorName()
Returns the adaptor pass name.
Definition Pass.cpp:825
LogicalResult tryMergeInto(MLIRContext *ctx, OpToOpPassAdaptor &rhs)
Try to merge the current pass adaptor into 'rhs'.
Definition Pass.cpp:748
OpToOpPassAdaptor(OpPassManager &&mgr)
Definition Pass.cpp:739
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:561
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:1161
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:1212
llvm::sys::SmartMutex< true > mutex
Mutex to keep instrumentation access thread-safe.
Definition Pass.cpp:1209