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