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