MLIR  21.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"
16 #include "mlir/IR/Dialect.h"
17 #include "mlir/IR/OpDefinition.h"
18 #include "mlir/IR/Threading.h"
19 #include "mlir/IR/Verifier.h"
22 #include "llvm/ADT/Hashing.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/ADT/ScopeExit.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/CrashRecoveryContext.h"
27 #include "llvm/Support/Mutex.h"
28 #include "llvm/Support/Signals.h"
29 #include "llvm/Support/Threading.h"
30 #include "llvm/Support/ToolOutputFile.h"
31 #include <optional>
32 
33 using namespace mlir;
34 using namespace mlir::detail;
35 
36 //===----------------------------------------------------------------------===//
37 // PassExecutionAction
38 //===----------------------------------------------------------------------===//
39 
41  const Pass &pass)
42  : Base(irUnits), pass(pass) {}
43 
44 void PassExecutionAction::print(raw_ostream &os) const {
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.
63 void 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.
79 void 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.
86 void Pass::printAsTextualPipeline(raw_ostream &os, bool pretty) {
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 
114 namespace mlir {
115 namespace detail {
118  : name(opName.getStringRef().str()), opName(opName),
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.
150  OpPassManager &nest(OpPassManager &&nested);
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 
215 OpPassManager &OpPassManagerImpl::nest(OpPassManager &&nested) {
216  auto *adaptor = new OpToOpPassAdaptor(std::move(nested));
217  addPass(std::unique_ptr<Pass>(adaptor));
218  return adaptor->getPassManagers().front();
219 }
220 
221 void 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) {
227  if (nesting == OpPassManager::Nesting::Implicit)
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 
238 void OpPassManagerImpl::clear() { passes.clear(); }
239 
240 LogicalResult OpPassManagerImpl::finalizePassList(MLIRContext *ctx) {
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  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  lastAdaptor = currentAdaptor;
257  continue;
258  }
259 
260  // Otherwise, try to merge into the existing adaptor and delete the
261  // current one. If merging fails, just remember this as the last adaptor.
262  if (succeeded(currentAdaptor->tryMergeInto(ctx, *lastAdaptor)))
263  pass.reset();
264  else
265  lastAdaptor = currentAdaptor;
266  } else if (lastAdaptor) {
267  // If this pass isn't an adaptor, finalize it and forget the last adaptor.
268  if (failed(finalizeAdaptor(lastAdaptor)))
269  return failure();
270  lastAdaptor = nullptr;
271  }
272  }
273 
274  // If there was an adaptor at the end of the manager, finalize it as well.
275  if (lastAdaptor && failed(finalizeAdaptor(lastAdaptor)))
276  return failure();
277 
278  // Now that the adaptors have been merged, erase any empty slots corresponding
279  // to the merged adaptors that were nulled-out in the loop above.
280  llvm::erase_if(passes, std::logical_not<std::unique_ptr<Pass>>());
281 
282  // If this is a op-agnostic pass manager, there is nothing left to do.
283  std::optional<OperationName> rawOpName = getOpName(*ctx);
284  if (!rawOpName)
285  return success();
286 
287  // Otherwise, verify that all of the passes are valid for the current
288  // operation anchor.
289  std::optional<RegisteredOperationName> opName =
290  rawOpName->getRegisteredInfo();
291  for (std::unique_ptr<Pass> &pass : passes) {
292  if (opName && !pass->canScheduleOn(*opName)) {
293  return emitError(UnknownLoc::get(ctx))
294  << "unable to schedule pass '" << pass->getName()
295  << "' on a PassManager intended to run on '" << getOpAnchorName()
296  << "'!";
297  }
298  }
299  return success();
300 }
301 
302 bool OpPassManagerImpl::canScheduleOn(MLIRContext &context,
303  OperationName opName) {
304  // If this pass manager is op-specific, we simply check if the provided
305  // operation name is the same as this one.
306  std::optional<OperationName> pmOpName = getOpName(context);
307  if (pmOpName)
308  return pmOpName == opName;
309 
310  // Otherwise, this is an op-agnostic pass manager. Check that the operation
311  // can be scheduled on all passes within the manager.
312  std::optional<RegisteredOperationName> registeredInfo =
313  opName.getRegisteredInfo();
314  if (!registeredInfo ||
315  !registeredInfo->hasTrait<OpTrait::IsIsolatedFromAbove>())
316  return false;
317  return llvm::all_of(passes, [&](const std::unique_ptr<Pass> &pass) {
318  return pass->canScheduleOn(*registeredInfo);
319  });
320 }
321 
322 //===----------------------------------------------------------------------===//
323 // OpPassManager
324 //===----------------------------------------------------------------------===//
325 
327  : impl(new OpPassManagerImpl(nesting)) {}
328 OpPassManager::OpPassManager(StringRef name, Nesting nesting)
329  : impl(new OpPassManagerImpl(name, nesting)) {}
331  : impl(new OpPassManagerImpl(name, nesting)) {}
332 OpPassManager::OpPassManager(OpPassManager &&rhs) { *this = std::move(rhs); }
333 OpPassManager::OpPassManager(const OpPassManager &rhs) { *this = rhs; }
335  impl = std::make_unique<OpPassManagerImpl>(*rhs.impl);
336  return *this;
337 }
339  impl = std::move(rhs.impl);
340  return *this;
341 }
342 
344 
346  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();
347 }
349  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();
350 }
351 
353  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();
354 }
356  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();
357 }
358 
359 /// Nest a new operation pass manager for the given operation kind under this
360 /// pass manager.
362  return impl->nest(nestedName);
363 }
364 OpPassManager &OpPassManager::nest(StringRef nestedName) {
365  return impl->nest(nestedName);
366 }
367 OpPassManager &OpPassManager::nestAny() { return impl->nestAny(); }
368 
369 /// Add the given pass to this pass manager. If this pass has a concrete
370 /// operation type, it must be the same type as this pass manager.
371 void OpPassManager::addPass(std::unique_ptr<Pass> pass) {
372  impl->addPass(std::move(pass));
373 }
374 
375 void OpPassManager::clear() { impl->clear(); }
376 
377 /// Returns the number of passes held by this manager.
378 size_t OpPassManager::size() const { return impl->passes.size(); }
379 
380 /// Returns the internal implementation instance.
382 
383 /// Return the operation name that this pass manager operates on.
384 std::optional<StringRef> OpPassManager::getOpName() const {
385  return impl->getOpName();
386 }
387 
388 /// Return the operation name that this pass manager operates on.
389 std::optional<OperationName>
391  return impl->getOpName(context);
392 }
393 
395  return impl->getOpAnchorName();
396 }
397 
398 /// Prints out the passes of the pass manager as the textual representation
399 /// of pipelines. When `pretty` is true, the printed pipeline is formatted for
400 /// readability.
402  raw_indented_ostream &os, StringRef anchorName,
404  bool pretty = false) {
405  os << anchorName << "(";
406  if (pretty) {
407  os << "\n";
408  os.indent();
409  }
410  llvm::interleave(
411  passes,
412  [&](mlir::Pass &pass) { pass.printAsTextualPipeline(os, pretty); },
413  [&]() {
414  os << ",";
415  if (pretty)
416  os << "\n";
417  });
418  if (pretty) {
419  os << "\n";
420  os.unindent();
421  }
422  os << ")";
423 }
425  raw_ostream &os, StringRef anchorName,
427  bool pretty) {
428  raw_indented_ostream indentedOS(os);
429  printAsTextualPipeline(indentedOS, anchorName, passes, pretty);
430 }
431 void OpPassManager::printAsTextualPipeline(raw_ostream &os, bool pretty) const {
432  StringRef anchorName = getOpAnchorName();
433  raw_indented_ostream indentedOS(os);
435  indentedOS, anchorName,
436  {MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin(),
437  MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end()},
438  pretty);
439 }
440 
442  llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes:\n";
443  printAsTextualPipeline(llvm::errs(), /*pretty=*/true);
444  llvm::errs() << "\n";
445 }
446 
448  DialectRegistry &dialects) {
449  for (const Pass &pass : pm.getPasses())
450  pass.getDependentDialects(dialects);
451 }
452 
454  registerDialectsForPipeline(*this, dialects);
455 }
456 
457 void OpPassManager::setNesting(Nesting nesting) { impl->nesting = nesting; }
458 
460 
461 LogicalResult OpPassManager::initialize(MLIRContext *context,
462  unsigned newInitGeneration) {
463  if (impl->initializationGeneration == newInitGeneration)
464  return success();
465  impl->initializationGeneration = newInitGeneration;
466  for (Pass &pass : getPasses()) {
467  // If this pass isn't an adaptor, directly initialize it.
468  auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
469  if (!adaptor) {
470  if (failed(pass.initialize(context)))
471  return failure();
472  continue;
473  }
474 
475  // Otherwise, initialize each of the adaptors pass managers.
476  for (OpPassManager &adaptorPM : adaptor->getPassManagers())
477  if (failed(adaptorPM.initialize(context, newInitGeneration)))
478  return failure();
479  }
480  return success();
481 }
482 
483 llvm::hash_code OpPassManager::hash() {
484  llvm::hash_code hashCode{};
485  for (Pass &pass : getPasses()) {
486  // If this pass isn't an adaptor, directly hash it.
487  auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
488  if (!adaptor) {
489  hashCode = llvm::hash_combine(hashCode, &pass);
490  continue;
491  }
492  // Otherwise, hash recursively each of the adaptors pass managers.
493  for (OpPassManager &adaptorPM : adaptor->getPassManagers())
494  llvm::hash_combine(hashCode, adaptorPM.hash());
495  }
496  return hashCode;
497 }
498 
499 //===----------------------------------------------------------------------===//
500 // OpToOpPassAdaptor
501 //===----------------------------------------------------------------------===//
502 
503 LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op,
504  AnalysisManager am, bool verifyPasses,
505  unsigned parentInitGeneration) {
506  std::optional<RegisteredOperationName> opInfo = op->getRegisteredInfo();
507  if (!opInfo)
508  return op->emitOpError()
509  << "trying to schedule a pass on an unregistered operation";
510  if (!opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>())
511  return op->emitOpError() << "trying to schedule a pass on an operation not "
512  "marked as 'IsolatedFromAbove'";
513  if (!pass->canScheduleOn(*op->getName().getRegisteredInfo()))
514  return op->emitOpError()
515  << "trying to schedule a pass on an unsupported operation";
516 
517  // Initialize the pass state with a callback for the pass to dynamically
518  // execute a pipeline on the currently visited operation.
520  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
521  pass};
522  auto dynamicPipelineCallback = [&](OpPassManager &pipeline,
523  Operation *root) -> LogicalResult {
524  if (!op->isAncestor(root))
525  return root->emitOpError()
526  << "Trying to schedule a dynamic pipeline on an "
527  "operation that isn't "
528  "nested under the current operation the pass is processing";
529  assert(
530  pipeline.getImpl().canScheduleOn(*op->getContext(), root->getName()));
531 
532  // Before running, finalize the passes held by the pipeline.
533  if (failed(pipeline.getImpl().finalizePassList(root->getContext())))
534  return failure();
535 
536  // Initialize the user provided pipeline and execute the pipeline.
537  if (failed(pipeline.initialize(root->getContext(), parentInitGeneration)))
538  return failure();
539  AnalysisManager nestedAm = root == op ? am : am.nest(root);
540  return OpToOpPassAdaptor::runPipeline(pipeline, root, nestedAm,
541  verifyPasses, parentInitGeneration,
542  pi, &parentInfo);
543  };
544  pass->passState.emplace(op, am, dynamicPipelineCallback);
545 
546  // Instrument before the pass has run.
547  if (pi)
548  pi->runBeforePass(pass, op);
549 
550  bool passFailed = false;
552  [&]() {
553  // Invoke the virtual runOnOperation method.
554  if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass))
555  adaptor->runOnOperation(verifyPasses);
556  else
557  pass->runOnOperation();
558  passFailed = pass->passState->irAndPassFailed.getInt();
559  },
560  {op}, *pass);
561 
562  // Invalidate any non preserved analyses.
563  am.invalidate(pass->passState->preservedAnalyses);
564 
565  // When verifyPasses is specified, we run the verifier (unless the pass
566  // failed).
567  if (!passFailed && verifyPasses) {
568  bool runVerifierNow = true;
569 
570  // If the pass is an adaptor pass, we don't run the verifier recursively
571  // because the nested operations should have already been verified after
572  // nested passes had run.
573  bool runVerifierRecursively = !isa<OpToOpPassAdaptor>(pass);
574 
575  // Reduce compile time by avoiding running the verifier if the pass didn't
576  // change the IR since the last time the verifier was run:
577  //
578  // 1) If the pass said that it preserved all analyses then it can't have
579  // permuted the IR.
580  //
581  // We run these checks in EXPENSIVE_CHECKS mode out of caution.
582 #ifndef EXPENSIVE_CHECKS
583  runVerifierNow = !pass->passState->preservedAnalyses.isAll();
584 #endif
585  if (runVerifierNow)
586  passFailed = failed(verify(op, runVerifierRecursively));
587  }
588 
589  // Instrument after the pass has run.
590  if (pi) {
591  if (passFailed)
592  pi->runAfterPassFailed(pass, op);
593  else
594  pi->runAfterPass(pass, op);
595  }
596 
597  // Return if the pass signaled a failure.
598  return failure(passFailed);
599 }
600 
601 /// Run the given operation and analysis manager on a provided op pass manager.
602 LogicalResult OpToOpPassAdaptor::runPipeline(
603  OpPassManager &pm, Operation *op, AnalysisManager am, bool verifyPasses,
604  unsigned parentInitGeneration, PassInstrumentor *instrumentor,
605  const PassInstrumentation::PipelineParentInfo *parentInfo) {
606  assert((!instrumentor || parentInfo) &&
607  "expected parent info if instrumentor is provided");
608  auto scopeExit = llvm::make_scope_exit([&] {
609  // Clear out any computed operation analyses. These analyses won't be used
610  // any more in this pipeline, and this helps reduce the current working set
611  // of memory. If preserving these analyses becomes important in the future
612  // we can re-evaluate this.
613  am.clear();
614  });
615 
616  // Run the pipeline over the provided operation.
617  if (instrumentor) {
618  instrumentor->runBeforePipeline(pm.getOpName(*op->getContext()),
619  *parentInfo);
620  }
621 
622  for (Pass &pass : pm.getPasses())
623  if (failed(run(&pass, op, am, verifyPasses, parentInitGeneration)))
624  return failure();
625 
626  if (instrumentor) {
627  instrumentor->runAfterPipeline(pm.getOpName(*op->getContext()),
628  *parentInfo);
629  }
630  return success();
631 }
632 
633 /// Find an operation pass manager with the given anchor name, or nullptr if one
634 /// does not exist.
635 static OpPassManager *
637  auto *it = llvm::find_if(
638  mgrs, [&](OpPassManager &mgr) { return mgr.getOpAnchorName() == name; });
639  return it == mgrs.end() ? nullptr : &*it;
640 }
641 
642 /// Find an operation pass manager that can operate on an operation of the given
643 /// type, or nullptr if one does not exist.
645  OperationName name,
646  MLIRContext &context) {
647  auto *it = llvm::find_if(mgrs, [&](OpPassManager &mgr) {
648  return mgr.getImpl().canScheduleOn(context, name);
649  });
650  return it == mgrs.end() ? nullptr : &*it;
651 }
652 
653 OpToOpPassAdaptor::OpToOpPassAdaptor(OpPassManager &&mgr) {
654  mgrs.emplace_back(std::move(mgr));
655 }
656 
657 void OpToOpPassAdaptor::getDependentDialects(DialectRegistry &dialects) const {
658  for (auto &pm : mgrs)
659  pm.getDependentDialects(dialects);
660 }
661 
662 LogicalResult OpToOpPassAdaptor::tryMergeInto(MLIRContext *ctx,
663  OpToOpPassAdaptor &rhs) {
664  // Functor used to check if a pass manager is generic, i.e. op-agnostic.
665  auto isGenericPM = [&](OpPassManager &pm) { return !pm.getOpName(); };
666 
667  // Functor used to detect if the given generic pass manager will have a
668  // potential schedule conflict with the given `otherPMs`.
669  auto hasScheduleConflictWith = [&](OpPassManager &genericPM,
671  return llvm::any_of(otherPMs, [&](OpPassManager &pm) {
672  // If this is a non-generic pass manager, a conflict will arise if a
673  // non-generic pass manager's operation name can be scheduled on the
674  // generic passmanager.
675  if (std::optional<OperationName> pmOpName = pm.getOpName(*ctx))
676  return genericPM.getImpl().canScheduleOn(*ctx, *pmOpName);
677  // Otherwise, this is a generic pass manager. We current can't determine
678  // when generic pass managers can be merged, so conservatively assume they
679  // conflict.
680  return true;
681  });
682  };
683 
684  // Check that if either adaptor has a generic pass manager, that pm is
685  // compatible within any non-generic pass managers.
686  //
687  // Check the current adaptor.
688  auto *lhsGenericPMIt = llvm::find_if(mgrs, isGenericPM);
689  if (lhsGenericPMIt != mgrs.end() &&
690  hasScheduleConflictWith(*lhsGenericPMIt, rhs.mgrs))
691  return failure();
692  // Check the rhs adaptor.
693  auto *rhsGenericPMIt = llvm::find_if(rhs.mgrs, isGenericPM);
694  if (rhsGenericPMIt != rhs.mgrs.end() &&
695  hasScheduleConflictWith(*rhsGenericPMIt, mgrs))
696  return failure();
697 
698  for (auto &pm : mgrs) {
699  // If an existing pass manager exists, then merge the given pass manager
700  // into it.
701  if (auto *existingPM =
702  findPassManagerWithAnchor(rhs.mgrs, pm.getOpAnchorName())) {
703  pm.getImpl().mergeInto(existingPM->getImpl());
704  } else {
705  // Otherwise, add the given pass manager to the list.
706  rhs.mgrs.emplace_back(std::move(pm));
707  }
708  }
709  mgrs.clear();
710 
711  // After coalescing, sort the pass managers within rhs by name.
712  auto compareFn = [](const OpPassManager &lhs, const OpPassManager &rhs) {
713  // Order op-specific pass managers first and op-agnostic pass managers last.
714  if (std::optional<StringRef> lhsName = lhs.getOpName()) {
715  if (std::optional<StringRef> rhsName = rhs.getOpName())
716  return *lhsName < *rhsName;
717  return true; // lhs(op-specific) < rhs(op-agnostic)
718  }
719  return false; // lhs(op-agnostic) > rhs(op-specific)
720  };
721  llvm::sort(rhs.mgrs, compareFn);
722  return success();
723 }
724 
725 /// Returns the adaptor pass name.
726 std::string OpToOpPassAdaptor::getAdaptorName() {
727  std::string name = "Pipeline Collection : [";
728  llvm::raw_string_ostream os(name);
729  llvm::interleaveComma(getPassManagers(), os, [&](OpPassManager &pm) {
730  os << '\'' << pm.getOpAnchorName() << '\'';
731  });
732  os << ']';
733  return name;
734 }
735 
736 void OpToOpPassAdaptor::runOnOperation() {
737  llvm_unreachable(
738  "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor");
739 }
740 
741 /// Run the held pipeline over all nested operations.
742 void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) {
743  if (getContext().isMultithreadingEnabled())
744  runOnOperationAsyncImpl(verifyPasses);
745  else
746  runOnOperationImpl(verifyPasses);
747 }
748 
749 /// Run this pass adaptor synchronously.
750 void OpToOpPassAdaptor::runOnOperationImpl(bool verifyPasses) {
751  auto am = getAnalysisManager();
752  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
753  this};
754  auto *instrumentor = am.getPassInstrumentor();
755  for (auto &region : getOperation()->getRegions()) {
756  for (auto &block : region) {
757  for (auto &op : block) {
758  auto *mgr = findPassManagerFor(mgrs, op.getName(), *op.getContext());
759  if (!mgr)
760  continue;
761 
762  // Run the held pipeline over the current operation.
763  unsigned initGeneration = mgr->impl->initializationGeneration;
764  if (failed(runPipeline(*mgr, &op, am.nest(&op), verifyPasses,
765  initGeneration, instrumentor, &parentInfo)))
766  signalPassFailure();
767  }
768  }
769  }
770 }
771 
772 /// Utility functor that checks if the two ranges of pass managers have a size
773 /// mismatch.
776  return lhs.size() != rhs.size() ||
777  llvm::any_of(llvm::seq<size_t>(0, lhs.size()),
778  [&](size_t i) { return lhs[i].size() != rhs[i].size(); });
779 }
780 
781 /// Run this pass adaptor synchronously.
782 void OpToOpPassAdaptor::runOnOperationAsyncImpl(bool verifyPasses) {
783  AnalysisManager am = getAnalysisManager();
784  MLIRContext *context = &getContext();
785 
786  // Create the async executors if they haven't been created, or if the main
787  // pipeline has changed.
788  if (asyncExecutors.empty() || hasSizeMismatch(asyncExecutors.front(), mgrs))
789  asyncExecutors.assign(context->getThreadPool().getMaxConcurrency(), mgrs);
790 
791  // This struct represents the information for a single operation to be
792  // scheduled on a pass manager.
793  struct OpPMInfo {
794  OpPMInfo(unsigned passManagerIdx, Operation *op, AnalysisManager am)
795  : passManagerIdx(passManagerIdx), op(op), am(am) {}
796 
797  /// The index of the pass manager to schedule the operation on.
798  unsigned passManagerIdx;
799  /// The operation to schedule.
800  Operation *op;
801  /// The analysis manager for the operation.
802  AnalysisManager am;
803  };
804 
805  // Run a prepass over the operation to collect the nested operations to
806  // execute over. This ensures that an analysis manager exists for each
807  // operation, as well as providing a queue of operations to execute over.
808  std::vector<OpPMInfo> opInfos;
810  for (auto &region : getOperation()->getRegions()) {
811  for (Operation &op : region.getOps()) {
812  // Get the pass manager index for this operation type.
813  auto pmIdxIt = knownOpPMIdx.try_emplace(op.getName(), std::nullopt);
814  if (pmIdxIt.second) {
815  if (auto *mgr = findPassManagerFor(mgrs, op.getName(), *context))
816  pmIdxIt.first->second = std::distance(mgrs.begin(), mgr);
817  }
818 
819  // If this operation can be scheduled, add it to the list.
820  if (pmIdxIt.first->second)
821  opInfos.emplace_back(*pmIdxIt.first->second, &op, am.nest(&op));
822  }
823  }
824 
825  // Get the current thread for this adaptor.
826  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
827  this};
828  auto *instrumentor = am.getPassInstrumentor();
829 
830  // An atomic failure variable for the async executors.
831  std::vector<std::atomic<bool>> activePMs(asyncExecutors.size());
832  std::fill(activePMs.begin(), activePMs.end(), false);
833  std::atomic<bool> hasFailure = false;
834  parallelForEach(context, opInfos, [&](OpPMInfo &opInfo) {
835  // Find an executor for this operation.
836  auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
837  bool expectedInactive = false;
838  return isActive.compare_exchange_strong(expectedInactive, true);
839  });
840  unsigned pmIndex = it - activePMs.begin();
841 
842  // Get the pass manager for this operation and execute it.
843  OpPassManager &pm = asyncExecutors[pmIndex][opInfo.passManagerIdx];
844  LogicalResult pipelineResult = runPipeline(
845  pm, opInfo.op, opInfo.am, verifyPasses,
846  pm.impl->initializationGeneration, instrumentor, &parentInfo);
847  if (failed(pipelineResult))
848  hasFailure.store(true);
849 
850  // Reset the active bit for this pass manager.
851  activePMs[pmIndex].store(false);
852  });
853 
854  // Signal a failure if any of the executors failed.
855  if (hasFailure)
856  signalPassFailure();
857 }
858 
859 //===----------------------------------------------------------------------===//
860 // PassManager
861 //===----------------------------------------------------------------------===//
862 
863 PassManager::PassManager(MLIRContext *ctx, StringRef operationName,
864  Nesting nesting)
865  : OpPassManager(operationName, nesting), context(ctx), passTiming(false),
866  verifyPasses(true) {}
867 
869  : OpPassManager(operationName, nesting),
870  context(operationName.getContext()), passTiming(false),
871  verifyPasses(true) {}
872 
873 PassManager::~PassManager() = default;
874 
875 void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; }
876 
877 /// Run the passes within this manager on the provided operation.
878 LogicalResult PassManager::run(Operation *op) {
879  MLIRContext *context = getContext();
880  std::optional<OperationName> anchorOp = getOpName(*context);
881  if (anchorOp && anchorOp != op->getName())
882  return emitError(op->getLoc())
883  << "can't run '" << getOpAnchorName() << "' pass manager on '"
884  << op->getName() << "' op";
885 
886  // Register all dialects for the current pipeline.
887  DialectRegistry dependentDialects;
888  getDependentDialects(dependentDialects);
889  context->appendDialectRegistry(dependentDialects);
890  for (StringRef name : dependentDialects.getDialectNames())
891  context->getOrLoadDialect(name);
892 
893  // Before running, make sure to finalize the pipeline pass list.
894  if (failed(getImpl().finalizePassList(context)))
895  return failure();
896 
897  // Notify the context that we start running a pipeline for bookkeeping.
898  context->enterMultiThreadedExecution();
899 
900  // Initialize all of the passes within the pass manager with a new generation.
901  llvm::hash_code newInitKey = context->getRegistryHash();
902  llvm::hash_code pipelineKey = hash();
903  if (newInitKey != initializationKey ||
904  pipelineKey != pipelineInitializationKey) {
905  if (failed(initialize(context, impl->initializationGeneration + 1)))
906  return failure();
907  initializationKey = newInitKey;
908  pipelineKey = pipelineInitializationKey;
909  }
910 
911  // Construct a top level analysis manager for the pipeline.
912  ModuleAnalysisManager am(op, instrumentor.get());
913 
914  // If reproducer generation is enabled, run the pass manager with crash
915  // handling enabled.
916  LogicalResult result =
917  crashReproGenerator ? runWithCrashRecovery(op, am) : runPasses(op, am);
918 
919  // Notify the context that the run is done.
920  context->exitMultiThreadedExecution();
921 
922  // Dump all of the pass statistics if necessary.
923  if (passStatisticsMode)
924  dumpStatistics();
925  return result;
926 }
927 
928 /// Add the provided instrumentation to the pass manager.
929 void PassManager::addInstrumentation(std::unique_ptr<PassInstrumentation> pi) {
930  if (!instrumentor)
931  instrumentor = std::make_unique<PassInstrumentor>();
932 
933  instrumentor->addInstrumentation(std::move(pi));
934 }
935 
936 LogicalResult PassManager::runPasses(Operation *op, AnalysisManager am) {
937  return OpToOpPassAdaptor::runPipeline(*this, op, am, verifyPasses,
938  impl->initializationGeneration);
939 }
940 
941 //===----------------------------------------------------------------------===//
942 // AnalysisManager
943 //===----------------------------------------------------------------------===//
944 
945 /// Get an analysis manager for the given operation, which must be a proper
946 /// descendant of the current operation represented by this analysis manager.
948  Operation *currentOp = impl->getOperation();
949  assert(currentOp->isProperAncestor(op) &&
950  "expected valid descendant operation");
951 
952  // Check for the base case where the provided operation is immediately nested.
953  if (currentOp == op->getParentOp())
954  return nestImmediate(op);
955 
956  // Otherwise, we need to collect all ancestors up to the current operation.
957  SmallVector<Operation *, 4> opAncestors;
958  do {
959  opAncestors.push_back(op);
960  op = op->getParentOp();
961  } while (op != currentOp);
962 
963  AnalysisManager result = *this;
964  for (Operation *op : llvm::reverse(opAncestors))
965  result = result.nestImmediate(op);
966  return result;
967 }
968 
969 /// Get an analysis manager for the given immediately nested child operation.
970 AnalysisManager AnalysisManager::nestImmediate(Operation *op) {
971  assert(impl->getOperation() == op->getParentOp() &&
972  "expected immediate child operation");
973 
974  auto [it, inserted] = impl->childAnalyses.try_emplace(op);
975  if (inserted)
976  it->second = std::make_unique<NestedAnalysisMap>(op, impl);
977  return {it->second.get()};
978 }
979 
980 /// Invalidate any non preserved analyses.
982  const detail::PreservedAnalyses &pa) {
983  // If all analyses were preserved, then there is nothing to do here.
984  if (pa.isAll())
985  return;
986 
987  // Invalidate the analyses for the current operation directly.
988  analyses.invalidate(pa);
989 
990  // If no analyses were preserved, then just simply clear out the child
991  // analysis results.
992  if (pa.isNone()) {
993  childAnalyses.clear();
994  return;
995  }
996 
997  // Otherwise, invalidate each child analysis map.
998  SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this);
999  while (!mapsToInvalidate.empty()) {
1000  auto *map = mapsToInvalidate.pop_back_val();
1001  for (auto &analysisPair : map->childAnalyses) {
1002  analysisPair.second->invalidate(pa);
1003  if (!analysisPair.second->childAnalyses.empty())
1004  mapsToInvalidate.push_back(analysisPair.second.get());
1005  }
1006  }
1007 }
1008 
1009 //===----------------------------------------------------------------------===//
1010 // PassInstrumentation
1011 //===----------------------------------------------------------------------===//
1012 
1014 
1016  std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1017 
1019  std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1020 
1021 //===----------------------------------------------------------------------===//
1022 // PassInstrumentor
1023 //===----------------------------------------------------------------------===//
1024 
1025 namespace mlir {
1026 namespace detail {
1028  /// Mutex to keep instrumentation access thread-safe.
1030 
1031  /// Set of registered instrumentations.
1032  std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;
1033 };
1034 } // namespace detail
1035 } // namespace mlir
1036 
1039 
1040 /// See PassInstrumentation::runBeforePipeline for details.
1042  std::optional<OperationName> name,
1043  const PassInstrumentation::PipelineParentInfo &parentInfo) {
1044  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1045  for (auto &instr : impl->instrumentations)
1046  instr->runBeforePipeline(name, parentInfo);
1047 }
1048 
1049 /// See PassInstrumentation::runAfterPipeline for details.
1051  std::optional<OperationName> name,
1052  const PassInstrumentation::PipelineParentInfo &parentInfo) {
1053  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1054  for (auto &instr : llvm::reverse(impl->instrumentations))
1055  instr->runAfterPipeline(name, parentInfo);
1056 }
1057 
1058 /// See PassInstrumentation::runBeforePass for details.
1060  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1061  for (auto &instr : impl->instrumentations)
1062  instr->runBeforePass(pass, op);
1063 }
1064 
1065 /// See PassInstrumentation::runAfterPass for details.
1067  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1068  for (auto &instr : llvm::reverse(impl->instrumentations))
1069  instr->runAfterPass(pass, op);
1070 }
1071 
1072 /// See PassInstrumentation::runAfterPassFailed for details.
1074  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1075  for (auto &instr : llvm::reverse(impl->instrumentations))
1076  instr->runAfterPassFailed(pass, op);
1077 }
1078 
1079 /// See PassInstrumentation::runBeforeAnalysis for details.
1081  Operation *op) {
1082  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1083  for (auto &instr : impl->instrumentations)
1084  instr->runBeforeAnalysis(name, id, op);
1085 }
1086 
1087 /// See PassInstrumentation::runAfterAnalysis for details.
1089  Operation *op) {
1090  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1091  for (auto &instr : llvm::reverse(impl->instrumentations))
1092  instr->runAfterAnalysis(name, id, op);
1093 }
1094 
1095 /// Add the given instrumentation to the collection.
1097  std::unique_ptr<PassInstrumentation> pi) {
1098  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1099  impl->instrumentations.emplace_back(std::move(pi));
1100 }
static InFlightDiagnostic mergeInto(FunctionOpInterface func1, FunctionOpInterface func2)
Merge func1 into func2.
Definition: Utils.cpp:31
static MLIRContext * getContext(OpFoldResult val)
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:401
static void registerDialectsForPipeline(const OpPassManager &pm, DialectRegistry &dialects)
Definition: Pass.cpp:447
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:774
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:644
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:636
#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:947
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:60
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
void executeAction(function_ref< void()> actionFn, const tracing::Action &action)
Dispatch the provided action to the handler if any, or just execute it.
Definition: MLIRContext.h:264
llvm::hash_code getRegistryHash()
Returns a hash of the registry of the context that may be used to give a rough indicator of if the st...
void enterMultiThreadedExecution()
These APIs are tracking whether the context will be used in a multithreading environment: this has no...
llvm::ThreadPoolInterface & getThreadPool()
Return the thread pool used by this context.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:97
void exitMultiThreadedExecution()
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:431
OpPassManager & operator=(const OpPassManager &rhs)
Definition: Pass.cpp:334
friend class PassManager
Allow access to the constructor.
Definition: PassManager.h:186
OpPassManager(Nesting nesting=Nesting::Explicit)
Construct a new op-agnostic ("any") pass manager with the given operation type and nesting behavior.
Definition: Pass.cpp:326
OpPassManager & nest()
Definition: PassManager.h:97
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:390
void setNesting(Nesting nesting)
Enable or disable the implicit nesting on this particular PassManager.
Definition: Pass.cpp:457
size_t size() const
Returns the number of passes held by this manager.
Definition: Pass.cpp:378
detail::OpPassManagerImpl & getImpl()
Returns the internal implementation instance.
Definition: Pass.cpp:381
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition: Pass.cpp:371
Nesting getNesting()
Return the current nesting mode.
Definition: Pass.cpp:459
Nesting
This enum represents the nesting behavior of the pass manager.
Definition: PassManager.h:49
@ Implicit
Implicit nesting behavior.
void dump()
Raw dump of the pass manager to llvm::errs().
Definition: Pass.cpp:441
llvm::pointee_iterator< MutableArrayRef< std::unique_ptr< Pass > >::iterator > pass_iterator
Iterator over the passes in this pass manager.
Definition: PassManager.h:76
llvm::pointee_iterator< ArrayRef< std::unique_ptr< Pass > >::const_iterator > const_pass_iterator
Definition: PassManager.h:82
void getDependentDialects(DialectRegistry &dialects) const
Register dependent dialects for the current pass manager.
Definition: Pass.cpp:453
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
Definition: Pass.cpp:394
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:384
OpPassManager & nestAny()
Nest a new op-agnostic ("any") pass manager under this pass manager.
Definition: Pass.cpp:367
iterator_range< pass_iterator > getPasses()
Definition: PassManager.h:79
static StringRef getAnyOpAnchorName()
Return the string name used to anchor op-agnostic pass managers that operate generically on any viabl...
Definition: PassManager.h:137
void clear()
Clear the pipeline, but not the other options set on this OpPassManager.
Definition: Pass.cpp:375
pass_iterator begin()
Definition: Pass.cpp:345
pass_iterator end()
Definition: Pass.cpp:348
This class provides the API for ops that are known to be isolated from above.
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
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Definition: Operation.h:123
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
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.
Definition: Operation.cpp:219
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:673
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: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: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:1018
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:1015
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:1073
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the given instrumentation to the collection.
Definition: Pass.cpp:1096
void runBeforeAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runBeforeAnalysis for details.
Definition: Pass.cpp:1080
void runAfterPass(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPass for details.
Definition: Pass.cpp:1066
void runAfterAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runAfterAnalysis for details.
Definition: Pass.cpp:1088
void runBeforePass(Pass *pass, Operation *op)
See PassInstrumentation::runBeforePass for details.
Definition: Pass.cpp:1059
void runBeforePipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runBeforePipeline for details.
Definition: Pass.cpp:1041
void runAfterPipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runAfterPipeline for details.
Definition: Pass.cpp:1050
MLIRContext * getContext() const
Return an instance of the context.
Definition: PassManager.h:257
LogicalResult run(Operation *op)
Run the passes within this manager on the provided operation.
Definition: Pass.cpp:878
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
Definition: Pass.cpp:929
void enableVerifier(bool enabled=true)
Runs the verifier after each individual pass.
Definition: Pass.cpp:875
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: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.
void printAsTextualPipeline(raw_ostream &os, bool pretty=false)
Prints out the pass in the textual representation of pipelines.
Definition: Pass.cpp:86
std::optional< StringRef > getOpName() const
Returns the name of the operation that this pass operates on, or std::nullopt if this is a generic Op...
Definition: Pass.h:83
virtual void runOnOperation()=0
The polymorphic API that runs the pass over the currently held operation.
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
void invalidate(const PreservedAnalyses &pa)
Invalidate any cached analyses based upon the given set of preserved analyses.
An adaptor pass used to run operation passes over nested operations.
Definition: PassDetail.h:26
LogicalResult parseFromString(StringRef options, raw_ostream &errorStream=llvm::errs())
Parse options out as key=value pairs that can then be handed off to the llvm::cl command line passing...
void print(raw_ostream &os) const
Print the options held by this struct in a form that can be parsed via 'parseFromString'.
void copyOptionValuesFrom(const PassOptions &other)
Copy the option values from 'other' into 'this', where 'other' has the same options as 'this'.
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 & unindent()
Decreases the indent and returning this raw_indented_ostream.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
virtual ArrayRef< IRUnit > getContextIRUnits() const
Return the set of IR units that are associated with this action.
Definition: Action.h:55
ArrayRef< IRUnit > irUnits
Set of IR units (operations, regions, blocks, values) that are associated with this action.
Definition: Action.h:66
AttrTypeReplacer.
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
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:423
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:981
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< OperationName > getOpName(MLIRContext &context)
Return the operation name of this pass manager.
Definition: Pass.cpp:166
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition: Pass.cpp:221
OpPassManager & nest(StringRef nestedName)
Definition: Pass.cpp:144
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:302
OpPassManagerImpl(OpPassManager::Nesting nesting)
Definition: Pass.cpp:123
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
Definition: Pass.cpp:179
OpPassManager & nestAny()
Definition: Pass.cpp:147
OpPassManager & nest(OperationName nestedName)
Nest a new operation pass manager for the given operation kind under this pass manager.
Definition: Pass.cpp:141
std::vector< std::unique_ptr< Pass > > passes
The set of passes to run as part of this pass manager.
Definition: Pass.cpp:195
std::optional< StringRef > getOpName() const
Definition: Pass.cpp:171
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
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:1032
llvm::sys::SmartMutex< true > mutex
Mutex to keep instrumentation access thread-safe.
Definition: Pass.cpp:1029