MLIR  14.0.0git
Pass.cpp
Go to the documentation of this file.
1 //===- Pass.cpp - Pass infrastructure implementation ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements common pass infrastructure.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/Pass/Pass.h"
14 #include "PassDetail.h"
15 #include "mlir/IR/Diagnostics.h"
16 #include "mlir/IR/Dialect.h"
17 #include "mlir/IR/Threading.h"
18 #include "mlir/IR/Verifier.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/ScopeExit.h"
22 #include "llvm/ADT/SetVector.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/CrashRecoveryContext.h"
25 #include "llvm/Support/Mutex.h"
26 #include "llvm/Support/Signals.h"
27 #include "llvm/Support/Threading.h"
28 #include "llvm/Support/ToolOutputFile.h"
29 
30 using namespace mlir;
31 using namespace mlir::detail;
32 
33 //===----------------------------------------------------------------------===//
34 // Pass
35 //===----------------------------------------------------------------------===//
36 
37 /// Out of line virtual method to ensure vtables and metadata are emitted to a
38 /// single .o file.
39 void Pass::anchor() {}
40 
41 /// Attempt to initialize the options of this pass from the given string.
43  return passOptions.parseFromString(options);
44 }
45 
46 /// Copy the option values from 'other', which is another instance of this
47 /// pass.
48 void Pass::copyOptionValuesFrom(const Pass *other) {
49  passOptions.copyOptionValuesFrom(other->passOptions);
50 }
51 
52 /// Prints out the pass in the textual representation of pipelines. If this is
53 /// an adaptor pass, print with the op_name(sub_pass,...) format.
54 void Pass::printAsTextualPipeline(raw_ostream &os) {
55  // Special case for adaptors to use the 'op_name(sub_passes)' format.
56  if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(this)) {
57  llvm::interleaveComma(adaptor->getPassManagers(), os,
58  [&](OpPassManager &pm) {
59  os << pm.getOpName() << "(";
60  pm.printAsTextualPipeline(os);
61  os << ")";
62  });
63  return;
64  }
65  // Otherwise, print the pass argument followed by its options. If the pass
66  // doesn't have an argument, print the name of the pass to give some indicator
67  // of what pass was run.
68  StringRef argument = getArgument();
69  if (!argument.empty())
70  os << argument;
71  else
72  os << "unknown<" << getName() << ">";
73  passOptions.print(os);
74 }
75 
76 //===----------------------------------------------------------------------===//
77 // OpPassManagerImpl
78 //===----------------------------------------------------------------------===//
79 
80 namespace mlir {
81 namespace detail {
83  OpPassManagerImpl(StringAttr identifier, OpPassManager::Nesting nesting)
84  : name(identifier.str()), identifier(identifier),
85  initializationGeneration(0), nesting(nesting) {}
86  OpPassManagerImpl(StringRef name, OpPassManager::Nesting nesting)
87  : name(name), initializationGeneration(0), nesting(nesting) {}
88 
89  /// Merge the passes of this pass manager into the one provided.
90  void mergeInto(OpPassManagerImpl &rhs);
91 
92  /// Nest a new operation pass manager for the given operation kind under this
93  /// pass manager.
94  OpPassManager &nest(StringAttr nestedName);
95  OpPassManager &nest(StringRef nestedName);
96 
97  /// Add the given pass to this pass manager. If this pass has a concrete
98  /// operation type, it must be the same type as this pass manager.
99  void addPass(std::unique_ptr<Pass> pass);
100 
101  /// Clear the list of passes in this pass manager, other options are
102  /// preserved.
103  void clear();
104 
105  /// Coalesce adjacent AdaptorPasses into one large adaptor. This runs
106  /// recursively through the pipeline graph.
107  void coalesceAdjacentAdaptorPasses();
108 
109  /// Return the operation name of this pass manager as an identifier.
110  StringAttr getOpName(MLIRContext &context) {
111  if (!identifier)
112  identifier = StringAttr::get(&context, name);
113  return *identifier;
114  }
115 
116  /// The name of the operation that passes of this pass manager operate on.
117  std::string name;
118 
119  /// The cached identifier (internalized in the context) for the name of the
120  /// operation that passes of this pass manager operate on.
122 
123  /// The set of passes to run as part of this pass manager.
124  std::vector<std::unique_ptr<Pass>> passes;
125 
126  /// The current initialization generation of this pass manager. This is used
127  /// to indicate when a pass manager should be reinitialized.
129 
130  /// Control the implicit nesting of passes that mismatch the name set for this
131  /// OpPassManager.
133 };
134 } // namespace detail
135 } // namespace mlir
136 
138  assert(name == rhs.name && "merging unrelated pass managers");
139  for (auto &pass : passes)
140  rhs.passes.push_back(std::move(pass));
141  passes.clear();
142 }
143 
144 OpPassManager &OpPassManagerImpl::nest(StringAttr nestedName) {
145  OpPassManager nested(nestedName, nesting);
146  auto *adaptor = new OpToOpPassAdaptor(std::move(nested));
147  addPass(std::unique_ptr<Pass>(adaptor));
148  return adaptor->getPassManagers().front();
149 }
150 
151 OpPassManager &OpPassManagerImpl::nest(StringRef nestedName) {
152  OpPassManager nested(nestedName, nesting);
153  auto *adaptor = new OpToOpPassAdaptor(std::move(nested));
154  addPass(std::unique_ptr<Pass>(adaptor));
155  return adaptor->getPassManagers().front();
156 }
157 
158 void OpPassManagerImpl::addPass(std::unique_ptr<Pass> pass) {
159  // If this pass runs on a different operation than this pass manager, then
160  // implicitly nest a pass manager for this operation if enabled.
161  auto passOpName = pass->getOpName();
162  if (passOpName && passOpName->str() != name) {
163  if (nesting == OpPassManager::Nesting::Implicit)
164  return nest(*passOpName).addPass(std::move(pass));
165  llvm::report_fatal_error(llvm::Twine("Can't add pass '") + pass->getName() +
166  "' restricted to '" + *passOpName +
167  "' on a PassManager intended to run on '" + name +
168  "', did you intend to nest?");
169  }
170 
171  passes.emplace_back(std::move(pass));
172 }
173 
174 void OpPassManagerImpl::clear() { passes.clear(); }
175 
177  // Bail out early if there are no adaptor passes.
178  if (llvm::none_of(passes, [](std::unique_ptr<Pass> &pass) {
179  return isa<OpToOpPassAdaptor>(pass.get());
180  }))
181  return;
182 
183  // Walk the pass list and merge adjacent adaptors.
184  OpToOpPassAdaptor *lastAdaptor = nullptr;
185  for (auto &passe : passes) {
186  // Check to see if this pass is an adaptor.
187  if (auto *currentAdaptor = dyn_cast<OpToOpPassAdaptor>(passe.get())) {
188  // If it is the first adaptor in a possible chain, remember it and
189  // continue.
190  if (!lastAdaptor) {
191  lastAdaptor = currentAdaptor;
192  continue;
193  }
194 
195  // Otherwise, merge into the existing adaptor and delete the current one.
196  currentAdaptor->mergeInto(*lastAdaptor);
197  passe.reset();
198  } else if (lastAdaptor) {
199  // If this pass is not an adaptor, then coalesce and forget any existing
200  // adaptor.
201  for (auto &pm : lastAdaptor->getPassManagers())
202  pm.getImpl().coalesceAdjacentAdaptorPasses();
203  lastAdaptor = nullptr;
204  }
205  }
206 
207  // If there was an adaptor at the end of the manager, coalesce it as well.
208  if (lastAdaptor) {
209  for (auto &pm : lastAdaptor->getPassManagers())
210  pm.getImpl().coalesceAdjacentAdaptorPasses();
211  }
212 
213  // Now that the adaptors have been merged, erase the empty slot corresponding
214  // to the merged adaptors that were nulled-out in the loop above.
215  llvm::erase_if(passes, std::logical_not<std::unique_ptr<Pass>>());
216 }
217 
218 //===----------------------------------------------------------------------===//
219 // OpPassManager
220 //===----------------------------------------------------------------------===//
221 
222 OpPassManager::OpPassManager(StringAttr name, Nesting nesting)
223  : impl(new OpPassManagerImpl(name, nesting)) {}
224 OpPassManager::OpPassManager(StringRef name, Nesting nesting)
225  : impl(new OpPassManagerImpl(name, nesting)) {}
227 OpPassManager::OpPassManager(const OpPassManager &rhs) { *this = rhs; }
229  impl = std::make_unique<OpPassManagerImpl>(rhs.impl->name, rhs.impl->nesting);
230  impl->initializationGeneration = rhs.impl->initializationGeneration;
231  for (auto &pass : rhs.impl->passes) {
232  auto newPass = pass->clone();
233  newPass->threadingSibling = pass.get();
234  impl->passes.push_back(std::move(newPass));
235  }
236  return *this;
237 }
238 
240 
242  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();
243 }
245  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();
246 }
247 
249  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();
250 }
252  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();
253 }
254 
255 /// Nest a new operation pass manager for the given operation kind under this
256 /// pass manager.
257 OpPassManager &OpPassManager::nest(StringAttr nestedName) {
258  return impl->nest(nestedName);
259 }
260 OpPassManager &OpPassManager::nest(StringRef nestedName) {
261  return impl->nest(nestedName);
262 }
263 
264 /// Add the given pass to this pass manager. If this pass has a concrete
265 /// operation type, it must be the same type as this pass manager.
266 void OpPassManager::addPass(std::unique_ptr<Pass> pass) {
267  impl->addPass(std::move(pass));
268 }
269 
270 void OpPassManager::clear() { impl->clear(); }
271 
272 /// Returns the number of passes held by this manager.
273 size_t OpPassManager::size() const { return impl->passes.size(); }
274 
275 /// Returns the internal implementation instance.
277 
278 /// Return the operation name that this pass manager operates on.
279 StringRef OpPassManager::getOpName() const { return impl->name; }
280 
281 /// Return the operation name that this pass manager operates on.
282 StringAttr OpPassManager::getOpName(MLIRContext &context) const {
283  return impl->getOpName(context);
284 }
285 
286 /// Prints out the given passes as the textual representation of a pipeline.
287 static void printAsTextualPipeline(ArrayRef<std::unique_ptr<Pass>> passes,
288  raw_ostream &os) {
289  llvm::interleaveComma(passes, os, [&](const std::unique_ptr<Pass> &pass) {
290  pass->printAsTextualPipeline(os);
291  });
292 }
293 
294 /// Prints out the passes of the pass manager as the textual representation
295 /// of pipelines.
297  ::printAsTextualPipeline(impl->passes, os);
298 }
299 
301  llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes: ";
302  ::printAsTextualPipeline(impl->passes, llvm::errs());
303  llvm::errs() << "\n";
304 }
305 
307  DialectRegistry &dialects) {
308  for (const Pass &pass : pm.getPasses())
309  pass.getDependentDialects(dialects);
310 }
311 
313  registerDialectsForPipeline(*this, dialects);
314 }
315 
316 void OpPassManager::setNesting(Nesting nesting) { impl->nesting = nesting; }
317 
319 
320 LogicalResult OpPassManager::initialize(MLIRContext *context,
321  unsigned newInitGeneration) {
322  if (impl->initializationGeneration == newInitGeneration)
323  return success();
324  impl->initializationGeneration = newInitGeneration;
325  for (Pass &pass : getPasses()) {
326  // If this pass isn't an adaptor, directly initialize it.
327  auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
328  if (!adaptor) {
329  if (failed(pass.initialize(context)))
330  return failure();
331  continue;
332  }
333 
334  // Otherwise, initialize each of the adaptors pass managers.
335  for (OpPassManager &adaptorPM : adaptor->getPassManagers())
336  if (failed(adaptorPM.initialize(context, newInitGeneration)))
337  return failure();
338  }
339  return success();
340 }
341 
342 //===----------------------------------------------------------------------===//
343 // OpToOpPassAdaptor
344 //===----------------------------------------------------------------------===//
345 
346 LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op,
347  AnalysisManager am, bool verifyPasses,
348  unsigned parentInitGeneration) {
349  if (!op->isRegistered())
350  return op->emitOpError()
351  << "trying to schedule a pass on an unregistered operation";
353  return op->emitOpError() << "trying to schedule a pass on an operation not "
354  "marked as 'IsolatedFromAbove'";
355 
356  // Initialize the pass state with a callback for the pass to dynamically
357  // execute a pipeline on the currently visited operation.
359  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
360  pass};
361  auto dynamicPipelineCallback = [&](OpPassManager &pipeline,
362  Operation *root) -> LogicalResult {
363  if (!op->isAncestor(root))
364  return root->emitOpError()
365  << "Trying to schedule a dynamic pipeline on an "
366  "operation that isn't "
367  "nested under the current operation the pass is processing";
368  assert(pipeline.getOpName() == root->getName().getStringRef());
369 
370  // Before running, make sure to coalesce any adjacent pass adaptors in the
371  // pipeline.
373 
374  // Initialize the user provided pipeline and execute the pipeline.
375  if (failed(pipeline.initialize(root->getContext(), parentInitGeneration)))
376  return failure();
377  AnalysisManager nestedAm = root == op ? am : am.nest(root);
378  return OpToOpPassAdaptor::runPipeline(pipeline.getPasses(), root, nestedAm,
379  verifyPasses, parentInitGeneration,
380  pi, &parentInfo);
381  };
382  pass->passState.emplace(op, am, dynamicPipelineCallback);
383 
384  // Instrument before the pass has run.
385  if (pi)
386  pi->runBeforePass(pass, op);
387 
388  // Invoke the virtual runOnOperation method.
389  if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass))
390  adaptor->runOnOperation(verifyPasses);
391  else
392  pass->runOnOperation();
393  bool passFailed = pass->passState->irAndPassFailed.getInt();
394 
395  // Invalidate any non preserved analyses.
396  am.invalidate(pass->passState->preservedAnalyses);
397 
398  // When verifyPasses is specified, we run the verifier (unless the pass
399  // failed).
400  if (!passFailed && verifyPasses) {
401  bool runVerifierNow = true;
402  // Reduce compile time by avoiding running the verifier if the pass didn't
403  // change the IR since the last time the verifier was run:
404  //
405  // 1) If the pass said that it preserved all analyses then it can't have
406  // permuted the IR.
407  // 2) If we just ran an OpToOpPassAdaptor (e.g. to run function passes
408  // within a module) then each sub-unit will have been verified on the
409  // subunit (and those passes aren't allowed to modify the parent).
410  //
411  // We run these checks in EXPENSIVE_CHECKS mode out of caution.
412 #ifndef EXPENSIVE_CHECKS
413  runVerifierNow = !isa<OpToOpPassAdaptor>(pass) &&
414  !pass->passState->preservedAnalyses.isAll();
415 #endif
416  if (runVerifierNow)
417  passFailed = failed(verify(op));
418  }
419 
420  // Instrument after the pass has run.
421  if (pi) {
422  if (passFailed)
423  pi->runAfterPassFailed(pass, op);
424  else
425  pi->runAfterPass(pass, op);
426  }
427 
428  // Return if the pass signaled a failure.
429  return failure(passFailed);
430 }
431 
432 /// Run the given operation and analysis manager on a provided op pass manager.
433 LogicalResult OpToOpPassAdaptor::runPipeline(
435  AnalysisManager am, bool verifyPasses, unsigned parentInitGeneration,
436  PassInstrumentor *instrumentor,
437  const PassInstrumentation::PipelineParentInfo *parentInfo) {
438  assert((!instrumentor || parentInfo) &&
439  "expected parent info if instrumentor is provided");
440  auto scopeExit = llvm::make_scope_exit([&] {
441  // Clear out any computed operation analyses. These analyses won't be used
442  // any more in this pipeline, and this helps reduce the current working set
443  // of memory. If preserving these analyses becomes important in the future
444  // we can re-evaluate this.
445  am.clear();
446  });
447 
448  // Run the pipeline over the provided operation.
449  if (instrumentor)
450  instrumentor->runBeforePipeline(op->getName().getIdentifier(), *parentInfo);
451  for (Pass &pass : passes)
452  if (failed(run(&pass, op, am, verifyPasses, parentInitGeneration)))
453  return failure();
454  if (instrumentor)
455  instrumentor->runAfterPipeline(op->getName().getIdentifier(), *parentInfo);
456  return success();
457 }
458 
459 /// Find an operation pass manager that can operate on an operation of the given
460 /// type, or nullptr if one does not exist.
462  StringRef name) {
463  auto *it = llvm::find_if(
464  mgrs, [&](OpPassManager &mgr) { return mgr.getOpName() == name; });
465  return it == mgrs.end() ? nullptr : &*it;
466 }
467 
468 /// Find an operation pass manager that can operate on an operation of the given
469 /// type, or nullptr if one does not exist.
471  StringAttr name,
472  MLIRContext &context) {
473  auto *it = llvm::find_if(
474  mgrs, [&](OpPassManager &mgr) { return mgr.getOpName(context) == name; });
475  return it == mgrs.end() ? nullptr : &*it;
476 }
477 
478 OpToOpPassAdaptor::OpToOpPassAdaptor(OpPassManager &&mgr) {
479  mgrs.emplace_back(std::move(mgr));
480 }
481 
482 void OpToOpPassAdaptor::getDependentDialects(DialectRegistry &dialects) const {
483  for (auto &pm : mgrs)
484  pm.getDependentDialects(dialects);
485 }
486 
487 /// Merge the current pass adaptor into given 'rhs'.
488 void OpToOpPassAdaptor::mergeInto(OpToOpPassAdaptor &rhs) {
489  for (auto &pm : mgrs) {
490  // If an existing pass manager exists, then merge the given pass manager
491  // into it.
492  if (auto *existingPM = findPassManagerFor(rhs.mgrs, pm.getOpName())) {
493  pm.getImpl().mergeInto(existingPM->getImpl());
494  } else {
495  // Otherwise, add the given pass manager to the list.
496  rhs.mgrs.emplace_back(std::move(pm));
497  }
498  }
499  mgrs.clear();
500 
501  // After coalescing, sort the pass managers within rhs by name.
502  llvm::array_pod_sort(rhs.mgrs.begin(), rhs.mgrs.end(),
503  [](const OpPassManager *lhs, const OpPassManager *rhs) {
504  return lhs->getOpName().compare(rhs->getOpName());
505  });
506 }
507 
508 /// Returns the adaptor pass name.
509 std::string OpToOpPassAdaptor::getAdaptorName() {
510  std::string name = "Pipeline Collection : [";
511  llvm::raw_string_ostream os(name);
512  llvm::interleaveComma(getPassManagers(), os, [&](OpPassManager &pm) {
513  os << '\'' << pm.getOpName() << '\'';
514  });
515  os << ']';
516  return os.str();
517 }
518 
519 void OpToOpPassAdaptor::runOnOperation() {
520  llvm_unreachable(
521  "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor");
522 }
523 
524 /// Run the held pipeline over all nested operations.
525 void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) {
526  if (getContext().isMultithreadingEnabled())
527  runOnOperationAsyncImpl(verifyPasses);
528  else
529  runOnOperationImpl(verifyPasses);
530 }
531 
532 /// Run this pass adaptor synchronously.
533 void OpToOpPassAdaptor::runOnOperationImpl(bool verifyPasses) {
534  auto am = getAnalysisManager();
535  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
536  this};
537  auto *instrumentor = am.getPassInstrumentor();
538  for (auto &region : getOperation()->getRegions()) {
539  for (auto &block : region) {
540  for (auto &op : block) {
541  auto *mgr = findPassManagerFor(mgrs, op.getName().getIdentifier(),
542  *op.getContext());
543  if (!mgr)
544  continue;
545 
546  // Run the held pipeline over the current operation.
547  unsigned initGeneration = mgr->impl->initializationGeneration;
548  if (failed(runPipeline(mgr->getPasses(), &op, am.nest(&op),
549  verifyPasses, initGeneration, instrumentor,
550  &parentInfo)))
551  return signalPassFailure();
552  }
553  }
554  }
555 }
556 
557 /// Utility functor that checks if the two ranges of pass managers have a size
558 /// mismatch.
561  return lhs.size() != rhs.size() ||
562  llvm::any_of(llvm::seq<size_t>(0, lhs.size()),
563  [&](size_t i) { return lhs[i].size() != rhs[i].size(); });
564 }
565 
566 /// Run this pass adaptor synchronously.
567 void OpToOpPassAdaptor::runOnOperationAsyncImpl(bool verifyPasses) {
568  AnalysisManager am = getAnalysisManager();
569  MLIRContext *context = &getContext();
570 
571  // Create the async executors if they haven't been created, or if the main
572  // pipeline has changed.
573  if (asyncExecutors.empty() || hasSizeMismatch(asyncExecutors.front(), mgrs))
574  asyncExecutors.assign(context->getThreadPool().getThreadCount(), mgrs);
575 
576  // Run a prepass over the operation to collect the nested operations to
577  // execute over. This ensures that an analysis manager exists for each
578  // operation, as well as providing a queue of operations to execute over.
579  std::vector<std::pair<Operation *, AnalysisManager>> opAMPairs;
580  for (auto &region : getOperation()->getRegions()) {
581  for (auto &block : region) {
582  for (auto &op : block) {
583  // Add this operation iff the name matches any of the pass managers.
584  if (findPassManagerFor(mgrs, op.getName().getIdentifier(), *context))
585  opAMPairs.emplace_back(&op, am.nest(&op));
586  }
587  }
588  }
589 
590  // Get the current thread for this adaptor.
591  PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(),
592  this};
593  auto *instrumentor = am.getPassInstrumentor();
594 
595  // An atomic failure variable for the async executors.
596  std::vector<std::atomic<bool>> activePMs(asyncExecutors.size());
597  std::fill(activePMs.begin(), activePMs.end(), false);
598  auto processFn = [&](auto &opPMPair) {
599  // Find a pass manager for this operation.
600  auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
601  bool expectedInactive = false;
602  return isActive.compare_exchange_strong(expectedInactive, true);
603  });
604  unsigned pmIndex = it - activePMs.begin();
605 
606  // Get the pass manager for this operation and execute it.
607  auto *pm =
608  findPassManagerFor(asyncExecutors[pmIndex],
609  opPMPair.first->getName().getIdentifier(), *context);
610  assert(pm && "expected valid pass manager for operation");
611 
612  unsigned initGeneration = pm->impl->initializationGeneration;
613  LogicalResult pipelineResult =
614  runPipeline(pm->getPasses(), opPMPair.first, opPMPair.second,
615  verifyPasses, initGeneration, instrumentor, &parentInfo);
616 
617  // Reset the active bit for this pass manager.
618  activePMs[pmIndex].store(false);
619  return pipelineResult;
620  };
621 
622  // Signal a failure if any of the executors failed.
623  if (failed(failableParallelForEach(context, opAMPairs, processFn)))
624  signalPassFailure();
625 }
626 
627 //===----------------------------------------------------------------------===//
628 // PassManager
629 //===----------------------------------------------------------------------===//
630 
632  StringRef operationName)
633  : OpPassManager(StringAttr::get(ctx, operationName), nesting), context(ctx),
634  initializationKey(DenseMapInfo<llvm::hash_code>::getTombstoneKey()),
635  passTiming(false), verifyPasses(true) {}
636 
637 PassManager::~PassManager() = default;
638 
639 void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; }
640 
641 /// Run the passes within this manager on the provided operation.
643  MLIRContext *context = getContext();
644  assert(op->getName().getIdentifier() == getOpName(*context) &&
645  "operation has a different name than the PassManager or is from a "
646  "different context");
647 
648  // Before running, make sure to coalesce any adjacent pass adaptors in the
649  // pipeline.
651 
652  // Register all dialects for the current pipeline.
653  DialectRegistry dependentDialects;
654  getDependentDialects(dependentDialects);
655  context->appendDialectRegistry(dependentDialects);
656  for (StringRef name : dependentDialects.getDialectNames())
657  context->getOrLoadDialect(name);
658 
659  // Initialize all of the passes within the pass manager with a new generation.
660  llvm::hash_code newInitKey = context->getRegistryHash();
661  if (newInitKey != initializationKey) {
662  if (failed(initialize(context, impl->initializationGeneration + 1)))
663  return failure();
664  initializationKey = newInitKey;
665  }
666 
667  // Construct a top level analysis manager for the pipeline.
668  ModuleAnalysisManager am(op, instrumentor.get());
669 
670  // Notify the context that we start running a pipeline for book keeping.
671  context->enterMultiThreadedExecution();
672 
673  // If reproducer generation is enabled, run the pass manager with crash
674  // handling enabled.
675  LogicalResult result =
676  crashReproGenerator ? runWithCrashRecovery(op, am) : runPasses(op, am);
677 
678  // Notify the context that the run is done.
679  context->exitMultiThreadedExecution();
680 
681  // Dump all of the pass statistics if necessary.
682  if (passStatisticsMode)
683  dumpStatistics();
684  return result;
685 }
686 
687 /// Add the provided instrumentation to the pass manager.
688 void PassManager::addInstrumentation(std::unique_ptr<PassInstrumentation> pi) {
689  if (!instrumentor)
690  instrumentor = std::make_unique<PassInstrumentor>();
691 
692  instrumentor->addInstrumentation(std::move(pi));
693 }
694 
695 LogicalResult PassManager::runPasses(Operation *op, AnalysisManager am) {
696  return OpToOpPassAdaptor::runPipeline(getPasses(), op, am, verifyPasses,
697  impl->initializationGeneration);
698 }
699 
700 //===----------------------------------------------------------------------===//
701 // AnalysisManager
702 //===----------------------------------------------------------------------===//
703 
704 /// Get an analysis manager for the given operation, which must be a proper
705 /// descendant of the current operation represented by this analysis manager.
707  Operation *currentOp = impl->getOperation();
708  assert(currentOp->isProperAncestor(op) &&
709  "expected valid descendant operation");
710 
711  // Check for the base case where the provided operation is immediately nested.
712  if (currentOp == op->getParentOp())
713  return nestImmediate(op);
714 
715  // Otherwise, we need to collect all ancestors up to the current operation.
716  SmallVector<Operation *, 4> opAncestors;
717  do {
718  opAncestors.push_back(op);
719  op = op->getParentOp();
720  } while (op != currentOp);
721 
722  AnalysisManager result = *this;
723  for (Operation *op : llvm::reverse(opAncestors))
724  result = result.nestImmediate(op);
725  return result;
726 }
727 
728 /// Get an analysis manager for the given immediately nested child operation.
729 AnalysisManager AnalysisManager::nestImmediate(Operation *op) {
730  assert(impl->getOperation() == op->getParentOp() &&
731  "expected immediate child operation");
732 
733  auto it = impl->childAnalyses.find(op);
734  if (it == impl->childAnalyses.end())
735  it = impl->childAnalyses
736  .try_emplace(op, std::make_unique<NestedAnalysisMap>(op, impl))
737  .first;
738  return {it->second.get()};
739 }
740 
741 /// Invalidate any non preserved analyses.
743  const detail::PreservedAnalyses &pa) {
744  // If all analyses were preserved, then there is nothing to do here.
745  if (pa.isAll())
746  return;
747 
748  // Invalidate the analyses for the current operation directly.
749  analyses.invalidate(pa);
750 
751  // If no analyses were preserved, then just simply clear out the child
752  // analysis results.
753  if (pa.isNone()) {
754  childAnalyses.clear();
755  return;
756  }
757 
758  // Otherwise, invalidate each child analysis map.
759  SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this);
760  while (!mapsToInvalidate.empty()) {
761  auto *map = mapsToInvalidate.pop_back_val();
762  for (auto &analysisPair : map->childAnalyses) {
763  analysisPair.second->invalidate(pa);
764  if (!analysisPair.second->childAnalyses.empty())
765  mapsToInvalidate.push_back(analysisPair.second.get());
766  }
767  }
768 }
769 
770 //===----------------------------------------------------------------------===//
771 // PassInstrumentation
772 //===----------------------------------------------------------------------===//
773 
775 
776 //===----------------------------------------------------------------------===//
777 // PassInstrumentor
778 //===----------------------------------------------------------------------===//
779 
780 namespace mlir {
781 namespace detail {
783  /// Mutex to keep instrumentation access thread-safe.
785 
786  /// Set of registered instrumentations.
787  std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;
788 };
789 } // namespace detail
790 } // namespace mlir
791 
794 
795 /// See PassInstrumentation::runBeforePipeline for details.
797  StringAttr name,
798  const PassInstrumentation::PipelineParentInfo &parentInfo) {
799  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
800  for (auto &instr : impl->instrumentations)
801  instr->runBeforePipeline(name, parentInfo);
802 }
803 
804 /// See PassInstrumentation::runAfterPipeline for details.
806  StringAttr name,
807  const PassInstrumentation::PipelineParentInfo &parentInfo) {
808  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
809  for (auto &instr : llvm::reverse(impl->instrumentations))
810  instr->runAfterPipeline(name, parentInfo);
811 }
812 
813 /// See PassInstrumentation::runBeforePass for details.
815  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
816  for (auto &instr : impl->instrumentations)
817  instr->runBeforePass(pass, op);
818 }
819 
820 /// See PassInstrumentation::runAfterPass for details.
822  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
823  for (auto &instr : llvm::reverse(impl->instrumentations))
824  instr->runAfterPass(pass, op);
825 }
826 
827 /// See PassInstrumentation::runAfterPassFailed for details.
829  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
830  for (auto &instr : llvm::reverse(impl->instrumentations))
831  instr->runAfterPassFailed(pass, op);
832 }
833 
834 /// See PassInstrumentation::runBeforeAnalysis for details.
836  Operation *op) {
837  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
838  for (auto &instr : impl->instrumentations)
839  instr->runBeforeAnalysis(name, id, op);
840 }
841 
842 /// See PassInstrumentation::runAfterAnalysis for details.
844  Operation *op) {
845  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
846  for (auto &instr : llvm::reverse(impl->instrumentations))
847  instr->runAfterAnalysis(name, id, op);
848 }
849 
850 /// Add the given instrumentation to the collection.
852  std::unique_ptr<PassInstrumentation> pi) {
853  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
854  impl->instrumentations.emplace_back(std::move(pi));
855 }
OpPassManager & nest()
Definition: PassManager.h:80
Nesting getNesting()
Return the current nesting mode.
Definition: Pass.cpp:318
Include the generated interface declarations.
LogicalResult run(Operation *op)
Run the passes within this manager on the provided operation.
Definition: Pass.cpp:642
OpPassManager::Nesting nesting
Control the implicit nesting of passes that mismatch the name set for this OpPassManager.
Definition: Pass.cpp:132
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...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
This struct represents information related to the parent pass of pipeline.
bool isAll() const
Returns true if all analyses were marked preserved.
StringAttr getOpName(MLIRContext &context)
Return the operation name of this pass manager as an identifier.
Definition: Pass.cpp:110
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
Definition: Operation.h:145
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:559
void mergeInto(OpToOpPassAdaptor &rhs)
Merge the current pass adaptor into given &#39;rhs&#39;.
Definition: Pass.cpp:488
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
Definition: Pass.cpp:688
void runAfterAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runAfterAnalysis for details.
Definition: Pass.cpp:843
MLIRContext * getContext() const
Return an instance of the context.
Definition: PassManager.h:189
LogicalResult verify(Operation *op)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs, on this operation and any nested operations.
Definition: Verifier.cpp:353
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context...
StringAttr getIdentifier() const
Return the name of this operation as a StringAttr.
static OpPassManager * findPassManagerFor(MutableArrayRef< OpPassManager > mgrs, StringRef name)
Find an operation pass manager that can operate on an operation of the given type, or nullptr if one does not exist.
Definition: Pass.cpp:461
PassInstrumentor * getPassInstrumentor() const
Returns a pass instrumentation object for the current operation.
This class represents an analysis manager for a particular operation instance.
void enterMultiThreadedExecution()
These APIs are tracking whether the context will be used in a multithreading environment: this has no...
Optional< StringAttr > identifier
The cached identifier (internalized in the context) for the name of the operation that passes of this...
Definition: Pass.cpp:121
iterator_range< pass_iterator > getPasses()
Definition: PassManager.h:66
bool isRegistered()
Returns true if this operation has a registered operation description, otherwise false.
Definition: Operation.h:67
pass_iterator end()
Definition: Pass.cpp:244
An adaptor pass used to run operation passes over nested operations.
Definition: PassDetail.h:22
virtual ~PassInstrumentation()=0
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:52
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:99
LogicalResult failableParallelForEach(MLIRContext *context, IteratorT begin, IteratorT end, FuncT &&func)
Invoke the given function on the elements between [begin, end) asynchronously.
Definition: Threading.h:36
size_t size() const
Returns the number of passes held by this manager.
Definition: Pass.cpp:273
An analysis manager class specifically for the top-level operation.
OpPassManager & operator=(const OpPassManager &rhs)
Definition: Pass.cpp:228
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
void copyOptionValuesFrom(const Pass *other)
Copy the option values from &#39;other&#39;, which is another instance of this pass.
Definition: Pass.cpp:48
void coalesceAdjacentAdaptorPasses()
Coalesce adjacent AdaptorPasses into one large adaptor.
Definition: Pass.cpp:176
virtual LogicalResult initializeOptions(StringRef options)
Attempt to initialize the options of this pass from the given string.
Definition: Pass.cpp:42
void mergeInto(OpPassManagerImpl &rhs)
Merge the passes of this pass manager into the one provided.
Definition: Pass.cpp:137
unsigned initializationGeneration
The current initialization generation of this pass manager.
Definition: Pass.cpp:128
StringRef getOpName() const
Return the operation name that this pass manager operates on.
Definition: Pass.cpp:279
StringAttr getOpName(MLIRContext &context) const
Return the operation name that this pass manager operates on.
Definition: Pass.cpp:282
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:470
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:117
void runAfterPass(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPass for details.
Definition: Pass.cpp:821
Optional< StringRef > getOpName() const
Returns the name of the operation that this pass operates on, or None if this is a generic OperationP...
Definition: Pass.h:86
A utility class to represent the analyses that are known to be preserved.
void runAfterPassFailed(Pass *pass, Operation *op)
See PassInstrumentation::runAfterPassFailed for details.
Definition: Pass.cpp:828
OpPassManagerImpl(StringAttr identifier, OpPassManager::Nesting nesting)
Definition: Pass.cpp:83
void clear()
Clear the pipeline, but not the other options set on this OpPassManager.
Definition: Pass.cpp:270
detail::OpPassManagerImpl & getImpl()
Returns the internal implementation instance.
Definition: Pass.cpp:276
void runBeforeAnalysis(StringRef name, TypeID id, Operation *op)
See PassInstrumentation::runBeforeAnalysis for details.
Definition: Pass.cpp:835
llvm::sys::SmartMutex< true > mutex
Mutex to keep instrumentation access thread-safe.
Definition: Pass.cpp:784
void exitMultiThreadedExecution()
void runBeforePipeline(StringAttr name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runBeforePipeline for details.
Definition: Pass.cpp:796
auto getDialectNames() const
Return the names of dialects known to this registry.
Definition: Dialect.h:353
std::string name
The name of the operation that passes of this pass manager operate on.
Definition: Pass.cpp:117
void invalidate(const PreservedAnalyses &pa)
Invalidate any non preserved analyses,.
pass_iterator begin()
Definition: Pass.cpp:241
static llvm::ManagedStatic< PassManagerOptions > options
static void registerDialectsForPipeline(const OpPassManager &pm, DialectRegistry &dialects)
Definition: Pass.cpp:306
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:92
llvm::pointee_iterator< ArrayRef< std::unique_ptr< Pass > >::const_iterator > const_pass_iterator
Definition: PassManager.h:69
This class holds a collection of PassInstrumentation objects, and invokes their respective call backs...
void clear()
Clear the list of passes in this pass manager, other options are preserved.
Definition: Pass.cpp:174
This class provides the API for ops that are known to be isolated from above.
void getDependentDialects(DialectRegistry &dialects) const
Register dependent dialects for the current pass manager.
Definition: Pass.cpp:312
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
Definition: Dialect.h:282
OpPassManagerImpl(StringRef name, OpPassManager::Nesting nesting)
Definition: Pass.cpp:86
std::vector< std::unique_ptr< Pass > > passes
The set of passes to run as part of this pass manager.
Definition: Pass.cpp:124
The abstract base pass class.
Definition: Pass.h:51
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
void printAsTextualPipeline(raw_ostream &os)
Prints out the passes of the pass manager as the textual representation of pipelines.
Definition: Pass.cpp:296
virtual void runOnOperation()=0
The polymorphic API that runs the pass over the currently held operation.
llvm::ThreadPool & getThreadPool()
Return the thread pool used by this context.
void clear()
Clear any held analyses.
PassManager(MLIRContext *ctx, Nesting nesting=Nesting::Explicit, StringRef operationName="builtin.module")
Create a new pass manager under the given context with a specific nesting style.
Definition: Pass.cpp:631
MutableArrayRef< OpPassManager > getPassManagers()
Returns the pass managers held by this adaptor.
Definition: PassDetail.h:36
void dump()
Raw dump of the pass manager to llvm::errs().
Definition: Pass.cpp:300
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition: Pass.cpp:266
OpPassManager(StringAttr name, Nesting nesting=Nesting::Explicit)
Definition: Pass.cpp:222
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "&#39;dim&#39; op " which is convenient for verifiers...
Definition: Operation.cpp:518
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:57
void enableVerifier(bool enabled=true)
Runs the verifier after each individual pass.
Definition: Pass.cpp:639
std::vector< std::unique_ptr< PassInstrumentation > > instrumentations
Set of registered instrumentations.
Definition: Pass.cpp:787
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:706
llvm::pointee_iterator< MutableArrayRef< std::unique_ptr< Pass > >::iterator > pass_iterator
Iterator over the passes in this pass manager.
Definition: PassManager.h:63
OpPassManager & nest(StringAttr nestedName)
Nest a new operation pass manager for the given operation kind under this pass manager.
Definition: Pass.cpp:144
void runAfterPipeline(StringAttr name, const PassInstrumentation::PipelineParentInfo &parentInfo)
See PassInstrumentation::runAfterPipeline for details.
Definition: Pass.cpp:805
bool isNone() const
Returns true if no analyses were marked preserved.
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
Definition: Operation.cpp:182
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the given instrumentation to the collection.
Definition: Pass.cpp:851
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition: Pass.cpp:158
void setNesting(Nesting nesting)
Enable or disable the implicit nesting on this particular PassManager.
Definition: Pass.cpp:316
void runBeforePass(Pass *pass, Operation *op)
See PassInstrumentation::runBeforePass for details.
Definition: Pass.cpp:814
void printAsTextualPipeline(raw_ostream &os)
Prints out the pass in the textual representation of pipelines.
Definition: Pass.cpp:54
This class represents a pass manager that runs passes on a specific operation type.
Definition: PassManager.h:51
void invalidate(const PreservedAnalyses &pa)
Invalidate any non preserved analyses.
Definition: Pass.cpp:742