brintos

brintos / llvm-project-archived public Read only

0
0
Text · 47.6 KiB · 75f8826 Raw
1281 lines · cpp
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-exception6//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"19#include "mlir/Support/FileUtilities.h"20#include "mlir/Support/IndentedOstream.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 32using namespace mlir;33using namespace mlir::detail;34 35//===----------------------------------------------------------------------===//36// PassExecutionAction37//===----------------------------------------------------------------------===//38 39PassExecutionAction::PassExecutionAction(ArrayRef<IRUnit> irUnits,40                                         const Pass &pass)41    : Base(irUnits), pass(pass) {}42 43void PassExecutionAction::print(raw_ostream &os) const {44  os << llvm::formatv("`{0}` running `{1}` on Operation `{2}`", tag,45                      pass.getName(), getOp()->getName());46}47 48Operation *PassExecutionAction::getOp() const {49  ArrayRef<IRUnit> irUnits = getContextIRUnits();50  return irUnits.empty() ? nullptr51                         : llvm::dyn_cast_if_present<Operation *>(irUnits[0]);52}53 54MLIR_DEFINE_EXPLICIT_TYPE_ID(::mlir::PassExecutionAction)55 56//===----------------------------------------------------------------------===//57// Pass58//===----------------------------------------------------------------------===//59 60/// Out of line virtual method to ensure vtables and metadata are emitted to a61/// single .o file.62void Pass::anchor() {}63 64/// Attempt to initialize the options of this pass from the given string.65LogicalResult Pass::initializeOptions(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 this77/// pass.78void 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 is83/// an adaptor pass, print its pass managers. When `pretty` is true, the84/// printed pipeline is formatted for readability.85void 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 pass99  // doesn't have an argument, print the name of the pass to give some indicator100  // of what pass was run.101  StringRef argument = getArgument();102  if (!argument.empty())103    os << argument;104  else105    os << "unknown<" << getName() << ">";106  passOptions.print(os);107}108 109//===----------------------------------------------------------------------===//110// OpPassManagerImpl111//===----------------------------------------------------------------------===//112 113namespace mlir {114namespace detail {115struct OpPassManagerImpl {116  OpPassManagerImpl(OperationName opName, OpPassManager::Nesting nesting)117      : name(opName.getStringRef().str()), opName(opName),118        initializationGeneration(0), nesting(nesting) {}119  OpPassManagerImpl(StringRef name, OpPassManager::Nesting nesting)120      : name(name == OpPassManager::getAnyOpAnchorName() ? "" : name.str()),121        initializationGeneration(0), nesting(nesting) {}122  OpPassManagerImpl(OpPassManager::Nesting nesting)123      : initializationGeneration(0), nesting(nesting) {}124  OpPassManagerImpl(const OpPassManagerImpl &rhs)125      : name(rhs.name), opName(rhs.opName),126        initializationGeneration(rhs.initializationGeneration),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 this139  /// pass manager.140  OpPassManager &nest(OperationName nestedName) {141    return nest(OpPassManager(nestedName, nesting));142  }143  OpPassManager &nest(StringRef nestedName) {144    return nest(OpPassManager(nestedName, nesting));145  }146  OpPassManager &nestAny() { return nest(OpPassManager(nesting)); }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 concrete152  /// 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 are156  /// preserved.157  void clear();158 159  /// Finalize the pass list in preparation for execution. This includes160  /// coalescing adjacent pass managers when possible, verifying scheduled161  /// 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 name176  /// of an operation, or the result of `getAnyOpAnchorName()` in the case of an177  /// 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 given183  /// operation type.184  bool canScheduleOn(MLIRContext &context, OperationName opName);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 the190  /// 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 used197  /// to indicate when a pass manager should be reinitialized.198  unsigned initializationGeneration;199 200  /// Control the implicit nesting of passes that mismatch the name set for this201  /// OpPassManager.202  OpPassManager::Nesting nesting;203};204} // namespace detail205} // namespace mlir206 207void OpPassManagerImpl::mergeInto(OpPassManagerImpl &rhs) {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 214OpPassManager &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 220void OpPassManagerImpl::addPass(std::unique_ptr<Pass> pass) {221  // If this pass runs on a different operation than this pass manager, then222  // 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 237void OpPassManagerImpl::clear() { passes.clear(); }238 239LogicalResult 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 and254      // 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 the262      // 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 corresponding287  // 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 current304  // 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 323bool OpPassManagerImpl::canScheduleOn(MLIRContext &context,324                                      OperationName opName) {325  // If this pass manager is op-specific, we simply check if the provided326  // 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 operation332  // 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// OpPassManager345//===----------------------------------------------------------------------===//346 347OpPassManager::OpPassManager(Nesting nesting)348    : impl(new OpPassManagerImpl(nesting)) {}349OpPassManager::OpPassManager(StringRef name, Nesting nesting)350    : impl(new OpPassManagerImpl(name, nesting)) {}351OpPassManager::OpPassManager(OperationName name, Nesting nesting)352    : impl(new OpPassManagerImpl(name, nesting)) {}353OpPassManager::OpPassManager(OpPassManager &&rhs) { *this = std::move(rhs); }354OpPassManager::OpPassManager(const OpPassManager &rhs) { *this = rhs; }355OpPassManager &OpPassManager::operator=(const OpPassManager &rhs) {356  impl = std::make_unique<OpPassManagerImpl>(*rhs.impl);357  return *this;358}359OpPassManager &OpPassManager::operator=(OpPassManager &&rhs) {360  impl = std::move(rhs.impl);361  return *this;362}363 364OpPassManager::~OpPassManager() = default;365 366OpPassManager::pass_iterator OpPassManager::begin() {367  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();368}369OpPassManager::pass_iterator OpPassManager::end() {370  return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end();371}372 373OpPassManager::const_pass_iterator OpPassManager::begin() const {374  return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin();375}376OpPassManager::const_pass_iterator OpPassManager::end() const {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 this381/// pass manager.382OpPassManager &OpPassManager::nest(OperationName nestedName) {383  return impl->nest(nestedName);384}385OpPassManager &OpPassManager::nest(StringRef nestedName) {386  return impl->nest(nestedName);387}388OpPassManager &OpPassManager::nestAny() { return impl->nestAny(); }389 390/// Add the given pass to this pass manager. If this pass has a concrete391/// operation type, it must be the same type as this pass manager.392void OpPassManager::addPass(std::unique_ptr<Pass> pass) {393  impl->addPass(std::move(pass));394}395 396void OpPassManager::clear() { impl->clear(); }397 398/// Returns the number of passes held by this manager.399size_t OpPassManager::size() const { return impl->passes.size(); }400 401/// Returns the internal implementation instance.402OpPassManagerImpl &OpPassManager::getImpl() { return *impl; }403 404/// Return the operation name that this pass manager operates on.405std::optional<StringRef> OpPassManager::getOpName() const {406  return impl->getOpName();407}408 409/// Return the operation name that this pass manager operates on.410std::optional<OperationName>411OpPassManager::getOpName(MLIRContext &context) const {412  return impl->getOpName(context);413}414 415StringRef OpPassManager::getOpAnchorName() const {416  return impl->getOpAnchorName();417}418 419/// Prints out the passes of the pass manager as the textual representation420/// of pipelines. When `pretty` is true, the printed pipeline is formatted for421/// readability.422void printAsTextualPipeline(423    raw_indented_ostream &os, StringRef anchorName,424    const llvm::iterator_range<OpPassManager::pass_iterator> &passes,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}445void printAsTextualPipeline(446    raw_ostream &os, StringRef anchorName,447    const llvm::iterator_range<OpPassManager::pass_iterator> &passes,448    bool pretty) {449  raw_indented_ostream indentedOS(os);450  printAsTextualPipeline(indentedOS, anchorName, passes, pretty);451}452void OpPassManager::printAsTextualPipeline(raw_ostream &os, bool pretty) const {453  StringRef anchorName = getOpAnchorName();454  raw_indented_ostream indentedOS(os);455  ::printAsTextualPipeline(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 462void OpPassManager::dump() {463  llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes:\n";464  printAsTextualPipeline(llvm::errs(), /*pretty=*/true);465  llvm::errs() << "\n";466}467 468static void registerDialectsForPipeline(const OpPassManager &pm,469                                        DialectRegistry &dialects) {470  for (const Pass &pass : pm.getPasses())471    pass.getDependentDialects(dialects);472}473 474void OpPassManager::getDependentDialects(DialectRegistry &dialects) const {475  registerDialectsForPipeline(*this, dialects);476}477 478void OpPassManager::setNesting(Nesting nesting) { impl->nesting = nesting; }479 480OpPassManager::Nesting OpPassManager::getNesting() { return impl->nesting; }481 482LogicalResult 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 526llvm::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// OpToOpPassAdaptor544//===----------------------------------------------------------------------===//545 546LogicalResult 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)) {563    return op->emitOpError() << "trying to schedule pass '" << pass->getName()564                             << "' on an unsupported operation";565  }566 567  // Initialize the pass state with a callback for the pass to dynamically568  // execute a pipeline on the currently visited operation.569  PassInstrumentor *pi = am.getPassInstrumentor();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;603  op->getContext()->executeAction<PassExecutionAction>(604      [&]() {605        // Invoke the virtual runOnOperation method.606        if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass))607          adaptor->runOnOperation(verifyPasses);608        else609          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 pass618  // failed).619  if (!passFailed && verifyPasses) {620    bool runVerifierNow = true;621 622    // If the pass is an adaptor pass, we don't run the verifier recursively623    // because the nested operations should have already been verified after624    // nested passes had run.625    bool runVerifierRecursively = !isa<OpToOpPassAdaptor>(pass);626 627    // Reduce compile time by avoiding running the verifier if the pass didn't628    // 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 have631    //     permuted the IR.632    //633    // We run these checks in EXPENSIVE_CHECKS mode out of caution.634#ifndef EXPENSIVE_CHECKS635    runVerifierNow = !pass->passState->preservedAnalyses.isAll();636#endif637    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    else646      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.654LogicalResult 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=" << verifyPasses662       << " 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 used669    // any more in this pipeline, and this helps reduce the current working set670    // of memory. If preserving these analyses becomes important in the future671    // 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 one698/// does not exist.699static OpPassManager *700findPassManagerWithAnchor(MutableArrayRef<OpPassManager> mgrs, StringRef name) {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 given717/// type, or nullptr if one does not exist.718static OpPassManager *findPassManagerFor(MutableArrayRef<OpPassManager> mgrs,719                                         OperationName name,720                                         MLIRContext &context) {721  LDBG(4) << "Looking for pass manager that can handle operation '" << name722          << "' 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 '" << name730            << "'";731    return nullptr;732  }733 734  LDBG(4) << "Found pass manager '" << it->getOpAnchorName()735          << "' that can handle operation '" << name << "'";736  return &*it;737}738 739OpToOpPassAdaptor::OpToOpPassAdaptor(OpPassManager &&mgr) {740  mgrs.emplace_back(std::move(mgr));741}742 743void OpToOpPassAdaptor::getDependentDialects(DialectRegistry &dialects) const {744  for (auto &pm : mgrs)745    pm.getDependentDialects(dialects);746}747 748LogicalResult 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 a757  // potential schedule conflict with the given `otherPMs`.758  auto hasScheduleConflictWith = [&](OpPassManager &genericPM,759                                     MutableArrayRef<OpPassManager> otherPMs) {760    return llvm::any_of(otherPMs, [&](OpPassManager &pm) {761      // If this is a non-generic pass manager, a conflict will arise if a762      // non-generic pass manager's operation name can be scheduled on the763      // 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 determine767      // when generic pass managers can be merged, so conservatively assume they768      // conflict.769      return true;770    });771  };772 773  // Check that if either adaptor has a generic pass manager, that pm is774  // 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 manager799    // 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.825std::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 835void OpToOpPassAdaptor::runOnOperation() {836  llvm_unreachable(837      "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor");838}839 840/// Run the held pipeline over all nested operations.841void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) {842  if (getContext().isMultithreadingEnabled())843    runOnOperationAsyncImpl(verifyPasses);844  else845    runOnOperationImpl(verifyPasses);846}847 848/// Run this pass adaptor synchronously.849void 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 " << processedOps894         << " operations";895}896 897/// Utility functor that checks if the two ranges of pass managers have a size898/// mismatch.899static bool hasSizeMismatch(ArrayRef<OpPassManager> lhs,900                            ArrayRef<OpPassManager> rhs) {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.907void 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 main920  // 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 be928  // 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 to942  // execute over. This ensures that an analysis manager exists for each943  // operation, as well as providing a queue of operations to execute over.944  std::vector<OpPMInfo> opInfos;945  DenseMap<OperationName, std::optional<unsigned>> knownOpPMIdx;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// PassManager1012//===----------------------------------------------------------------------===//1013 1014PassManager::PassManager(MLIRContext *ctx, StringRef operationName,1015                         Nesting nesting)1016    : OpPassManager(operationName, nesting), context(ctx), passTiming(false),1017      verifyPasses(true) {}1018 1019PassManager::PassManager(OperationName operationName, Nesting nesting)1020    : OpPassManager(operationName, nesting),1021      context(operationName.getContext()), passTiming(false),1022      verifyPasses(true) {}1023 1024PassManager::~PassManager() = default;1025 1026void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; }1027 1028/// Run the passes within this manager on the provided operation.1029LogicalResult PassManager::run(Operation *op) {1030  LDBG_OS([&](raw_ostream &os) {1031    os << "Starting PassManager run on operation '"1032       << OpWithFlags(op, OpPrintingFlags().skipRegions()) << "' with "1033       << size() << " passes, verifyPasses=" << verifyPasses << " pipeline: ";1034    printAsTextualPipeline(os, /*pretty=*/false);1035  });1036 1037  MLIRContext *context = getContext();1038  std::optional<OperationName> anchorOp = getOpName(*context);1039  if (anchorOp && anchorOp != op->getName()) {1040    return emitError(op->getLoc())1041           << "can't run '" << getOpAnchorName() << "' pass manager on '"1042           << op->getName() << "' op";1043  }1044 1045  // Register all dialects for the current pipeline.1046  LDBG(2) << "Registering dependent dialects for pipeline";1047  DialectRegistry dependentDialects;1048  getDependentDialects(dependentDialects);1049  context->appendDialectRegistry(dependentDialects);1050  for (StringRef name : dependentDialects.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 crash1087  // 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.1108void 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 1115LogicalResult 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// AnalysisManager1123//===----------------------------------------------------------------------===//1124 1125/// Get an analysis manager for the given operation, which must be a proper1126/// descendant of the current operation represented by this analysis manager.1127AnalysisManager AnalysisManager::nest(Operation *op) {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.1150AnalysisManager 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.1161void detail::NestedAnalysisMap::invalidate(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 child1171  // 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// PassInstrumentation1191//===----------------------------------------------------------------------===//1192 1193PassInstrumentation::~PassInstrumentation() = default;1194 1195void PassInstrumentation::runBeforePipeline(1196    std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}1197 1198void PassInstrumentation::runAfterPipeline(1199    std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {}1200 1201//===----------------------------------------------------------------------===//1202// PassInstrumentor1203//===----------------------------------------------------------------------===//1204 1205namespace mlir {1206namespace detail {1207struct PassInstrumentorImpl {1208  /// Mutex to keep instrumentation access thread-safe.1209  llvm::sys::SmartMutex<true> mutex;1210 1211  /// Set of registered instrumentations.1212  std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;1213};1214} // namespace detail1215} // namespace mlir1216 1217PassInstrumentor::PassInstrumentor() : impl(new PassInstrumentorImpl()) {}1218PassInstrumentor::~PassInstrumentor() = default;1219 1220/// See PassInstrumentation::runBeforePipeline for details.1221void PassInstrumentor::runBeforePipeline(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.1230void PassInstrumentor::runAfterPipeline(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.1239void PassInstrumentor::runBeforePass(Pass *pass, Operation *op) {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.1246void PassInstrumentor::runAfterPass(Pass *pass, Operation *op) {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.1253void PassInstrumentor::runAfterPassFailed(Pass *pass, Operation *op) {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.1260void PassInstrumentor::runBeforeAnalysis(StringRef name, TypeID id,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.1268void PassInstrumentor::runAfterAnalysis(StringRef name, TypeID id,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.1276void PassInstrumentor::addInstrumentation(1277    std::unique_ptr<PassInstrumentation> pi) {1278  llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);1279  impl->instrumentations.emplace_back(std::move(pi));1280}1281