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 ®ion : 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 ®ion : 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