MLIR  22.0.0git
Pass.cpp
Go to the documentation of this file.
1 //===- Pass.cpp - Pass infrastructure implementation ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements common pass infrastructure.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/Pass/Pass.h"
14 #include "PassDetail.h"
15 #include "mlir/IR/Diagnostics.h"
16 #include "mlir/IR/OpDefinition.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/Mutex.h"
25 #include "llvm/Support/Signals.h"
26 #include "llvm/Support/Threading.h"
27 #include <optional>
28 
29 using namespace mlir;
30 using namespace mlir::detail;
31 
32 //===----------------------------------------------------------------------===//
33 // PassExecutionAction
34 //===----------------------------------------------------------------------===//
35 
37  const Pass &pass)
38  : Base(irUnits), pass(pass) {}
39 
40 void PassExecutionAction::print(raw_ostream &os) const {
41  os << llvm::formatv("`{0}` running `{1}` on Operation `{2}`", tag,
42  pass.getName(), getOp()->getName());
43 }
44 
47  return irUnits.empty() ? nullptr
48  : llvm::dyn_cast_if_present<Operation *>(irUnits[0]);
49 }
50 
52 
53 //===----------------------------------------------------------------------===//
54 // Pass
55 //===----------------------------------------------------------------------===//
56 
57 /// Out of line virtual method to ensure vtables and metadata are emitted to a
58 /// single .o file.
59 void Pass::anchor() {}
60 
61 /// Attempt to initialize the options of this pass from the given string.
63  StringRef options,
64  function_ref<LogicalResult(const Twine &)> errorHandler) {
65  std::string errStr;
66  llvm::raw_string_ostream os(errStr);
67  if (failed(passOptions.parseFromString(options, os))) {
68  return errorHandler(errStr);
69  }
70  return success();
71 }
72 
73 /// Copy the option values from 'other', which is another instance of this
74 /// pass.
75 void Pass::copyOptionValuesFrom(const Pass *other) {
76  passOptions.copyOptionValuesFrom(other->passOptions);
77 }
78 
79 /// Prints out the pass in the textual representation of pipelines. If this is
80 /// an adaptor pass, print its pass managers. When `pretty` is true, the
81 /// printed pipeline is formatted for readability.
82 void Pass::printAsTextualPipeline(raw_ostream &os, bool pretty) {
83  // Special case for adaptors to print its pass managers.
84  if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(this)) {
85  llvm::interleave(
86  adaptor->getPassManagers(),
87  [&](OpPassManager &pm) { pm.printAsTextualPipeline(os, pretty); },
88  [&] {
89  os << ",";
90  if (pretty)
91  os << "\n";
92  });
93  return;
94  }
95  // Otherwise, print the pass argument followed by its options. If the pass
96  // doesn't have an argument, print the name of the pass to give some indicator
97  // of what pass was run.
98  StringRef argument = getArgument();
99  if (!argument.empty())
100  os << argument;
101  else
102  os << "unknown<" << getName() << ">";
103  passOptions.print(os);
104 }
105 
106 //===----------------------------------------------------------------------===//
107 // OpPassManagerImpl
108 //===----------------------------------------------------------------------===//
109 
110 namespace mlir {
111 namespace detail {
114  : name(opName.getStringRef().str()), opName(opName),
117  : name(name == OpPassManager::getAnyOpAnchorName() ? "" : name.str()),
122  : name(rhs.name), opName(rhs.opName),
124  nesting(rhs.nesting) {
125  for (const std::unique_ptr<Pass> &pass : rhs.passes) {
126  std::unique_ptr<Pass> newPass = pass->clone();
127  newPass->threadingSibling = pass.get();
128  passes.push_back(std::move(newPass));
129  }
130  }
131 
132  /// Merge the passes of this pass manager into the one provided.
133  void mergeInto(OpPassManagerImpl &rhs);
134 
135  /// Nest a new operation pass manager for the given operation kind under this
136  /// pass manager.
138  return nest(OpPassManager(nestedName, nesting));
139  }
140  OpPassManager &nest(StringRef nestedName) {
141  return nest(OpPassManager(nestedName, nesting));
142  }
144 
145  /// Nest the given pass manager under this pass manager.
146  OpPassManager &nest(OpPassManager &&nested);
147 
148  /// Add the given pass to this pass manager. If this pass has a concrete
149  /// operation type, it must be the same type as this pass manager.
150  void addPass(std::unique_ptr<Pass> pass);
151 
152  /// Clear the list of passes in this pass manager, other options are
153  /// preserved.
154  void clear();
155 
156  /// Finalize the pass list in preparation for execution. This includes
157  /// coalescing adjacent pass managers when possible, verifying scheduled
158  /// passes, etc.
159  LogicalResult finalizePassList(MLIRContext *ctx);
160 
161  /// Return the operation name of this pass manager.
162  std::optional<OperationName> getOpName(MLIRContext &context) {
163  if (!name.empty() && !opName)
164  opName = OperationName(name, &context);
165  return opName;
166  }
167  std::optional<StringRef> getOpName() const {
168  return name.empty() ? std::optional<StringRef>()
169  : std::optional<StringRef>(name);
170  }
171 
172  /// Return the name used to anchor this pass manager. This is either the name
173  /// of an operation, or the result of `getAnyOpAnchorName()` in the case of an
174  /// op-agnostic pass manager.
175  StringRef getOpAnchorName() const {
176  return getOpName().value_or(OpPassManager::getAnyOpAnchorName());
177  }
178 
179  /// Indicate if the current pass manager can be scheduled on the given
180  /// operation type.
182 
183  /// The name of the operation that passes of this pass manager operate on.
184  std::string name;
185 
186  /// The cached OperationName (internalized in the context) for the name of the
187  /// operation that passes of this pass manager operate on.
188  std::optional<OperationName> opName;
189 
190  /// The set of passes to run as part of this pass manager.
191  std::vector<std::unique_ptr<Pass>> passes;
192 
193  /// The current initialization generation of this pass manager. This is used
194  /// to indicate when a pass manager should be reinitialized.
196 
197  /// Control the implicit nesting of passes that mismatch the name set for this
198  /// OpPassManager.
200 };
201 } // namespace detail
202 } // namespace mlir
203 
205  assert(name == rhs.name && "merging unrelated pass managers");
206  for (auto &pass : passes)
207  rhs.passes.push_back(std::move(pass));
208  passes.clear();
209 }
210 
211 OpPassManager &OpPassManagerImpl::nest(OpPassManager &&nested) {
212  auto *adaptor = new OpToOpPassAdaptor(std::move(nested));
213  addPass(std::unique_ptr<Pass>(adaptor));
214  return adaptor->getPassManagers().front();
215 }
216 
217 void OpPassManagerImpl::addPass(std::unique_ptr<Pass> pass) {
218  // If this pass runs on a different operation than this pass manager, then
219  // implicitly nest a pass manager for this operation if enabled.
220  std::optional<StringRef> pmOpName = getOpName();
221  std::optional<StringRef> passOpName = pass->getOpName();
222  if (pmOpName && passOpName && *pmOpName != *passOpName) {
223  if (nesting == OpPassManager::Nesting::Implicit)
224  return nest(*passOpName).addPass(std::move(pass));
225  llvm::report_fatal_error(llvm::Twine("Can't add pass '") + pass->getName() +
226  "' restricted to '" + *passOpName +
227  "' on a PassManager intended to run on '" +
228  getOpAnchorName() + "', did you intend to nest?");
229  }
230 
231  passes.emplace_back(std::move(pass));
232 }
233 
234 void OpPassManagerImpl::clear() { passes.clear(); }
235 
236 LogicalResult OpPassManagerImpl::finalizePassList(MLIRContext *ctx) {
237  auto finalizeAdaptor = [ctx](OpToOpPassAdaptor *adaptor) {
238  for (auto &pm : adaptor->getPassManagers())
239  if (failed(pm.getImpl().finalizePassList(ctx)))
240  return failure();
241  return success();
242  };
243 
244  // Walk the pass list and merge adjacent adaptors.
245  OpToOpPassAdaptor *lastAdaptor = nullptr;
246  for (auto &pass : passes) {
247  // Check to see if this pass is an adaptor.
248  if (auto *currentAdaptor = dyn_cast<OpToOpPassAdaptor>(pass.get())) {
249  // If it is the first adaptor in a possible chain, remember it and
250  // continue.
251  if (!lastAdaptor) {
252  lastAdaptor = currentAdaptor;
253  continue;
254  }
255 
256  // Otherwise, try to merge into the existing adaptor and delete the
257  // current one. If merging fails, just remember this as the last adaptor.
258  if (succeeded(currentAdaptor->tryMergeInto(ctx, *lastAdaptor)))
259  pass.reset();
260  else
261  lastAdaptor = currentAdaptor;
262  } else if (lastAdaptor) {
263  // If this pass isn't an adaptor, finalize it and forget the last adaptor.
264  if (failed(finalizeAdaptor(lastAdaptor)))
265  return failure();
266  lastAdaptor = nullptr;
267  }
268  }
269 
270  // If there was an adaptor at the end of the manager, finalize it as well.
271  if (lastAdaptor && failed(finalizeAdaptor(lastAdaptor)))
272  return failure();
273 
274  // Now that the adaptors have been merged, erase any empty slots corresponding
275  // to the merged adaptors that were nulled-out in the loop above.
276  llvm::erase_if(passes, std::logical_not<std::unique_ptr<Pass>>());
277 
278  // If this is a op-agnostic pass manager, there is nothing left to do.
279  std::optional<OperationName> rawOpName = getOpName(*ctx);
280  if (!rawOpName)
281  return success();
282 
283  // Otherwise, verify that all of the passes are valid for the current
284  // operation anchor.
285  std::optional<RegisteredOperationName> opName =
286  rawOpName->getRegisteredInfo();
287  for (std::unique_ptr<Pass> &pass : passes) {
288  if (opName && !pass->canScheduleOn(*opName)) {
289  return emitError(UnknownLoc::get(ctx))
290  << "unable to schedule pass '" << pass->getName()
291  << "' on a PassManager intended to run on '" << getOpAnchorName()
292  << "'!";
293  }
294  }
295  return success();
296 }
297 
298 bool OpPassManagerImpl::canScheduleOn(MLIRContext &context,
299  OperationName opName) {
300  // If this pass manager is op-specific, we simply check if the provided
301  // operation name is the same as this one.
302  std::optional<OperationName> pmOpName = getOpName(context);
303  if (pmOpName)
304  return pmOpName == opName;
305 
306  // Otherwise, this is an op-agnostic pass manager. Check that the operation
307  // can be scheduled on all passes within the manager.
308  std::optional<RegisteredOperationName> registeredInfo =
309  opName.getRegisteredInfo();
310  if (!registeredInfo ||
311  !registeredInfo->hasTrait<OpTrait::IsIsolatedFromAbove>())
312  return false;
313  return llvm::all_of(passes, [&](const std::unique_ptr<Pass> &pass) {
314  return pass->canScheduleOn(*registeredInfo);
315  });
316 }
317 
318 //===----------------------------------------------------------------------===//
319 // OpPassManager
320 //===----------------------------------------------------------------------===//
321 
323  : impl(new OpPassManagerImpl(nesting)) {}
324 OpPassManager::OpPassManager(StringRef name, Nesting nesting)
325  : impl(new OpPassManagerImpl(name, nesting)) {}
327  : impl(new OpPassManagerImpl(name, nesting)) {}
328 OpPassManager::OpPassManager(OpPassManager &&rhs) { *this = std::move(rhs); }
329 OpPassManager::OpPassManager(const OpPassManager &rhs) { *this = rhs; }
331  impl = std::make_unique<OpPassManagerImpl>(*rhs.impl);
332  return *this;
333 }
335  impl = std::move(rhs.impl);
336  return *this;
337 }
338 
340 
342  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();
343 }
345  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();
346 }
347 
349  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();
350 }
352  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();
353 }
354 
355 /// Nest a new operation pass manager for the given operation kind under this
356 /// pass manager.
358  return impl->nest(nestedName);
359 }
360 OpPassManager &OpPassManager::nest(StringRef nestedName) {
361  return impl->nest(nestedName);
362 }
363 OpPassManager &OpPassManager::nestAny() { return impl->nestAny(); }
364 
365 /// Add the given pass to this pass manager. If this pass has a concrete
366 /// operation type, it must be the same type as this pass manager.
367 void OpPassManager::addPass(std::unique_ptr<Pass> pass) {
368  impl->addPass(std::move(pass));
369 }
370 
371 void OpPassManager::clear() { impl->clear(); }
372 
373 /// Returns the number of passes held by this manager.
374 size_t OpPassManager::size() const { return impl->passes.size(); }
375 
376 /// Returns the internal implementation instance.
378 
379 /// Return the operation name that this pass manager operates on.
380 std::optional<StringRef> OpPassManager::getOpName() const {
381  return impl->getOpName();
382 }
383 
384 /// Return the operation name that this pass manager operates on.
385 std::optional<OperationName>
387  return impl->getOpName(context);
388 }
389 
391  return impl->getOpAnchorName();
392 }
393 
394 /// Prints out the passes of the pass manager as the textual representation
395 /// of pipelines. When `pretty` is true, the printed pipeline is formatted for
396 /// readability.
398  raw_indented_ostream &os, StringRef anchorName,
400  bool pretty = false) {
401  os << anchorName << "(";
402  if (pretty) {
403  os << "\n";
404  os.indent();
405  }
406  llvm::interleave(
407  passes,
408  [&](mlir::Pass &pass) { pass.printAsTextualPipeline(os, pretty); },
409  [&]() {
410  os << ",";
411  if (pretty)
412  os << "\n";
413  });
414  if (pretty) {
415  os << "\n";
416  os.unindent();
417  }
418  os << ")";
419 }
421  raw_ostream &os, StringRef anchorName,
423  bool pretty) {
424  raw_indented_ostream indentedOS(os);
425  printAsTextualPipeline(indentedOS, anchorName, passes, pretty);
426 }
427 void OpPassManager::printAsTextualPipeline(raw_ostream &os, bool pretty) const {
428  StringRef anchorName = getOpAnchorName();
429  raw_indented_ostream indentedOS(os);
431  indentedOS, anchorName,
432  {MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin(),
433  MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end()},
434  pretty);
435 }
436 
438  llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes:\n";
439  printAsTextualPipeline(llvm::errs(), /*pretty=*/true);
440  llvm::errs() << "\n";
441 }
442 
444  DialectRegistry &dialects) {
445  for (const Pass &pass : pm.getPasses())
446  pass.getDependentDialects(dialects);
447 }
448 
450  registerDialectsForPipeline(*this, dialects);
451 }
452 
453 void OpPassManager::setNesting(Nesting nesting) { impl->nesting = nesting; }
454 
456 
457 LogicalResult OpPassManager::initialize(MLIRContext *context,
458  unsigned newInitGeneration) {
459  if (impl->initializationGeneration == newInitGeneration)
460  return success();
461  impl->initializationGeneration = newInitGeneration;
462  for (Pass &pass : getPasses()) {
463  // If this pass isn't an adaptor, directly initialize it.
464  auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
465  if (!adaptor) {
466  if (failed(pass.initialize(context)))
467  return failure();
468  continue;
469  }
470 
471  // Otherwise, initialize each of the adaptors pass managers.
472  for (OpPassManager &adaptorPM : adaptor->getPassManagers())
473  if (failed(adaptorPM.initialize(context, newInitGeneration)))
474  return failure();
475  }
476  return success();
477 }
478 
479 llvm::hash_code OpPassManager::hash() {
480  llvm::hash_code hashCode{};
481  for (Pass &pass : getPasses()) {
482  // If this pass isn't an adaptor, directly hash it.
483  auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
484  if (!adaptor) {
485  hashCode = llvm::hash_combine(hashCode, &pass);
486  continue;
487  }
488  // Otherwise, hash recursively each of the adaptors pass managers.
489  for (OpPassManager &adaptorPM : adaptor->getPassManagers())
490  llvm::hash_combine(hashCode, adaptorPM.hash());
491  }
492  return hashCode;
493 }
494 
495 //===----------------------------------------------------------------------===//
496 // OpToOpPassAdaptor
497 //===----------------------------------------------------------------------===//
498 
499 LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op,
500  AnalysisManager am, bool verifyPasses,
501  unsigned parentInitGeneration) {
502  std::optional<RegisteredOperationName> opInfo = op->getRegisteredInfo();
503  if (!opInfo)
504  return op->emitOpError()
505  << "trying to schedule a pass on an unregistered operation";
506  if (!opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>())
507  return op->emitOpError() << "trying to schedule a pass on an operation not "
508  "marked as 'IsolatedFromAbove'";
509  if (!pass->canScheduleOn(*op->getName().getRegisteredInfo()))
510  return op->emitOpError()
511  << "trying to schedule a pass on an unsupported operation";
512 
513  // Initialize the pass state with a callback for the pass to dynamically
514  // execute a pipeline on the currently visited operation.
516  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
517  pass};
518  auto dynamicPipelineCallback = [&](OpPassManager &pipeline,
519  Operation *root) -> LogicalResult {
520  if (!op->isAncestor(root))
521  return root->emitOpError()
522  << "Trying to schedule a dynamic pipeline on an "
523  "operation that isn't "
524  "nested under the current operation the pass is processing";
525  assert(
526  pipeline.getImpl().canScheduleOn(*op->getContext(), root->getName()));
527 
528  // Before running, finalize the passes held by the pipeline.
529  if (failed(pipeline.getImpl().finalizePassList(root->getContext())))
530  return failure();
531 
532  // Initialize the user provided pipeline and execute the pipeline.
533  if (failed(pipeline.initialize(root->getContext(), parentInitGeneration)))
534  return failure();
535  AnalysisManager nestedAm = root == op ? am : am.nest(root);
536  return OpToOpPassAdaptor::runPipeline(pipeline, root, nestedAm,
537  verifyPasses, parentInitGeneration,
538  pi, &parentInfo);
539  };
540  pass->passState.emplace(op, am, dynamicPipelineCallback);
541 
542  // Instrument before the pass has run.
543  if (pi)
544  pi->runBeforePass(pass, op);
545 
546  bool passFailed = false;
548  [&]() {
549  // Invoke the virtual runOnOperation method.
550  if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass))
551  adaptor->runOnOperation(verifyPasses);
552  else
553  pass->runOnOperation();
554  passFailed = pass->passState->irAndPassFailed.getInt();
555  },
556  {op}, *pass);
557 
558  // Invalidate any non preserved analyses.
559  am.invalidate(pass->passState->preservedAnalyses);
560 
561  // When verifyPasses is specified, we run the verifier (unless the pass
562  // failed).
563  if (!passFailed && verifyPasses) {
564  bool runVerifierNow = true;
565 
566  // If the pass is an adaptor pass, we don't run the verifier recursively
567  // because the nested operations should have already been verified after
568  // nested passes had run.
569  bool runVerifierRecursively = !isa<OpToOpPassAdaptor>(pass);
570 
571  // Reduce compile time by avoiding running the verifier if the pass didn't
572  // change the IR since the last time the verifier was run:
573  //
574  // 1) If the pass said that it preserved all analyses then it can't have
575  // permuted the IR.
576  //
577  // We run these checks in EXPENSIVE_CHECKS mode out of caution.
578 #ifndef EXPENSIVE_CHECKS
579  runVerifierNow = !pass->passState->preservedAnalyses.isAll();
580 #endif
581  if (runVerifierNow)
582  passFailed = failed(verify(op, runVerifierRecursively));
583  }
584 
585  // Instrument after the pass has run.
586  if (pi) {
587  if (passFailed)
588  pi->runAfterPassFailed(pass, op);
589  else
590  pi->runAfterPass(pass, op);
591  }
592 
593  // Return if the pass signaled a failure.
594  return failure(passFailed);
595 }
596 
597 /// Run the given operation and analysis manager on a provided op pass manager.
598 LogicalResult OpToOpPassAdaptor::runPipeline(
599  OpPassManager &pm, Operation *op, AnalysisManager am, bool verifyPasses,
600  unsigned parentInitGeneration, PassInstrumentor *instrumentor,
601  const PassInstrumentation::PipelineParentInfo *parentInfo) {
602  assert((!instrumentor || parentInfo) &&
603  "expected parent info if instrumentor is provided");
604  auto scopeExit = llvm::make_scope_exit([&] {
605  // Clear out any computed operation analyses. These analyses won't be used
606  // any more in this pipeline, and this helps reduce the current working set
607  // of memory. If preserving these analyses becomes important in the future
608  // we can re-evaluate this.
609  am.clear();
610  });
611 
612  // Run the pipeline over the provided operation.
613  if (instrumentor) {
614  instrumentor->runBeforePipeline(pm.getOpName(*op->getContext()),
615  *parentInfo);
616  }
617 
618  for (Pass &pass : pm.getPasses())
619  if (failed(run(&pass, op, am, verifyPasses, parentInitGeneration)))
620  return failure();
621 
622  if (instrumentor) {
623  instrumentor->runAfterPipeline(pm.getOpName(*op->getContext()),
624  *parentInfo);
625  }
626  return success();
627 }
628 
629 /// Find an operation pass manager with the given anchor name, or nullptr if one
630 /// does not exist.
631 static OpPassManager *
633  auto *it = llvm::find_if(
634  mgrs, [&](OpPassManager &mgr) { return mgr.getOpAnchorName() == name; });
635  return it == mgrs.end() ? nullptr : &*it;
636 }
637 
638 /// Find an operation pass manager that can operate on an operation of the given
639 /// type, or nullptr if one does not exist.
641  OperationName name,
642  MLIRContext &context) {
643  auto *it = llvm::find_if(mgrs, [&](OpPassManager &mgr) {
644  return mgr.getImpl().canScheduleOn(context, name);
645  });
646  return it == mgrs.end() ? nullptr : &*it;
647 }
648 
649 OpToOpPassAdaptor::OpToOpPassAdaptor(OpPassManager &&mgr) {
650  mgrs.emplace_back(std::move(mgr));
651 }
652 
653 void OpToOpPassAdaptor::getDependentDialects(DialectRegistry &dialects) const {
654  for (auto &pm : mgrs)
655  pm.getDependentDialects(dialects);
656 }
657 
658 LogicalResult OpToOpPassAdaptor::tryMergeInto(MLIRContext *ctx,
659  OpToOpPassAdaptor &rhs) {
660  // Functor used to check if a pass manager is generic, i.e. op-agnostic.
661  auto isGenericPM = [&](OpPassManager &pm) { return !pm.getOpName(); };
662 
663  // Functor used to detect if the given generic pass manager will have a
664  // potential schedule conflict with the given `otherPMs`.
665  auto hasScheduleConflictWith = [&](OpPassManager &genericPM,
667  return llvm::any_of(otherPMs, [&](OpPassManager &pm) {
668  // If this is a non-generic pass manager, a conflict will arise if a
669  // non-generic pass manager's operation name can be scheduled on the
670  // generic passmanager.
671  if (std::optional<OperationName> pmOpName = pm.getOpName(*ctx))
672  return genericPM.getImpl().canScheduleOn(*ctx, *pmOpName);
673  // Otherwise, this is a generic pass manager. We current can't determine
674  // when generic pass managers can be merged, so conservatively assume they
675  // conflict.
676  return true;
677  });
678  };
679 
680  // Check that if either adaptor has a generic pass manager, that pm is
681  // compatible within any non-generic pass managers.
682  //
683  // Check the current adaptor.
684  auto *lhsGenericPMIt = llvm::find_if(mgrs, isGenericPM);
685  if (lhsGenericPMIt != mgrs.end() &&
686  hasScheduleConflictWith(*lhsGenericPMIt, rhs.mgrs))
687  return failure();
688  // Check the rhs adaptor.
689  auto *rhsGenericPMIt = llvm::find_if(rhs.mgrs, isGenericPM);
690  if (rhsGenericPMIt != rhs.mgrs.end() &&
691  hasScheduleConflictWith(*rhsGenericPMIt, mgrs))
692  return failure();
693 
694  for (auto &pm : mgrs) {
695  // If an existing pass manager exists, then merge the given pass manager
696  // into it.
697  if (auto *existingPM =
698  findPassManagerWithAnchor(rhs.mgrs, pm.getOpAnchorName())) {
699  pm.getImpl().mergeInto(existingPM->getImpl());
700  } else {
701  // Otherwise, add the given pass manager to the list.
702  rhs.mgrs.emplace_back(std::move(pm));
703  }
704  }
705  mgrs.clear();
706 
707  // After coalescing, sort the pass managers within rhs by name.
708  auto compareFn = [](const OpPassManager &lhs, const OpPassManager &rhs) {
709  // Order op-specific pass managers first and op-agnostic pass managers last.
710  if (std::optional<StringRef> lhsName = lhs.getOpName()) {
711  if (std::optional<StringRef> rhsName = rhs.getOpName())
712  return *lhsName < *rhsName;
713  return true; // lhs(op-specific) < rhs(op-agnostic)
714  }
715  return false; // lhs(op-agnostic) > rhs(op-specific)
716  };
717  llvm::sort(rhs.mgrs, compareFn);
718  return success();
719 }
720 
721 /// Returns the adaptor pass name.
722 std::string OpToOpPassAdaptor::getAdaptorName() {
723  std::string name = "Pipeline Collection : [";
724  llvm::raw_string_ostream os(name);
725  llvm::interleaveComma(getPassManagers(), os, [&](OpPassManager &pm) {
726  os << '\'' << pm.getOpAnchorName() << '\'';
727  });
728  os << ']';
729  return name;
730 }
731 
732 void OpToOpPassAdaptor::runOnOperation() {
733  llvm_unreachable(
734  "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor");
735 }
736 
737 /// Run the held pipeline over all nested operations.
738 void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) {
739  if (getContext().isMultithreadingEnabled())
740  runOnOperationAsyncImpl(verifyPasses);
741  else
742  runOnOperationImpl(verifyPasses);
743 }
744 
745 /// Run this pass adaptor synchronously.
746 void OpToOpPassAdaptor::runOnOperationImpl(bool verifyPasses) {
747  auto am = getAnalysisManager();
748  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
749  this};
750  auto *instrumentor = am.getPassInstrumentor();
751  for (auto &region : getOperation()->getRegions()) {
752  for (auto &block : region) {
753  for (auto &op : block) {
754  auto *mgr = findPassManagerFor(mgrs, op.getName(), *op.getContext());
755  if (!mgr)
756  continue;
757 
758  // Run the held pipeline over the current operation.
759  unsigned initGeneration = mgr->impl->initializationGeneration;
760  if (failed(runPipeline(*mgr, &op, am.nest(&op), verifyPasses,
761  initGeneration, instrumentor, &parentInfo)))
762  signalPassFailure();
763  }
764  }
765  }
766 }
767 
768 /// Utility functor that checks if the two ranges of pass managers have a size
769 /// mismatch.
772  return lhs.size() != rhs.size() ||
773  llvm::any_of(llvm::seq<size_t>(0, lhs.size()),
774  [&](size_t i) { return lhs[i].size() != rhs[i].size(); });
775 }
776 
777 /// Run this pass adaptor synchronously.
778 void OpToOpPassAdaptor::runOnOperationAsyncImpl(bool verifyPasses) {
779  AnalysisManager am = getAnalysisManager();
780  MLIRContext *context = &getContext();
781 
782  // Create the async executors if they haven't been created, or if the main
783  // pipeline has changed.
784  if (asyncExecutors.empty() || hasSizeMismatch(asyncExecutors.front(), mgrs))
785  asyncExecutors.assign(context->getThreadPool().getMaxConcurrency(), mgrs);
786 
787  // This struct represents the information for a single operation to be
788  // scheduled on a pass manager.
789  struct OpPMInfo {
790  OpPMInfo(unsigned passManagerIdx, Operation *op, AnalysisManager am)
791  : passManagerIdx(passManagerIdx), op(op), am(am) {}
792 
793  /// The index of the pass manager to schedule the operation on.
794  unsigned passManagerIdx;
795  /// The operation to schedule.
796  Operation *op;
797  /// The analysis manager for the operation.
798  AnalysisManager am;
799  };
800 
801  // Run a prepass over the operation to collect the nested operations to
802  // execute over. This ensures that an analysis manager exists for each
803  // operation, as well as providing a queue of operations to execute over.
804  std::vector<OpPMInfo> opInfos;
806  for (auto &region : getOperation()->getRegions()) {
807  for (Operation &op : region.getOps()) {
808  // Get the pass manager index for this operation type.
809  auto pmIdxIt = knownOpPMIdx.try_emplace(op.getName(), std::nullopt);
810  if (pmIdxIt.second) {
811  if (auto *mgr = findPassManagerFor(mgrs, op.getName(), *context))
812  pmIdxIt.first->second = std::distance(mgrs.begin(), mgr);
813  }
814 
815  // If this operation can be scheduled, add it to the list.
816  if (pmIdxIt.first->second)
817  opInfos.emplace_back(*pmIdxIt.first->second, &op, am.nest(&op));
818  }
819  }
820 
821  // Get the current thread for this adaptor.
822  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
823  this};
824  auto *instrumentor = am.getPassInstrumentor();
825 
826  // An atomic failure variable for the async executors.
827  std::vector<std::atomic<bool>> activePMs(asyncExecutors.size());
828  llvm::fill(activePMs, false);
829  std::atomic<bool> hasFailure = false;
830  parallelForEach(context, opInfos, [&](OpPMInfo &opInfo) {
831  // Find an executor for this operation.
832  auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
833  bool expectedInactive = false;
834  return isActive.compare_exchange_strong(expectedInactive, true);
835  });
836  unsigned pmIndex = it - activePMs.begin();
837 
838  // Get the pass manager for this operation and execute it.
839  OpPassManager &pm = asyncExecutors[pmIndex][opInfo.passManagerIdx];
840  LogicalResult pipelineResult = runPipeline(
841  pm, opInfo.op, opInfo.am, verifyPasses,
842  pm.impl->initializationGeneration, instrumentor, &parentInfo);
843  if (failed(pipelineResult))
844  hasFailure.store(true);
845 
846  // Reset the active bit for this pass manager.
847  activePMs[pmIndex].store(false);
848  });
849 
850  // Signal a failure if any of the executors failed.
851  if (hasFailure)
852  signalPassFailure();
853 }
854 
855 //===----------------------------------------------------------------------===//
856 // PassManager
857 //===----------------------------------------------------------------------===//
858 
859 PassManager::PassManager(MLIRContext *ctx, StringRef operationName,
860  Nesting nesting)
861  : OpPassManager(operationName, nesting), context(ctx), passTiming(false),
862  verifyPasses(true) {}
863 
865  : OpPassManager(operationName, nesting),
866  context(operationName.getContext()), passTiming(false),
867  verifyPasses(true) {}
868 
869 PassManager::~PassManager() = default;
870 
871 void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; }
872 
873 /// Run the passes within this manager on the provided operation.
874 LogicalResult PassManager::run(Operation *op) {
875  MLIRContext *context = getContext();
876  std::optional<OperationName> anchorOp = getOpName(*context);
877  if (anchorOp && anchorOp != op->getName())
878  return emitError(op->getLoc())
879  << "can't run '" << getOpAnchorName() << "' pass manager on '"
880  << op->getName() << "' op";
881 
882  // Register all dialects for the current pipeline.
883  DialectRegistry dependentDialects;
884  getDependentDialects(dependentDialects);
885  context->appendDialectRegistry(dependentDialects);
886  for (StringRef name : dependentDialects.getDialectNames())
887  context->getOrLoadDialect(name);
888 
889  // Before running, make sure to finalize the pipeline pass list.
890  if (failed(getImpl().finalizePassList(context)))
891  return failure();
892 
893  // Notify the context that we start running a pipeline for bookkeeping.
894  context->enterMultiThreadedExecution();
895 
896  // Initialize all of the passes within the pass manager with a new generation.
897  llvm::hash_code newInitKey = context->getRegistryHash();
898  llvm::hash_code pipelineKey = hash();
899  if (newInitKey != initializationKey ||
900  pipelineKey != pipelineInitializationKey) {
901  if (failed(initialize(context, impl->initializationGeneration + 1)))
902  return failure();
903  initializationKey = newInitKey;
904  pipelineKey = pipelineInitializationKey;
905  }
906 
907  // Construct a top level analysis manager for the pipeline.
908  ModuleAnalysisManager am(op, instrumentor.get());
909 
910  // If reproducer generation is enabled, run the pass manager with crash
911  // handling enabled.
912  LogicalResult result =
913  crashReproGenerator ? runWithCrashRecovery(op, am) : runPasses(op, am);
914 
915  // Notify the context that the run is done.
916  context->exitMultiThreadedExecution();
917 
918  // Dump all of the pass statistics if necessary.
919  if (passStatisticsMode)
920  dumpStatistics();
921  return result;
922 }
923 
924 /// Add the provided instrumentation to the pass manager.
925 void PassManager::addInstrumentation(std::unique_ptr<PassInstrumentation> pi) {
926  if (!instrumentor)
927  instrumentor = std::make_unique<PassInstrumentor>();
928 
929  instrumentor->addInstrumentation(std::move(pi));
930 }
931 
932 LogicalResult PassManager::runPasses(Operation *op, AnalysisManager am) {
933  return OpToOpPassAdaptor::runPipeline(*this, op, am, verifyPasses,
934  impl->initializationGeneration);
935 }
936 
937 //===----------------------------------------------------------------------===//
938 // AnalysisManager
939 //===----------------------------------------------------------------------===//
940 
941 /// Get an analysis manager for the given operation, which must be a proper
942 /// descendant of the current operation represented by this analysis manager.
944  Operation *currentOp = impl->getOperation();
945  assert(currentOp->isProperAncestor(op) &&
946  "expected valid descendant operation");
947 
948  // Check for the base case where the provided operation is immediately nested.
949  if (currentOp == op->getParentOp())
950  return nestImmediate(op);
951 
952  // Otherwise, we need to collect all ancestors up to the current operation.
953  SmallVector<Operation *, 4> opAncestors;
954  do {
955  opAncestors.push_back(op);
956  op = op->getParentOp();
957  } while (op != currentOp);
958 
959  AnalysisManager result = *this;
960  for (Operation *op : llvm::reverse(opAncestors))
961  result = result.nestImmediate(op);
962  return result;
963 }
964 
965 /// Get an analysis manager for the given immediately nested child operation.
966 AnalysisManager AnalysisManager::nestImmediate(Operation *op) {
967  assert(impl->getOperation() == op->getParentOp() &&
968  "expected immediate child operation");
969 
970  auto [it, inserted] = impl->childAnalyses.try_emplace(op);
971  if (inserted)
972  it->second = std::make_unique<NestedAnalysisMap>(op, impl);
973  return {it->second.get()};
974 }
975 
976 /// Invalidate any non preserved analyses.
978  const detail::PreservedAnalyses &pa) {
979  // If all analyses were preserved, then there is nothing to do here.
980  if (pa.isAll())
981  return;
982 
983  // Invalidate the analyses for the current operation directly.
984  analyses.invalidate(pa);
985 
986  // If no analyses were preserved, then just simply clear out the child
987  // analysis results.
988  if (pa.isNone()) {
989  childAnalyses.clear();
990  return;
991  }
992 
993  // Otherwise, invalidate each child analysis map.
994  SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this);
995  while (!mapsToInvalidate.empty()) {
996  auto *map = mapsToInvalidate.pop_back_val();
997  for (auto &analysisPair : map->childAnalyses) {
998  analysisPair.second->invalidate(pa);
999  if (!analysisPair.second->childAnalyses.empty())
1000  mapsToInvalidate.push_back(analysisPair.second.get());
1001  }
1002  }
1003 }
1004 
1005 //===----------------------------------------------------------------------===//
1006 // PassInstrumentation
1007 //===----------------------------------------------------------------------===//
1008 
1010 
1012  std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1013 
1015  std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}
1016 
1017 //===----------------------------------------------------------------------===//
1018 // PassInstrumentor
1019 //===----------------------------------------------------------------------===//
1020 
1021 namespace mlir {
1022 namespace detail {
1024  /// Mutex to keep instrumentation access thread-safe.
1026 
1027  /// Set of registered instrumentations.
1028  std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;
1029 };
1030 } // namespace detail
1031 } // namespace mlir
1032 
1035 
1036 /// See PassInstrumentation::runBeforePipeline for details.
1038  std::optional<OperationName> name,
1039  const PassInstrumentation::PipelineParentInfo &parentInfo) {
1040  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1041  for (auto &instr : impl->instrumentations)
1042  instr->runBeforePipeline(name, parentInfo);
1043 }
1044 
1045 /// See PassInstrumentation::runAfterPipeline for details.
1047  std::optional<OperationName> name,
1048  const PassInstrumentation::PipelineParentInfo &parentInfo) {
1049  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1050  for (auto &instr : llvm::reverse(impl->instrumentations))
1051  instr->runAfterPipeline(name, parentInfo);
1052 }
1053 
1054 /// See PassInstrumentation::runBeforePass for details.
1056  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1057  for (auto &instr : impl->instrumentations)
1058  instr->runBeforePass(pass, op);
1059 }
1060 
1061 /// See PassInstrumentation::runAfterPass for details.
1063  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1064  for (auto &instr : llvm::reverse(impl->instrumentations))
1065  instr->runAfterPass(pass, op);
1066 }
1067 
1068 /// See PassInstrumentation::runAfterPassFailed for details.
1070  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1071  for (auto &instr : llvm::reverse(impl->instrumentations))
1072  instr->runAfterPassFailed(pass, op);
1073 }
1074 
1075 /// See PassInstrumentation::runBeforeAnalysis for details.
1077  Operation *op) {
1078  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1079  for (auto &instr : impl->instrumentations)
1080  instr->runBeforeAnalysis(name, id, op);
1081 }
1082 
1083 /// See PassInstrumentation::runAfterAnalysis for details.
1085  Operation *op) {
1086  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1087  for (auto &instr : llvm::reverse(impl->instrumentations))
1088  instr->runAfterAnalysis(name, id, op);
1089 }
1090 
1091 /// Add the given instrumentation to the collection.
1093  std::unique_ptr<PassInstrumentation> pi) {
1094  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
1095  impl->instrumentations.emplace_back(std::move(pi));
1096 }
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:397
static void registerDialectsForPipeline(const OpPassManager &pm, DialectRegistry &dialects)
Definition: Pass.cpp:443
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:770
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:640
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:632
#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:943
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:427
OpPassManager & operator=(const OpPassManager &rhs)
Definition: Pass.cpp:330
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:322
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:386
void setNesting(Nesting nesting)
Enable or disable the implicit nesting on this particular PassManager.
Definition: Pass.cpp:453
size_t size() const
Returns the number of passes held by this manager.
Definition: Pass.cpp:374
detail::OpPassManagerImpl & getImpl()
Returns the internal implementation instance.
Definition: Pass.cpp:377
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition: Pass.cpp:367
Nesting getNesting()
Return the current nesting mode.
Definition: Pass.cpp:455
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:437
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:449
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
Definition: Pass.cpp:390
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:380
OpPassManager & nestAny()
Nest a new op-agnostic ("any") pass manager under this pass manager.
Definition: Pass.cpp:363
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:371
pass_iterator begin()
Definition: Pass.cpp:341
pass_iterator end()
Definition: Pass.cpp:344
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:218
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:672
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:40
PassExecutionAction(ArrayRef< IRUnit > irUnits, const Pass &pass)
Construct a PassExecutionAction.
Definition: Pass.cpp:36
Operation * getOp() const
Get the operation that is the base of this pass.
Definition: Pass.cpp:45
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:1014
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:1011
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:1069
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the given instrumentation to the collection.
Definition: Pass.cpp:1092
void runBeforeAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runBeforeAnalysis for details.
Definition: Pass.cpp:1076
void runAfterPass(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPass for details.
Definition: Pass.cpp:1062
void runAfterAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runAfterAnalysis for details.
Definition: Pass.cpp:1084
void runBeforePass(Pass *pass, Operation *op)
See PassInstrumentation::runBeforePass for details.
Definition: Pass.cpp:1055
void runBeforePipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runBeforePipeline for details.
Definition: Pass.cpp:1037
void runAfterPipeline(std::optional< OperationName > name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runAfterPipeline for details.
Definition: Pass.cpp:1046
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:874
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
Definition: Pass.cpp:925
void enableVerifier(bool enabled=true)
Runs the verifier after each individual pass.
Definition: Pass.cpp:871
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:75
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:62
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:82
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:977
void clear()
Clear the list of passes in this pass manager, other options are preserved.
Definition: Pass.cpp:234
OpPassManagerImpl(const OpPassManagerImpl &rhs)
Definition: Pass.cpp:121
std::string name
The name of the operation that passes of this pass manager operate on.
Definition: Pass.cpp:184
OpPassManager::Nesting nesting
Control the implicit nesting of passes that mismatch the name set for this OpPassManager.
Definition: Pass.cpp:199
std::optional< OperationName > getOpName(MLIRContext &context)
Return the operation name of this pass manager.
Definition: Pass.cpp:162
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition: Pass.cpp:217
OpPassManager & nest(StringRef nestedName)
Definition: Pass.cpp:140
unsigned initializationGeneration
The current initialization generation of this pass manager.
Definition: Pass.cpp:195
OpPassManagerImpl(OperationName opName, OpPassManager::Nesting nesting)
Definition: Pass.cpp:113
bool canScheduleOn(MLIRContext &context, OperationName opName)
Indicate if the current pass manager can be scheduled on the given operation type.
Definition: Pass.cpp:298
OpPassManagerImpl(OpPassManager::Nesting nesting)
Definition: Pass.cpp:119
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
Definition: Pass.cpp:175
OpPassManager & nestAny()
Definition: Pass.cpp:143
OpPassManager & nest(OperationName nestedName)
Nest a new operation pass manager for the given operation kind under this pass manager.
Definition: Pass.cpp:137
std::vector< std::unique_ptr< Pass > > passes
The set of passes to run as part of this pass manager.
Definition: Pass.cpp:191
std::optional< StringRef > getOpName() const
Definition: Pass.cpp:167
void mergeInto(OpPassManagerImpl &rhs)
Merge the passes of this pass manager into the one provided.
Definition: Pass.cpp:204
LogicalResult finalizePassList(MLIRContext *ctx)
Finalize the pass list in preparation for execution.
Definition: Pass.cpp:236
std::optional< OperationName > opName
The cached OperationName (internalized in the context) for the name of the operation that passes of t...
Definition: Pass.cpp:188
OpPassManagerImpl(StringRef name, OpPassManager::Nesting nesting)
Definition: Pass.cpp:116
std::vector< std::unique_ptr< PassInstrumentation > > instrumentations
Set of registered instrumentations.
Definition: Pass.cpp:1028
llvm::sys::SmartMutex< true > mutex
Mutex to keep instrumentation access thread-safe.
Definition: Pass.cpp:1025