148ccae24SRiver Riddle //===- Pass.cpp - Pass infrastructure implementation ----------------------===// 248ccae24SRiver Riddle // 330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information. 556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 648ccae24SRiver Riddle // 756222a06SMehdi Amini //===----------------------------------------------------------------------===// 848ccae24SRiver Riddle // 948ccae24SRiver Riddle // This file implements common pass infrastructure. 1048ccae24SRiver Riddle // 1148ccae24SRiver Riddle //===----------------------------------------------------------------------===// 1248ccae24SRiver Riddle 1348ccae24SRiver Riddle #include "mlir/Pass/Pass.h" 1443d0ca84SRiver Riddle #include "PassDetail.h" 15eaf7f6b6SRiver Riddle #include "mlir/IR/Diagnostics.h" 165c036e68SRiver Riddle #include "mlir/IR/Dialect.h" 1736d3efeaSRiver Riddle #include "mlir/IR/OpDefinition.h" 186569cf2aSRiver Riddle #include "mlir/IR/Threading.h" 1957818885SStephen Neuendorffer #include "mlir/IR/Verifier.h" 207a7dcc17SRiver Riddle #include "mlir/Support/FileUtilities.h" 21809b4403SMehdi Amini #include "llvm/ADT/Hashing.h" 22c900d499SChristian Sigg #include "llvm/ADT/STLExtras.h" 236c05ca21SMehdi Amini #include "llvm/ADT/ScopeExit.h" 24af45236cSRiver Riddle #include "llvm/Support/CommandLine.h" 257a7dcc17SRiver Riddle #include "llvm/Support/CrashRecoveryContext.h" 266e983ae8SRiver Riddle #include "llvm/Support/Mutex.h" 27e62ff42fSRiver Riddle #include "llvm/Support/Signals.h" 28af45236cSRiver Riddle #include "llvm/Support/Threading.h" 297a7dcc17SRiver Riddle #include "llvm/Support/ToolOutputFile.h" 30a1fe1f5fSKazu Hirata #include <optional> 3148ccae24SRiver Riddle 3248ccae24SRiver Riddle using namespace mlir; 33300e4126SRiver Riddle using namespace mlir::detail; 34300e4126SRiver Riddle 35300e4126SRiver Riddle //===----------------------------------------------------------------------===// 36930744fcSMehdi Amini // PassExecutionAction 37930744fcSMehdi Amini //===----------------------------------------------------------------------===// 38930744fcSMehdi Amini 3946708a5bSAman LaChapelle PassExecutionAction::PassExecutionAction(ArrayRef<IRUnit> irUnits, 4046708a5bSAman LaChapelle const Pass &pass) 4146708a5bSAman LaChapelle : Base(irUnits), pass(pass) {} 4246708a5bSAman LaChapelle 43930744fcSMehdi Amini void PassExecutionAction::print(raw_ostream &os) const { 44930744fcSMehdi Amini os << llvm::formatv("`{0}` running `{1}` on Operation `{2}`", tag, 45930744fcSMehdi Amini pass.getName(), getOp()->getName()); 46930744fcSMehdi Amini } 47930744fcSMehdi Amini 4846708a5bSAman LaChapelle Operation *PassExecutionAction::getOp() const { 4946708a5bSAman LaChapelle ArrayRef<IRUnit> irUnits = getContextIRUnits(); 5046708a5bSAman LaChapelle return irUnits.empty() ? nullptr 5146708a5bSAman LaChapelle : llvm::dyn_cast_if_present<Operation *>(irUnits[0]); 5246708a5bSAman LaChapelle } 5346708a5bSAman LaChapelle 54930744fcSMehdi Amini //===----------------------------------------------------------------------===// 55300e4126SRiver Riddle // Pass 56300e4126SRiver Riddle //===----------------------------------------------------------------------===// 5748ccae24SRiver Riddle 5848ccae24SRiver Riddle /// Out of line virtual method to ensure vtables and metadata are emitted to a 5948ccae24SRiver Riddle /// single .o file. 6048ccae24SRiver Riddle void Pass::anchor() {} 6148ccae24SRiver Riddle 6221610e66SRiver Riddle /// Attempt to initialize the options of this pass from the given string. 631079fc4fSIvan Butygin LogicalResult Pass::initializeOptions( 641079fc4fSIvan Butygin StringRef options, 651079fc4fSIvan Butygin function_ref<LogicalResult(const Twine &)> errorHandler) { 661079fc4fSIvan Butygin std::string errStr; 671079fc4fSIvan Butygin llvm::raw_string_ostream os(errStr); 681079fc4fSIvan Butygin if (failed(passOptions.parseFromString(options, os))) { 691079fc4fSIvan Butygin return errorHandler(errStr); 701079fc4fSIvan Butygin } 711079fc4fSIvan Butygin return success(); 7221610e66SRiver Riddle } 7321610e66SRiver Riddle 7421610e66SRiver Riddle /// Copy the option values from 'other', which is another instance of this 7521610e66SRiver Riddle /// pass. 7621610e66SRiver Riddle void Pass::copyOptionValuesFrom(const Pass *other) { 7721610e66SRiver Riddle passOptions.copyOptionValuesFrom(other->passOptions); 7821610e66SRiver Riddle } 7921610e66SRiver Riddle 80ae6946ecSMLIR Team /// Prints out the pass in the textual representation of pipelines. If this is 81e874bbc2Srkayaith /// an adaptor pass, print its pass managers. 8281100138SRiver Riddle void Pass::printAsTextualPipeline(raw_ostream &os) { 83e874bbc2Srkayaith // Special case for adaptors to print its pass managers. 8456a69851SRiver Riddle if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(this)) { 850d8df980SRiver Riddle llvm::interleave( 860d8df980SRiver Riddle adaptor->getPassManagers(), 87e874bbc2Srkayaith [&](OpPassManager &pm) { pm.printAsTextualPipeline(os); }, 880d8df980SRiver Riddle [&] { os << ","; }); 8921610e66SRiver Riddle return; 90ae6946ecSMLIR Team } 917824768bSRiver Riddle // Otherwise, print the pass argument followed by its options. If the pass 927824768bSRiver Riddle // doesn't have an argument, print the name of the pass to give some indicator 937824768bSRiver Riddle // of what pass was run. 947824768bSRiver Riddle StringRef argument = getArgument(); 957824768bSRiver Riddle if (!argument.empty()) 967824768bSRiver Riddle os << argument; 9721610e66SRiver Riddle else 987824768bSRiver Riddle os << "unknown<" << getName() << ">"; 9921610e66SRiver Riddle passOptions.print(os); 100ae6946ecSMLIR Team } 101ae6946ecSMLIR Team 102300e4126SRiver Riddle //===----------------------------------------------------------------------===// 103e702875dSRiver Riddle // OpPassManagerImpl 1045c036e68SRiver Riddle //===----------------------------------------------------------------------===// 1055c036e68SRiver Riddle 1065c036e68SRiver Riddle namespace mlir { 1075c036e68SRiver Riddle namespace detail { 1085c036e68SRiver Riddle struct OpPassManagerImpl { 1099c9a4317SRiver Riddle OpPassManagerImpl(OperationName opName, OpPassManager::Nesting nesting) 110c2fb9c29SRiver Riddle : name(opName.getStringRef().str()), opName(opName), 1111ba5ea67SRiver Riddle initializationGeneration(0), nesting(nesting) {} 112008b9d97SMehdi Amini OpPassManagerImpl(StringRef name, OpPassManager::Nesting nesting) 113c2fb9c29SRiver Riddle : name(name == OpPassManager::getAnyOpAnchorName() ? "" : name.str()), 114c2fb9c29SRiver Riddle initializationGeneration(0), nesting(nesting) {} 115c2fb9c29SRiver Riddle OpPassManagerImpl(OpPassManager::Nesting nesting) 11687d627b6SKazu Hirata : initializationGeneration(0), nesting(nesting) {} 117c2fb9c29SRiver Riddle OpPassManagerImpl(const OpPassManagerImpl &rhs) 118c2fb9c29SRiver Riddle : name(rhs.name), opName(rhs.opName), 119c2fb9c29SRiver Riddle initializationGeneration(rhs.initializationGeneration), 120c2fb9c29SRiver Riddle nesting(rhs.nesting) { 121c2fb9c29SRiver Riddle for (const std::unique_ptr<Pass> &pass : rhs.passes) { 122c2fb9c29SRiver Riddle std::unique_ptr<Pass> newPass = pass->clone(); 123c2fb9c29SRiver Riddle newPass->threadingSibling = pass.get(); 124c2fb9c29SRiver Riddle passes.push_back(std::move(newPass)); 125c2fb9c29SRiver Riddle } 126c2fb9c29SRiver Riddle } 1275c036e68SRiver Riddle 128e702875dSRiver Riddle /// Merge the passes of this pass manager into the one provided. 129983382f1SRiver Riddle void mergeInto(OpPassManagerImpl &rhs); 130983382f1SRiver Riddle 131983382f1SRiver Riddle /// Nest a new operation pass manager for the given operation kind under this 132983382f1SRiver Riddle /// pass manager. 133c2fb9c29SRiver Riddle OpPassManager &nest(OperationName nestedName) { 134c2fb9c29SRiver Riddle return nest(OpPassManager(nestedName, nesting)); 135c2fb9c29SRiver Riddle } 136c2fb9c29SRiver Riddle OpPassManager &nest(StringRef nestedName) { 137c2fb9c29SRiver Riddle return nest(OpPassManager(nestedName, nesting)); 138c2fb9c29SRiver Riddle } 139c2fb9c29SRiver Riddle OpPassManager &nestAny() { return nest(OpPassManager(nesting)); } 140c2fb9c29SRiver Riddle 141c2fb9c29SRiver Riddle /// Nest the given pass manager under this pass manager. 142c2fb9c29SRiver Riddle OpPassManager &nest(OpPassManager &&nested); 1435c036e68SRiver Riddle 144983382f1SRiver Riddle /// Add the given pass to this pass manager. If this pass has a concrete 145983382f1SRiver Riddle /// operation type, it must be the same type as this pass manager. 146983382f1SRiver Riddle void addPass(std::unique_ptr<Pass> pass); 147983382f1SRiver Riddle 148a8c1d9d6SMehdi Amini /// Clear the list of passes in this pass manager, other options are 149a8c1d9d6SMehdi Amini /// preserved. 150a8c1d9d6SMehdi Amini void clear(); 151a8c1d9d6SMehdi Amini 1529c9a4317SRiver Riddle /// Finalize the pass list in preparation for execution. This includes 1539c9a4317SRiver Riddle /// coalescing adjacent pass managers when possible, verifying scheduled 1549c9a4317SRiver Riddle /// passes, etc. 1559c9a4317SRiver Riddle LogicalResult finalizePassList(MLIRContext *ctx); 156e702875dSRiver Riddle 1579c9a4317SRiver Riddle /// Return the operation name of this pass manager. 1580a81ace0SKazu Hirata std::optional<OperationName> getOpName(MLIRContext &context) { 159c2fb9c29SRiver Riddle if (!name.empty() && !opName) 1609c9a4317SRiver Riddle opName = OperationName(name, &context); 161c2fb9c29SRiver Riddle return opName; 162c0b6bc07SMehdi Amini } 1630a81ace0SKazu Hirata std::optional<StringRef> getOpName() const { 1640a81ace0SKazu Hirata return name.empty() ? std::optional<StringRef>() 1650a81ace0SKazu Hirata : std::optional<StringRef>(name); 166c2fb9c29SRiver Riddle } 167c2fb9c29SRiver Riddle 168c2fb9c29SRiver Riddle /// Return the name used to anchor this pass manager. This is either the name 169c2fb9c29SRiver Riddle /// of an operation, or the result of `getAnyOpAnchorName()` in the case of an 170c2fb9c29SRiver Riddle /// op-agnostic pass manager. 171c2fb9c29SRiver Riddle StringRef getOpAnchorName() const { 17230c67587SKazu Hirata return getOpName().value_or(OpPassManager::getAnyOpAnchorName()); 173c2fb9c29SRiver Riddle } 174c2fb9c29SRiver Riddle 175c2fb9c29SRiver Riddle /// Indicate if the current pass manager can be scheduled on the given 176c2fb9c29SRiver Riddle /// operation type. 177c2fb9c29SRiver Riddle bool canScheduleOn(MLIRContext &context, OperationName opName); 178983382f1SRiver Riddle 1795c036e68SRiver Riddle /// The name of the operation that passes of this pass manager operate on. 1804455f3ceSMehdi Amini std::string name; 1811284dc34SMehdi Amini 1829c9a4317SRiver Riddle /// The cached OperationName (internalized in the context) for the name of the 183c0b6bc07SMehdi Amini /// operation that passes of this pass manager operate on. 1840a81ace0SKazu Hirata std::optional<OperationName> opName; 1855c036e68SRiver Riddle 1865c036e68SRiver Riddle /// The set of passes to run as part of this pass manager. 1875c036e68SRiver Riddle std::vector<std::unique_ptr<Pass>> passes; 188008b9d97SMehdi Amini 1891ba5ea67SRiver Riddle /// The current initialization generation of this pass manager. This is used 1901ba5ea67SRiver Riddle /// to indicate when a pass manager should be reinitialized. 1911ba5ea67SRiver Riddle unsigned initializationGeneration; 1921ba5ea67SRiver Riddle 193008b9d97SMehdi Amini /// Control the implicit nesting of passes that mismatch the name set for this 194008b9d97SMehdi Amini /// OpPassManager. 195008b9d97SMehdi Amini OpPassManager::Nesting nesting; 1965c036e68SRiver Riddle }; 197be0a7e9fSMehdi Amini } // namespace detail 198be0a7e9fSMehdi Amini } // namespace mlir 1995c036e68SRiver Riddle 200983382f1SRiver Riddle void OpPassManagerImpl::mergeInto(OpPassManagerImpl &rhs) { 201983382f1SRiver Riddle assert(name == rhs.name && "merging unrelated pass managers"); 202983382f1SRiver Riddle for (auto &pass : passes) 203983382f1SRiver Riddle rhs.passes.push_back(std::move(pass)); 204983382f1SRiver Riddle passes.clear(); 205983382f1SRiver Riddle } 206983382f1SRiver Riddle 207c2fb9c29SRiver Riddle OpPassManager &OpPassManagerImpl::nest(OpPassManager &&nested) { 208983382f1SRiver Riddle auto *adaptor = new OpToOpPassAdaptor(std::move(nested)); 209983382f1SRiver Riddle addPass(std::unique_ptr<Pass>(adaptor)); 210983382f1SRiver Riddle return adaptor->getPassManagers().front(); 211983382f1SRiver Riddle } 212983382f1SRiver Riddle 213983382f1SRiver Riddle void OpPassManagerImpl::addPass(std::unique_ptr<Pass> pass) { 214983382f1SRiver Riddle // If this pass runs on a different operation than this pass manager, then 215008b9d97SMehdi Amini // implicitly nest a pass manager for this operation if enabled. 2160a81ace0SKazu Hirata std::optional<StringRef> pmOpName = getOpName(); 2170a81ace0SKazu Hirata std::optional<StringRef> passOpName = pass->getOpName(); 218c2fb9c29SRiver Riddle if (pmOpName && passOpName && *pmOpName != *passOpName) { 219008b9d97SMehdi Amini if (nesting == OpPassManager::Nesting::Implicit) 220983382f1SRiver Riddle return nest(*passOpName).addPass(std::move(pass)); 221008b9d97SMehdi Amini llvm::report_fatal_error(llvm::Twine("Can't add pass '") + pass->getName() + 222008b9d97SMehdi Amini "' restricted to '" + *passOpName + 223c2fb9c29SRiver Riddle "' on a PassManager intended to run on '" + 224c2fb9c29SRiver Riddle getOpAnchorName() + "', did you intend to nest?"); 225008b9d97SMehdi Amini } 226983382f1SRiver Riddle 227983382f1SRiver Riddle passes.emplace_back(std::move(pass)); 228983382f1SRiver Riddle } 229983382f1SRiver Riddle 230a8c1d9d6SMehdi Amini void OpPassManagerImpl::clear() { passes.clear(); } 231a8c1d9d6SMehdi Amini 2329c9a4317SRiver Riddle LogicalResult OpPassManagerImpl::finalizePassList(MLIRContext *ctx) { 233c2fb9c29SRiver Riddle auto finalizeAdaptor = [ctx](OpToOpPassAdaptor *adaptor) { 234c2fb9c29SRiver Riddle for (auto &pm : adaptor->getPassManagers()) 235c2fb9c29SRiver Riddle if (failed(pm.getImpl().finalizePassList(ctx))) 236c2fb9c29SRiver Riddle return failure(); 237c2fb9c29SRiver Riddle return success(); 238c2fb9c29SRiver Riddle }; 239c2fb9c29SRiver Riddle 240e702875dSRiver Riddle // Walk the pass list and merge adjacent adaptors. 24156a69851SRiver Riddle OpToOpPassAdaptor *lastAdaptor = nullptr; 2429c9a4317SRiver Riddle for (auto &pass : passes) { 243e702875dSRiver Riddle // Check to see if this pass is an adaptor. 2449c9a4317SRiver Riddle if (auto *currentAdaptor = dyn_cast<OpToOpPassAdaptor>(pass.get())) { 245e702875dSRiver Riddle // If it is the first adaptor in a possible chain, remember it and 246e702875dSRiver Riddle // continue. 247e702875dSRiver Riddle if (!lastAdaptor) { 248e702875dSRiver Riddle lastAdaptor = currentAdaptor; 249e702875dSRiver Riddle continue; 250e702875dSRiver Riddle } 251e702875dSRiver Riddle 252c2fb9c29SRiver Riddle // Otherwise, try to merge into the existing adaptor and delete the 253c2fb9c29SRiver Riddle // current one. If merging fails, just remember this as the last adaptor. 254c2fb9c29SRiver Riddle if (succeeded(currentAdaptor->tryMergeInto(ctx, *lastAdaptor))) 2559c9a4317SRiver Riddle pass.reset(); 256c2fb9c29SRiver Riddle else 257c2fb9c29SRiver Riddle lastAdaptor = currentAdaptor; 25881100138SRiver Riddle } else if (lastAdaptor) { 259c2fb9c29SRiver Riddle // If this pass isn't an adaptor, finalize it and forget the last adaptor. 260c2fb9c29SRiver Riddle if (failed(finalizeAdaptor(lastAdaptor))) 2619c9a4317SRiver Riddle return failure(); 262e702875dSRiver Riddle lastAdaptor = nullptr; 263e702875dSRiver Riddle } 264e702875dSRiver Riddle } 265e702875dSRiver Riddle 2669c9a4317SRiver Riddle // If there was an adaptor at the end of the manager, finalize it as well. 267c2fb9c29SRiver Riddle if (lastAdaptor && failed(finalizeAdaptor(lastAdaptor))) 2689c9a4317SRiver Riddle return failure(); 269e702875dSRiver Riddle 2709c9a4317SRiver Riddle // Now that the adaptors have been merged, erase any empty slots corresponding 271e702875dSRiver Riddle // to the merged adaptors that were nulled-out in the loop above. 272e702875dSRiver Riddle llvm::erase_if(passes, std::logical_not<std::unique_ptr<Pass>>()); 2739c9a4317SRiver Riddle 274c2fb9c29SRiver Riddle // If this is a op-agnostic pass manager, there is nothing left to do. 2750a81ace0SKazu Hirata std::optional<OperationName> rawOpName = getOpName(*ctx); 276c2fb9c29SRiver Riddle if (!rawOpName) 277c2fb9c29SRiver Riddle return success(); 278c2fb9c29SRiver Riddle 279c2fb9c29SRiver Riddle // Otherwise, verify that all of the passes are valid for the current 280c2fb9c29SRiver Riddle // operation anchor. 2810a81ace0SKazu Hirata std::optional<RegisteredOperationName> opName = 2820a81ace0SKazu Hirata rawOpName->getRegisteredInfo(); 2839c9a4317SRiver Riddle for (std::unique_ptr<Pass> &pass : passes) { 2849c9a4317SRiver Riddle if (opName && !pass->canScheduleOn(*opName)) { 2859c9a4317SRiver Riddle return emitError(UnknownLoc::get(ctx)) 2869c9a4317SRiver Riddle << "unable to schedule pass '" << pass->getName() 287c2fb9c29SRiver Riddle << "' on a PassManager intended to run on '" << getOpAnchorName() 288c2fb9c29SRiver Riddle << "'!"; 2899c9a4317SRiver Riddle } 2909c9a4317SRiver Riddle } 2919c9a4317SRiver Riddle return success(); 292e702875dSRiver Riddle } 293e702875dSRiver Riddle 294c2fb9c29SRiver Riddle bool OpPassManagerImpl::canScheduleOn(MLIRContext &context, 295c2fb9c29SRiver Riddle OperationName opName) { 296c2fb9c29SRiver Riddle // If this pass manager is op-specific, we simply check if the provided 297c2fb9c29SRiver Riddle // operation name is the same as this one. 2980a81ace0SKazu Hirata std::optional<OperationName> pmOpName = getOpName(context); 299c2fb9c29SRiver Riddle if (pmOpName) 300c2fb9c29SRiver Riddle return pmOpName == opName; 301c2fb9c29SRiver Riddle 302c2fb9c29SRiver Riddle // Otherwise, this is an op-agnostic pass manager. Check that the operation 303c2fb9c29SRiver Riddle // can be scheduled on all passes within the manager. 3040a81ace0SKazu Hirata std::optional<RegisteredOperationName> registeredInfo = 3050a81ace0SKazu Hirata opName.getRegisteredInfo(); 306c2fb9c29SRiver Riddle if (!registeredInfo || 307c2fb9c29SRiver Riddle !registeredInfo->hasTrait<OpTrait::IsIsolatedFromAbove>()) 308c2fb9c29SRiver Riddle return false; 309c2fb9c29SRiver Riddle return llvm::all_of(passes, [&](const std::unique_ptr<Pass> &pass) { 310c2fb9c29SRiver Riddle return pass->canScheduleOn(*registeredInfo); 311c2fb9c29SRiver Riddle }); 312c2fb9c29SRiver Riddle } 313c2fb9c29SRiver Riddle 314e702875dSRiver Riddle //===----------------------------------------------------------------------===// 315e702875dSRiver Riddle // OpPassManager 316e702875dSRiver Riddle //===----------------------------------------------------------------------===// 317e702875dSRiver Riddle 318c2fb9c29SRiver Riddle OpPassManager::OpPassManager(Nesting nesting) 319c2fb9c29SRiver Riddle : impl(new OpPassManagerImpl(nesting)) {} 320008b9d97SMehdi Amini OpPassManager::OpPassManager(StringRef name, Nesting nesting) 321008b9d97SMehdi Amini : impl(new OpPassManagerImpl(name, nesting)) {} 322c2fb9c29SRiver Riddle OpPassManager::OpPassManager(OperationName name, Nesting nesting) 323c2fb9c29SRiver Riddle : impl(new OpPassManagerImpl(name, nesting)) {} 32413bd4109Srkayaith OpPassManager::OpPassManager(OpPassManager &&rhs) { *this = std::move(rhs); } 325e702875dSRiver Riddle OpPassManager::OpPassManager(const OpPassManager &rhs) { *this = rhs; } 326e702875dSRiver Riddle OpPassManager &OpPassManager::operator=(const OpPassManager &rhs) { 327c2fb9c29SRiver Riddle impl = std::make_unique<OpPassManagerImpl>(*rhs.impl); 328e702875dSRiver Riddle return *this; 3295c036e68SRiver Riddle } 33013bd4109Srkayaith OpPassManager &OpPassManager::operator=(OpPassManager &&rhs) { 33113bd4109Srkayaith impl = std::move(rhs.impl); 33213bd4109Srkayaith return *this; 33313bd4109Srkayaith } 3345c036e68SRiver Riddle 335e5639b3fSMehdi Amini OpPassManager::~OpPassManager() = default; 3365c036e68SRiver Riddle 33733a64540SRiver Riddle OpPassManager::pass_iterator OpPassManager::begin() { 3386c05ca21SMehdi Amini return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin(); 33933a64540SRiver Riddle } 3406c05ca21SMehdi Amini OpPassManager::pass_iterator OpPassManager::end() { 3416c05ca21SMehdi Amini return MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end(); 3426c05ca21SMehdi Amini } 34333a64540SRiver Riddle 344f9dc2b70SMehdi Amini OpPassManager::const_pass_iterator OpPassManager::begin() const { 3456c05ca21SMehdi Amini return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin(); 346f9dc2b70SMehdi Amini } 347f9dc2b70SMehdi Amini OpPassManager::const_pass_iterator OpPassManager::end() const { 3486c05ca21SMehdi Amini return ArrayRef<std::unique_ptr<Pass>>{impl->passes}.end(); 349ed5fe209SRiver Riddle } 3506067cdebSRiver Riddle 3515c036e68SRiver Riddle /// Nest a new operation pass manager for the given operation kind under this 3525c036e68SRiver Riddle /// pass manager. 353c2fb9c29SRiver Riddle OpPassManager &OpPassManager::nest(OperationName nestedName) { 354983382f1SRiver Riddle return impl->nest(nestedName); 355ed5fe209SRiver Riddle } 3565c036e68SRiver Riddle OpPassManager &OpPassManager::nest(StringRef nestedName) { 357983382f1SRiver Riddle return impl->nest(nestedName); 3585c036e68SRiver Riddle } 359c2fb9c29SRiver Riddle OpPassManager &OpPassManager::nestAny() { return impl->nestAny(); } 3605c036e68SRiver Riddle 361cb1bcba6SRiver Riddle /// Add the given pass to this pass manager. If this pass has a concrete 362cb1bcba6SRiver Riddle /// operation type, it must be the same type as this pass manager. 3635c036e68SRiver Riddle void OpPassManager::addPass(std::unique_ptr<Pass> pass) { 364983382f1SRiver Riddle impl->addPass(std::move(pass)); 3655c036e68SRiver Riddle } 3665c036e68SRiver Riddle 367a8c1d9d6SMehdi Amini void OpPassManager::clear() { impl->clear(); } 368a8c1d9d6SMehdi Amini 3695c036e68SRiver Riddle /// Returns the number of passes held by this manager. 3705c036e68SRiver Riddle size_t OpPassManager::size() const { return impl->passes.size(); } 3715c036e68SRiver Riddle 3725c036e68SRiver Riddle /// Returns the internal implementation instance. 3735c036e68SRiver Riddle OpPassManagerImpl &OpPassManager::getImpl() { return *impl; } 3745c036e68SRiver Riddle 375c0b6bc07SMehdi Amini /// Return the operation name that this pass manager operates on. 3760a81ace0SKazu Hirata std::optional<StringRef> OpPassManager::getOpName() const { 377c2fb9c29SRiver Riddle return impl->getOpName(); 378c2fb9c29SRiver Riddle } 3795c036e68SRiver Riddle 3805c036e68SRiver Riddle /// Return the operation name that this pass manager operates on. 3810a81ace0SKazu Hirata std::optional<OperationName> 3820a81ace0SKazu Hirata OpPassManager::getOpName(MLIRContext &context) const { 383c0b6bc07SMehdi Amini return impl->getOpName(context); 384c0b6bc07SMehdi Amini } 3855c036e68SRiver Riddle 386c2fb9c29SRiver Riddle StringRef OpPassManager::getOpAnchorName() const { 387c2fb9c29SRiver Riddle return impl->getOpAnchorName(); 388c2fb9c29SRiver Riddle } 389c2fb9c29SRiver Riddle 390983382f1SRiver Riddle /// Prints out the passes of the pass manager as the textual representation 391983382f1SRiver Riddle /// of pipelines. 39203e29a49SPuyan Lotfi void printAsTextualPipeline( 39303e29a49SPuyan Lotfi raw_ostream &os, StringRef anchorName, 39403e29a49SPuyan Lotfi const llvm::iterator_range<OpPassManager::pass_iterator> &passes) { 39503e29a49SPuyan Lotfi os << anchorName << "("; 396e874bbc2Srkayaith llvm::interleave( 39703e29a49SPuyan Lotfi passes, [&](mlir::Pass &pass) { pass.printAsTextualPipeline(os); }, 398e874bbc2Srkayaith [&]() { os << ","; }); 399e874bbc2Srkayaith os << ")"; 400fe3c1195SMehdi Amini } 40103e29a49SPuyan Lotfi void OpPassManager::printAsTextualPipeline(raw_ostream &os) const { 40203e29a49SPuyan Lotfi StringRef anchorName = getOpAnchorName(); 40303e29a49SPuyan Lotfi ::printAsTextualPipeline( 40403e29a49SPuyan Lotfi os, anchorName, 40503e29a49SPuyan Lotfi {MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin(), 40603e29a49SPuyan Lotfi MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end()}); 40703e29a49SPuyan Lotfi } 408fe3c1195SMehdi Amini 409fe3c1195SMehdi Amini void OpPassManager::dump() { 410cad61e49Srkayaith llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes:\n"; 411e874bbc2Srkayaith printAsTextualPipeline(llvm::errs()); 412fe3c1195SMehdi Amini llvm::errs() << "\n"; 413983382f1SRiver Riddle } 414983382f1SRiver Riddle 415f9dc2b70SMehdi Amini static void registerDialectsForPipeline(const OpPassManager &pm, 416f9dc2b70SMehdi Amini DialectRegistry &dialects) { 417f9dc2b70SMehdi Amini for (const Pass &pass : pm.getPasses()) 418f9dc2b70SMehdi Amini pass.getDependentDialects(dialects); 419f9dc2b70SMehdi Amini } 420f9dc2b70SMehdi Amini 421f9dc2b70SMehdi Amini void OpPassManager::getDependentDialects(DialectRegistry &dialects) const { 422f9dc2b70SMehdi Amini registerDialectsForPipeline(*this, dialects); 423f9dc2b70SMehdi Amini } 424f9dc2b70SMehdi Amini 4251ba5ea67SRiver Riddle void OpPassManager::setNesting(Nesting nesting) { impl->nesting = nesting; } 4261ba5ea67SRiver Riddle 427a62d38a9SMehdi Amini OpPassManager::Nesting OpPassManager::getNesting() { return impl->nesting; } 428a62d38a9SMehdi Amini 429b1aaed02SMehdi Amini LogicalResult OpPassManager::initialize(MLIRContext *context, 4301ba5ea67SRiver Riddle unsigned newInitGeneration) { 4311ba5ea67SRiver Riddle if (impl->initializationGeneration == newInitGeneration) 432b1aaed02SMehdi Amini return success(); 4331ba5ea67SRiver Riddle impl->initializationGeneration = newInitGeneration; 4341ba5ea67SRiver Riddle for (Pass &pass : getPasses()) { 4351ba5ea67SRiver Riddle // If this pass isn't an adaptor, directly initialize it. 4361ba5ea67SRiver Riddle auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass); 4371ba5ea67SRiver Riddle if (!adaptor) { 438b1aaed02SMehdi Amini if (failed(pass.initialize(context))) 439b1aaed02SMehdi Amini return failure(); 4401ba5ea67SRiver Riddle continue; 4411ba5ea67SRiver Riddle } 4421ba5ea67SRiver Riddle 4431ba5ea67SRiver Riddle // Otherwise, initialize each of the adaptors pass managers. 4441ba5ea67SRiver Riddle for (OpPassManager &adaptorPM : adaptor->getPassManagers()) 445b1aaed02SMehdi Amini if (failed(adaptorPM.initialize(context, newInitGeneration))) 446b1aaed02SMehdi Amini return failure(); 4471ba5ea67SRiver Riddle } 448b1aaed02SMehdi Amini return success(); 4491ba5ea67SRiver Riddle } 450a62d38a9SMehdi Amini 451809b4403SMehdi Amini llvm::hash_code OpPassManager::hash() { 452ec5e947fSMehdi Amini llvm::hash_code hashCode{}; 453809b4403SMehdi Amini for (Pass &pass : getPasses()) { 454809b4403SMehdi Amini // If this pass isn't an adaptor, directly hash it. 455809b4403SMehdi Amini auto *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass); 456809b4403SMehdi Amini if (!adaptor) { 457809b4403SMehdi Amini hashCode = llvm::hash_combine(hashCode, &pass); 458809b4403SMehdi Amini continue; 459809b4403SMehdi Amini } 460809b4403SMehdi Amini // Otherwise, hash recursively each of the adaptors pass managers. 461809b4403SMehdi Amini for (OpPassManager &adaptorPM : adaptor->getPassManagers()) 462809b4403SMehdi Amini llvm::hash_combine(hashCode, adaptorPM.hash()); 463809b4403SMehdi Amini } 464809b4403SMehdi Amini return hashCode; 465809b4403SMehdi Amini } 466809b4403SMehdi Amini 467809b4403SMehdi Amini 468300e4126SRiver Riddle //===----------------------------------------------------------------------===// 4695c036e68SRiver Riddle // OpToOpPassAdaptor 470300e4126SRiver Riddle //===----------------------------------------------------------------------===// 471300e4126SRiver Riddle 4726c05ca21SMehdi Amini LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op, 4731ba5ea67SRiver Riddle AnalysisManager am, bool verifyPasses, 4741ba5ea67SRiver Riddle unsigned parentInitGeneration) { 4750a81ace0SKazu Hirata std::optional<RegisteredOperationName> opInfo = op->getRegisteredInfo(); 476c2fb9c29SRiver Riddle if (!opInfo) 4771284dc34SMehdi Amini return op->emitOpError() 4781284dc34SMehdi Amini << "trying to schedule a pass on an unregistered operation"; 479c2fb9c29SRiver Riddle if (!opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>()) 4801284dc34SMehdi Amini return op->emitOpError() << "trying to schedule a pass on an operation not " 4811284dc34SMehdi Amini "marked as 'IsolatedFromAbove'"; 48287da4b6fSMatthias Springer if (!pass->canScheduleOn(*op->getName().getRegisteredInfo())) 48387da4b6fSMatthias Springer return op->emitOpError() 48487da4b6fSMatthias Springer << "trying to schedule a pass on an unsupported operation"; 4851284dc34SMehdi Amini 486fb1de7edSMehdi Amini // Initialize the pass state with a callback for the pass to dynamically 487fb1de7edSMehdi Amini // execute a pipeline on the currently visited operation. 488d7eba200SRiver Riddle PassInstrumentor *pi = am.getPassInstrumentor(); 489d7eba200SRiver Riddle PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(), 490d7eba200SRiver Riddle pass}; 49102b6fb21SMehdi Amini auto dynamicPipelineCallback = [&](OpPassManager &pipeline, 492cd7107a6SMehdi Amini Operation *root) -> LogicalResult { 493cd7107a6SMehdi Amini if (!op->isAncestor(root)) 494cd7107a6SMehdi Amini return root->emitOpError() 495fb1de7edSMehdi Amini << "Trying to schedule a dynamic pipeline on an " 496fb1de7edSMehdi Amini "operation that isn't " 497fb1de7edSMehdi Amini "nested under the current operation the pass is processing"; 498c2fb9c29SRiver Riddle assert( 499c2fb9c29SRiver Riddle pipeline.getImpl().canScheduleOn(*op->getContext(), root->getName())); 500cd7107a6SMehdi Amini 5019c9a4317SRiver Riddle // Before running, finalize the passes held by the pipeline. 5029c9a4317SRiver Riddle if (failed(pipeline.getImpl().finalizePassList(root->getContext()))) 5039c9a4317SRiver Riddle return failure(); 504cde203e0SRiver Riddle 5051ba5ea67SRiver Riddle // Initialize the user provided pipeline and execute the pipeline. 506b1aaed02SMehdi Amini if (failed(pipeline.initialize(root->getContext(), parentInitGeneration))) 507b1aaed02SMehdi Amini return failure(); 508d7eba200SRiver Riddle AnalysisManager nestedAm = root == op ? am : am.nest(root); 509c2fb9c29SRiver Riddle return OpToOpPassAdaptor::runPipeline(pipeline, root, nestedAm, 5101ba5ea67SRiver Riddle verifyPasses, parentInitGeneration, 5111ba5ea67SRiver Riddle pi, &parentInfo); 512fb1de7edSMehdi Amini }; 51302b6fb21SMehdi Amini pass->passState.emplace(op, am, dynamicPipelineCallback); 514d7eba200SRiver Riddle 5156c05ca21SMehdi Amini // Instrument before the pass has run. 5166c05ca21SMehdi Amini if (pi) 5176c05ca21SMehdi Amini pi->runBeforePass(pass, op); 5186c05ca21SMehdi Amini 519930744fcSMehdi Amini bool passFailed = false; 520930744fcSMehdi Amini op->getContext()->executeAction<PassExecutionAction>( 521930744fcSMehdi Amini [&]() { 5226c05ca21SMehdi Amini // Invoke the virtual runOnOperation method. 523cd7107a6SMehdi Amini if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) 524cd7107a6SMehdi Amini adaptor->runOnOperation(verifyPasses); 525cd7107a6SMehdi Amini else 5266c05ca21SMehdi Amini pass->runOnOperation(); 527930744fcSMehdi Amini passFailed = pass->passState->irAndPassFailed.getInt(); 528930744fcSMehdi Amini }, 529f406adf1SMehdi Amini {op}, *pass); 5306c05ca21SMehdi Amini 5316c05ca21SMehdi Amini // Invalidate any non preserved analyses. 5326c05ca21SMehdi Amini am.invalidate(pass->passState->preservedAnalyses); 5336c05ca21SMehdi Amini 534a490ca8eSChris Lattner // When verifyPasses is specified, we run the verifier (unless the pass 535a490ca8eSChris Lattner // failed). 536a490ca8eSChris Lattner if (!passFailed && verifyPasses) { 537a490ca8eSChris Lattner bool runVerifierNow = true; 53850f82e68SRiver Riddle 53950f82e68SRiver Riddle // If the pass is an adaptor pass, we don't run the verifier recursively 54050f82e68SRiver Riddle // because the nested operations should have already been verified after 54150f82e68SRiver Riddle // nested passes had run. 54250f82e68SRiver Riddle bool runVerifierRecursively = !isa<OpToOpPassAdaptor>(pass); 54350f82e68SRiver Riddle 544a490ca8eSChris Lattner // Reduce compile time by avoiding running the verifier if the pass didn't 545a490ca8eSChris Lattner // change the IR since the last time the verifier was run: 546a490ca8eSChris Lattner // 547a490ca8eSChris Lattner // 1) If the pass said that it preserved all analyses then it can't have 548a490ca8eSChris Lattner // permuted the IR. 549a490ca8eSChris Lattner // 550a490ca8eSChris Lattner // We run these checks in EXPENSIVE_CHECKS mode out of caution. 551a490ca8eSChris Lattner #ifndef EXPENSIVE_CHECKS 55250f82e68SRiver Riddle runVerifierNow = !pass->passState->preservedAnalyses.isAll(); 553a490ca8eSChris Lattner #endif 554a490ca8eSChris Lattner if (runVerifierNow) 55550f82e68SRiver Riddle passFailed = failed(verify(op, runVerifierRecursively)); 556a490ca8eSChris Lattner } 557cd7107a6SMehdi Amini 5586c05ca21SMehdi Amini // Instrument after the pass has run. 5596c05ca21SMehdi Amini if (pi) { 5606c05ca21SMehdi Amini if (passFailed) 5616c05ca21SMehdi Amini pi->runAfterPassFailed(pass, op); 5626c05ca21SMehdi Amini else 5636c05ca21SMehdi Amini pi->runAfterPass(pass, op); 5646c05ca21SMehdi Amini } 5656c05ca21SMehdi Amini 5666c05ca21SMehdi Amini // Return if the pass signaled a failure. 5676c05ca21SMehdi Amini return failure(passFailed); 5686c05ca21SMehdi Amini } 5696c05ca21SMehdi Amini 5706c05ca21SMehdi Amini /// Run the given operation and analysis manager on a provided op pass manager. 5716c05ca21SMehdi Amini LogicalResult OpToOpPassAdaptor::runPipeline( 572c2fb9c29SRiver Riddle OpPassManager &pm, Operation *op, AnalysisManager am, bool verifyPasses, 573c2fb9c29SRiver Riddle unsigned parentInitGeneration, PassInstrumentor *instrumentor, 574d7eba200SRiver Riddle const PassInstrumentation::PipelineParentInfo *parentInfo) { 575d7eba200SRiver Riddle assert((!instrumentor || parentInfo) && 576d7eba200SRiver Riddle "expected parent info if instrumentor is provided"); 57702b6fb21SMehdi Amini auto scopeExit = llvm::make_scope_exit([&] { 5785c036e68SRiver Riddle // Clear out any computed operation analyses. These analyses won't be used 579af45236cSRiver Riddle // any more in this pipeline, and this helps reduce the current working set 580af45236cSRiver Riddle // of memory. If preserving these analyses becomes important in the future 5818bfedb3cSKazuaki Ishizaki // we can re-evaluate this. 58229099e03SRiver Riddle am.clear(); 5836c05ca21SMehdi Amini }); 5846c05ca21SMehdi Amini 5856c05ca21SMehdi Amini // Run the pipeline over the provided operation. 586c2fb9c29SRiver Riddle if (instrumentor) { 587c2fb9c29SRiver Riddle instrumentor->runBeforePipeline(pm.getOpName(*op->getContext()), 588c2fb9c29SRiver Riddle *parentInfo); 589c2fb9c29SRiver Riddle } 590c2fb9c29SRiver Riddle 591c2fb9c29SRiver Riddle for (Pass &pass : pm.getPasses()) 5921ba5ea67SRiver Riddle if (failed(run(&pass, op, am, verifyPasses, parentInitGeneration))) 5936c05ca21SMehdi Amini return failure(); 594c2fb9c29SRiver Riddle 595c2fb9c29SRiver Riddle if (instrumentor) { 596c2fb9c29SRiver Riddle instrumentor->runAfterPipeline(pm.getOpName(*op->getContext()), 597c2fb9c29SRiver Riddle *parentInfo); 598c2fb9c29SRiver Riddle } 5996c05ca21SMehdi Amini return success(); 600af45236cSRiver Riddle } 601af45236cSRiver Riddle 602c2fb9c29SRiver Riddle /// Find an operation pass manager with the given anchor name, or nullptr if one 603c2fb9c29SRiver Riddle /// does not exist. 604c2fb9c29SRiver Riddle static OpPassManager * 605c2fb9c29SRiver Riddle findPassManagerWithAnchor(MutableArrayRef<OpPassManager> mgrs, StringRef name) { 60602b6fb21SMehdi Amini auto *it = llvm::find_if( 607c2fb9c29SRiver Riddle mgrs, [&](OpPassManager &mgr) { return mgr.getOpAnchorName() == name; }); 608e702875dSRiver Riddle return it == mgrs.end() ? nullptr : &*it; 609e702875dSRiver Riddle } 610e702875dSRiver Riddle 611c0b6bc07SMehdi Amini /// Find an operation pass manager that can operate on an operation of the given 612c0b6bc07SMehdi Amini /// type, or nullptr if one does not exist. 613c0b6bc07SMehdi Amini static OpPassManager *findPassManagerFor(MutableArrayRef<OpPassManager> mgrs, 6149c9a4317SRiver Riddle OperationName name, 615c0b6bc07SMehdi Amini MLIRContext &context) { 616c2fb9c29SRiver Riddle auto *it = llvm::find_if(mgrs, [&](OpPassManager &mgr) { 617c2fb9c29SRiver Riddle return mgr.getImpl().canScheduleOn(context, name); 618c2fb9c29SRiver Riddle }); 619c0b6bc07SMehdi Amini return it == mgrs.end() ? nullptr : &*it; 620c0b6bc07SMehdi Amini } 621c0b6bc07SMehdi Amini 62256a69851SRiver Riddle OpToOpPassAdaptor::OpToOpPassAdaptor(OpPassManager &&mgr) { 623e702875dSRiver Riddle mgrs.emplace_back(std::move(mgr)); 624e702875dSRiver Riddle } 625e702875dSRiver Riddle 626f9dc2b70SMehdi Amini void OpToOpPassAdaptor::getDependentDialects(DialectRegistry &dialects) const { 627f9dc2b70SMehdi Amini for (auto &pm : mgrs) 628f9dc2b70SMehdi Amini pm.getDependentDialects(dialects); 629f9dc2b70SMehdi Amini } 630f9dc2b70SMehdi Amini 631c2fb9c29SRiver Riddle LogicalResult OpToOpPassAdaptor::tryMergeInto(MLIRContext *ctx, 632c2fb9c29SRiver Riddle OpToOpPassAdaptor &rhs) { 633c2fb9c29SRiver Riddle // Functor used to check if a pass manager is generic, i.e. op-agnostic. 634c2fb9c29SRiver Riddle auto isGenericPM = [&](OpPassManager &pm) { return !pm.getOpName(); }; 635c2fb9c29SRiver Riddle 636c2fb9c29SRiver Riddle // Functor used to detect if the given generic pass manager will have a 637c2fb9c29SRiver Riddle // potential schedule conflict with the given `otherPMs`. 638c2fb9c29SRiver Riddle auto hasScheduleConflictWith = [&](OpPassManager &genericPM, 639c2fb9c29SRiver Riddle MutableArrayRef<OpPassManager> otherPMs) { 640c2fb9c29SRiver Riddle return llvm::any_of(otherPMs, [&](OpPassManager &pm) { 641c2fb9c29SRiver Riddle // If this is a non-generic pass manager, a conflict will arise if a 642c2fb9c29SRiver Riddle // non-generic pass manager's operation name can be scheduled on the 643c2fb9c29SRiver Riddle // generic passmanager. 6440a81ace0SKazu Hirata if (std::optional<OperationName> pmOpName = pm.getOpName(*ctx)) 645c2fb9c29SRiver Riddle return genericPM.getImpl().canScheduleOn(*ctx, *pmOpName); 646c2fb9c29SRiver Riddle // Otherwise, this is a generic pass manager. We current can't determine 647c2fb9c29SRiver Riddle // when generic pass managers can be merged, so conservatively assume they 648c2fb9c29SRiver Riddle // conflict. 649c2fb9c29SRiver Riddle return true; 650c2fb9c29SRiver Riddle }); 651c2fb9c29SRiver Riddle }; 652c2fb9c29SRiver Riddle 653c2fb9c29SRiver Riddle // Check that if either adaptor has a generic pass manager, that pm is 654c2fb9c29SRiver Riddle // compatible within any non-generic pass managers. 655c2fb9c29SRiver Riddle // 656c2fb9c29SRiver Riddle // Check the current adaptor. 657c2fb9c29SRiver Riddle auto *lhsGenericPMIt = llvm::find_if(mgrs, isGenericPM); 658c2fb9c29SRiver Riddle if (lhsGenericPMIt != mgrs.end() && 659c2fb9c29SRiver Riddle hasScheduleConflictWith(*lhsGenericPMIt, rhs.mgrs)) 660c2fb9c29SRiver Riddle return failure(); 661c2fb9c29SRiver Riddle // Check the rhs adaptor. 662c2fb9c29SRiver Riddle auto *rhsGenericPMIt = llvm::find_if(rhs.mgrs, isGenericPM); 663c2fb9c29SRiver Riddle if (rhsGenericPMIt != rhs.mgrs.end() && 664c2fb9c29SRiver Riddle hasScheduleConflictWith(*rhsGenericPMIt, mgrs)) 665c2fb9c29SRiver Riddle return failure(); 666c2fb9c29SRiver Riddle 667e702875dSRiver Riddle for (auto &pm : mgrs) { 668e702875dSRiver Riddle // If an existing pass manager exists, then merge the given pass manager 669e702875dSRiver Riddle // into it. 670c2fb9c29SRiver Riddle if (auto *existingPM = 671c2fb9c29SRiver Riddle findPassManagerWithAnchor(rhs.mgrs, pm.getOpAnchorName())) { 672e702875dSRiver Riddle pm.getImpl().mergeInto(existingPM->getImpl()); 673e702875dSRiver Riddle } else { 674e702875dSRiver Riddle // Otherwise, add the given pass manager to the list. 675e702875dSRiver Riddle rhs.mgrs.emplace_back(std::move(pm)); 676e702875dSRiver Riddle } 677e702875dSRiver Riddle } 678e702875dSRiver Riddle mgrs.clear(); 679e702875dSRiver Riddle 680e702875dSRiver Riddle // After coalescing, sort the pass managers within rhs by name. 681c2fb9c29SRiver Riddle auto compareFn = [](const OpPassManager *lhs, const OpPassManager *rhs) { 682c2fb9c29SRiver Riddle // Order op-specific pass managers first and op-agnostic pass managers last. 6830a81ace0SKazu Hirata if (std::optional<StringRef> lhsName = lhs->getOpName()) { 6840a81ace0SKazu Hirata if (std::optional<StringRef> rhsName = rhs->getOpName()) 685c2fb9c29SRiver Riddle return lhsName->compare(*rhsName); 686c2fb9c29SRiver Riddle return -1; // lhs(op-specific) < rhs(op-agnostic) 687c2fb9c29SRiver Riddle } 688c2fb9c29SRiver Riddle return 1; // lhs(op-agnostic) > rhs(op-specific) 689c2fb9c29SRiver Riddle }; 690c2fb9c29SRiver Riddle llvm::array_pod_sort(rhs.mgrs.begin(), rhs.mgrs.end(), compareFn); 691c2fb9c29SRiver Riddle return success(); 692e702875dSRiver Riddle } 693e702875dSRiver Riddle 69433a64540SRiver Riddle /// Returns the adaptor pass name. 69556a69851SRiver Riddle std::string OpToOpPassAdaptor::getAdaptorName() { 69633a64540SRiver Riddle std::string name = "Pipeline Collection : ["; 69733a64540SRiver Riddle llvm::raw_string_ostream os(name); 6982f21a579SRiver Riddle llvm::interleaveComma(getPassManagers(), os, [&](OpPassManager &pm) { 699c2fb9c29SRiver Riddle os << '\'' << pm.getOpAnchorName() << '\''; 70033a64540SRiver Riddle }); 70133a64540SRiver Riddle os << ']'; 702884221edSJOE1994 return name; 70333a64540SRiver Riddle } 70433a64540SRiver Riddle 7055c036e68SRiver Riddle void OpToOpPassAdaptor::runOnOperation() { 706cd7107a6SMehdi Amini llvm_unreachable( 707cd7107a6SMehdi Amini "Unexpected call to Pass::runOnOperation() on OpToOpPassAdaptor"); 708cd7107a6SMehdi Amini } 709cd7107a6SMehdi Amini 710cd7107a6SMehdi Amini /// Run the held pipeline over all nested operations. 711cd7107a6SMehdi Amini void OpToOpPassAdaptor::runOnOperation(bool verifyPasses) { 712cb9ae002SRiver Riddle if (getContext().isMultithreadingEnabled()) 713cd7107a6SMehdi Amini runOnOperationAsyncImpl(verifyPasses); 714cb9ae002SRiver Riddle else 715cd7107a6SMehdi Amini runOnOperationImpl(verifyPasses); 71656a69851SRiver Riddle } 71756a69851SRiver Riddle 71856a69851SRiver Riddle /// Run this pass adaptor synchronously. 719cd7107a6SMehdi Amini void OpToOpPassAdaptor::runOnOperationImpl(bool verifyPasses) { 7205c036e68SRiver Riddle auto am = getAnalysisManager(); 7211c649d57SRiver Riddle PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(), 7221c649d57SRiver Riddle this}; 723120509a6SRiver Riddle auto *instrumentor = am.getPassInstrumentor(); 7245c036e68SRiver Riddle for (auto ®ion : getOperation()->getRegions()) { 7255c036e68SRiver Riddle for (auto &block : region) { 7265c036e68SRiver Riddle for (auto &op : block) { 7279c9a4317SRiver Riddle auto *mgr = findPassManagerFor(mgrs, op.getName(), *op.getContext()); 728e702875dSRiver Riddle if (!mgr) 729120509a6SRiver Riddle continue; 730120509a6SRiver Riddle 7315c036e68SRiver Riddle // Run the held pipeline over the current operation. 7321ba5ea67SRiver Riddle unsigned initGeneration = mgr->impl->initializationGeneration; 733c2fb9c29SRiver Riddle if (failed(runPipeline(*mgr, &op, am.nest(&op), verifyPasses, 734c2fb9c29SRiver Riddle initGeneration, instrumentor, &parentInfo))) 735*5b21fd29SBilly Zhu signalPassFailure(); 7365c036e68SRiver Riddle } 7375c036e68SRiver Riddle } 7386067cdebSRiver Riddle } 7396067cdebSRiver Riddle } 740300e4126SRiver Riddle 741e702875dSRiver Riddle /// Utility functor that checks if the two ranges of pass managers have a size 742e702875dSRiver Riddle /// mismatch. 743e702875dSRiver Riddle static bool hasSizeMismatch(ArrayRef<OpPassManager> lhs, 744e702875dSRiver Riddle ArrayRef<OpPassManager> rhs) { 745e702875dSRiver Riddle return lhs.size() != rhs.size() || 746e702875dSRiver Riddle llvm::any_of(llvm::seq<size_t>(0, lhs.size()), 747e702875dSRiver Riddle [&](size_t i) { return lhs[i].size() != rhs[i].size(); }); 748e702875dSRiver Riddle } 7495c036e68SRiver Riddle 75056a69851SRiver Riddle /// Run this pass adaptor synchronously. 751cd7107a6SMehdi Amini void OpToOpPassAdaptor::runOnOperationAsyncImpl(bool verifyPasses) { 75229099e03SRiver Riddle AnalysisManager am = getAnalysisManager(); 75384bd07afSRiver Riddle MLIRContext *context = &getContext(); 754af45236cSRiver Riddle 755af45236cSRiver Riddle // Create the async executors if they haven't been created, or if the main 7565c036e68SRiver Riddle // pipeline has changed. 757e702875dSRiver Riddle if (asyncExecutors.empty() || hasSizeMismatch(asyncExecutors.front(), mgrs)) 758744616b3SMehdi Amini asyncExecutors.assign(context->getThreadPool().getMaxConcurrency(), mgrs); 759af45236cSRiver Riddle 760c2fb9c29SRiver Riddle // This struct represents the information for a single operation to be 761c2fb9c29SRiver Riddle // scheduled on a pass manager. 762c2fb9c29SRiver Riddle struct OpPMInfo { 763c2fb9c29SRiver Riddle OpPMInfo(unsigned passManagerIdx, Operation *op, AnalysisManager am) 764c2fb9c29SRiver Riddle : passManagerIdx(passManagerIdx), op(op), am(am) {} 765c2fb9c29SRiver Riddle 766c2fb9c29SRiver Riddle /// The index of the pass manager to schedule the operation on. 767c2fb9c29SRiver Riddle unsigned passManagerIdx; 768c2fb9c29SRiver Riddle /// The operation to schedule. 769c2fb9c29SRiver Riddle Operation *op; 770c2fb9c29SRiver Riddle /// The analysis manager for the operation. 771c2fb9c29SRiver Riddle AnalysisManager am; 772c2fb9c29SRiver Riddle }; 773c2fb9c29SRiver Riddle 77400c6ef86SRiver Riddle // Run a prepass over the operation to collect the nested operations to 77500c6ef86SRiver Riddle // execute over. This ensures that an analysis manager exists for each 77600c6ef86SRiver Riddle // operation, as well as providing a queue of operations to execute over. 777c2fb9c29SRiver Riddle std::vector<OpPMInfo> opInfos; 7780a81ace0SKazu Hirata DenseMap<OperationName, std::optional<unsigned>> knownOpPMIdx; 7795c036e68SRiver Riddle for (auto ®ion : getOperation()->getRegions()) { 780c2fb9c29SRiver Riddle for (Operation &op : region.getOps()) { 781c2fb9c29SRiver Riddle // Get the pass manager index for this operation type. 7821a36588eSKazu Hirata auto pmIdxIt = knownOpPMIdx.try_emplace(op.getName(), std::nullopt); 783c2fb9c29SRiver Riddle if (pmIdxIt.second) { 784c2fb9c29SRiver Riddle if (auto *mgr = findPassManagerFor(mgrs, op.getName(), *context)) 785c2fb9c29SRiver Riddle pmIdxIt.first->second = std::distance(mgrs.begin(), mgr); 7865c036e68SRiver Riddle } 787c2fb9c29SRiver Riddle 788c2fb9c29SRiver Riddle // If this operation can be scheduled, add it to the list. 789c2fb9c29SRiver Riddle if (pmIdxIt.first->second) 790c2fb9c29SRiver Riddle opInfos.emplace_back(*pmIdxIt.first->second, &op, am.nest(&op)); 7915c036e68SRiver Riddle } 7925c036e68SRiver Riddle } 793af45236cSRiver Riddle 794120509a6SRiver Riddle // Get the current thread for this adaptor. 7951c649d57SRiver Riddle PassInstrumentation::PipelineParentInfo parentInfo = {llvm::get_threadid(), 7961c649d57SRiver Riddle this}; 797120509a6SRiver Riddle auto *instrumentor = am.getPassInstrumentor(); 798120509a6SRiver Riddle 799af45236cSRiver Riddle // An atomic failure variable for the async executors. 8006569cf2aSRiver Riddle std::vector<std::atomic<bool>> activePMs(asyncExecutors.size()); 8016569cf2aSRiver Riddle std::fill(activePMs.begin(), activePMs.end(), false); 802*5b21fd29SBilly Zhu std::atomic<bool> hasFailure = false; 803*5b21fd29SBilly Zhu parallelForEach(context, opInfos, [&](OpPMInfo &opInfo) { 804c2fb9c29SRiver Riddle // Find an executor for this operation. 8056569cf2aSRiver Riddle auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) { 8066569cf2aSRiver Riddle bool expectedInactive = false; 8076569cf2aSRiver Riddle return isActive.compare_exchange_strong(expectedInactive, true); 8086569cf2aSRiver Riddle }); 8096569cf2aSRiver Riddle unsigned pmIndex = it - activePMs.begin(); 81007c1a96aSRiver Riddle 811e702875dSRiver Riddle // Get the pass manager for this operation and execute it. 812c2fb9c29SRiver Riddle OpPassManager &pm = asyncExecutors[pmIndex][opInfo.passManagerIdx]; 813c2fb9c29SRiver Riddle LogicalResult pipelineResult = runPipeline( 814c2fb9c29SRiver Riddle pm, opInfo.op, opInfo.am, verifyPasses, 815c2fb9c29SRiver Riddle pm.impl->initializationGeneration, instrumentor, &parentInfo); 816*5b21fd29SBilly Zhu if (failed(pipelineResult)) 817*5b21fd29SBilly Zhu hasFailure.store(true); 818120509a6SRiver Riddle 8196569cf2aSRiver Riddle // Reset the active bit for this pass manager. 8206569cf2aSRiver Riddle activePMs[pmIndex].store(false); 821*5b21fd29SBilly Zhu }); 822af45236cSRiver Riddle 823af45236cSRiver Riddle // Signal a failure if any of the executors failed. 824*5b21fd29SBilly Zhu if (hasFailure) 825af45236cSRiver Riddle signalPassFailure(); 826af45236cSRiver Riddle } 827af45236cSRiver Riddle 8280e3260bcSRiver Riddle //===----------------------------------------------------------------------===// 8290e3260bcSRiver Riddle // PassManager 8300e3260bcSRiver Riddle //===----------------------------------------------------------------------===// 83150efe0fcSRiver Riddle 83294a30928Srkayaith PassManager::PassManager(MLIRContext *ctx, StringRef operationName, 83394a30928Srkayaith Nesting nesting) 83494a30928Srkayaith : OpPassManager(operationName, nesting), context(ctx), passTiming(false), 83594a30928Srkayaith verifyPasses(true) {} 83694a30928Srkayaith 83794a30928Srkayaith PassManager::PassManager(OperationName operationName, Nesting nesting) 83894a30928Srkayaith : OpPassManager(operationName, nesting), 83994a30928Srkayaith context(operationName.getContext()), passTiming(false), 84094a30928Srkayaith verifyPasses(true) {} 841300e4126SRiver Riddle 842e5639b3fSMehdi Amini PassManager::~PassManager() = default; 843300e4126SRiver Riddle 844cd7107a6SMehdi Amini void PassManager::enableVerifier(bool enabled) { verifyPasses = enabled; } 845cd7107a6SMehdi Amini 84600c6ef86SRiver Riddle /// Run the passes within this manager on the provided operation. 84700c6ef86SRiver Riddle LogicalResult PassManager::run(Operation *op) { 84800c6ef86SRiver Riddle MLIRContext *context = getContext(); 8490a81ace0SKazu Hirata std::optional<OperationName> anchorOp = getOpName(*context); 85013bd4109Srkayaith if (anchorOp && anchorOp != op->getName()) 85113bd4109Srkayaith return emitError(op->getLoc()) 85213bd4109Srkayaith << "can't run '" << getOpAnchorName() << "' pass manager on '" 85313bd4109Srkayaith << op->getName() << "' op"; 85400c6ef86SRiver Riddle 855f9dc2b70SMehdi Amini // Register all dialects for the current pipeline. 856f9dc2b70SMehdi Amini DialectRegistry dependentDialects; 857f9dc2b70SMehdi Amini getDependentDialects(dependentDialects); 8582996a8d6SAlex Zinenko context->appendDialectRegistry(dependentDialects); 8592996a8d6SAlex Zinenko for (StringRef name : dependentDialects.getDialectNames()) 8602996a8d6SAlex Zinenko context->getOrLoadDialect(name); 861f9dc2b70SMehdi Amini 8629c9a4317SRiver Riddle // Before running, make sure to finalize the pipeline pass list. 8639c9a4317SRiver Riddle if (failed(getImpl().finalizePassList(context))) 8649c9a4317SRiver Riddle return failure(); 8659c9a4317SRiver Riddle 8663e2e10b5SMehdi Amini // Notify the context that we start running a pipeline for bookkeeping. 8673e2e10b5SMehdi Amini context->enterMultiThreadedExecution(); 8683e2e10b5SMehdi Amini 8691ba5ea67SRiver Riddle // Initialize all of the passes within the pass manager with a new generation. 87002bc4c95SRiver Riddle llvm::hash_code newInitKey = context->getRegistryHash(); 871809b4403SMehdi Amini llvm::hash_code pipelineKey = hash(); 872809b4403SMehdi Amini if (newInitKey != initializationKey || pipelineKey != pipelineInitializationKey) { 873b1aaed02SMehdi Amini if (failed(initialize(context, impl->initializationGeneration + 1))) 874b1aaed02SMehdi Amini return failure(); 87502bc4c95SRiver Riddle initializationKey = newInitKey; 876809b4403SMehdi Amini pipelineKey = pipelineInitializationKey; 87702bc4c95SRiver Riddle } 8781ba5ea67SRiver Riddle 87900c6ef86SRiver Riddle // Construct a top level analysis manager for the pipeline. 88000c6ef86SRiver Riddle ModuleAnalysisManager am(op, instrumentor.get()); 8817a7dcc17SRiver Riddle 8827a7dcc17SRiver Riddle // If reproducer generation is enabled, run the pass manager with crash 8837a7dcc17SRiver Riddle // handling enabled. 88400c6ef86SRiver Riddle LogicalResult result = 88592469ca0SRiver Riddle crashReproGenerator ? runWithCrashRecovery(op, am) : runPasses(op, am); 88633a64540SRiver Riddle 88761070690SMehdi Amini // Notify the context that the run is done. 88800c6ef86SRiver Riddle context->exitMultiThreadedExecution(); 88961070690SMehdi Amini 89033a64540SRiver Riddle // Dump all of the pass statistics if necessary. 89133a64540SRiver Riddle if (passStatisticsMode) 89233a64540SRiver Riddle dumpStatistics(); 89333a64540SRiver Riddle return result; 8946558f80cSRiver Riddle } 8956558f80cSRiver Riddle 896bbe65b46SRiver Riddle /// Add the provided instrumentation to the pass manager. 897bbe65b46SRiver Riddle void PassManager::addInstrumentation(std::unique_ptr<PassInstrumentation> pi) { 8982d2b40bcSRiver Riddle if (!instrumentor) 899c900d499SChristian Sigg instrumentor = std::make_unique<PassInstrumentor>(); 9002d2b40bcSRiver Riddle 901bbe65b46SRiver Riddle instrumentor->addInstrumentation(std::move(pi)); 9022d2b40bcSRiver Riddle } 9032d2b40bcSRiver Riddle 90492469ca0SRiver Riddle LogicalResult PassManager::runPasses(Operation *op, AnalysisManager am) { 905c2fb9c29SRiver Riddle return OpToOpPassAdaptor::runPipeline(*this, op, am, verifyPasses, 90692469ca0SRiver Riddle impl->initializationGeneration); 90792469ca0SRiver Riddle } 90892469ca0SRiver Riddle 909485746f5SRiver Riddle //===----------------------------------------------------------------------===// 910485746f5SRiver Riddle // AnalysisManager 911485746f5SRiver Riddle //===----------------------------------------------------------------------===// 912485746f5SRiver Riddle 913d7eba200SRiver Riddle /// Get an analysis manager for the given operation, which must be a proper 914d7eba200SRiver Riddle /// descendant of the current operation represented by this analysis manager. 915d7eba200SRiver Riddle AnalysisManager AnalysisManager::nest(Operation *op) { 916d7eba200SRiver Riddle Operation *currentOp = impl->getOperation(); 917d7eba200SRiver Riddle assert(currentOp->isProperAncestor(op) && 918d7eba200SRiver Riddle "expected valid descendant operation"); 919d7eba200SRiver Riddle 920d7eba200SRiver Riddle // Check for the base case where the provided operation is immediately nested. 921d7eba200SRiver Riddle if (currentOp == op->getParentOp()) 922d7eba200SRiver Riddle return nestImmediate(op); 923d7eba200SRiver Riddle 924d7eba200SRiver Riddle // Otherwise, we need to collect all ancestors up to the current operation. 925d7eba200SRiver Riddle SmallVector<Operation *, 4> opAncestors; 926d7eba200SRiver Riddle do { 927d7eba200SRiver Riddle opAncestors.push_back(op); 928d7eba200SRiver Riddle op = op->getParentOp(); 929d7eba200SRiver Riddle } while (op != currentOp); 930d7eba200SRiver Riddle 931d7eba200SRiver Riddle AnalysisManager result = *this; 932d7eba200SRiver Riddle for (Operation *op : llvm::reverse(opAncestors)) 933d7eba200SRiver Riddle result = result.nestImmediate(op); 934d7eba200SRiver Riddle return result; 9352d2b40bcSRiver Riddle } 9362d2b40bcSRiver Riddle 937d7eba200SRiver Riddle /// Get an analysis manager for the given immediately nested child operation. 938d7eba200SRiver Riddle AnalysisManager AnalysisManager::nestImmediate(Operation *op) { 939d7eba200SRiver Riddle assert(impl->getOperation() == op->getParentOp() && 940d7eba200SRiver Riddle "expected immediate child operation"); 941d7eba200SRiver Riddle 9420078d4b5SKazu Hirata auto [it, inserted] = impl->childAnalyses.try_emplace(op); 9430078d4b5SKazu Hirata if (inserted) 9440078d4b5SKazu Hirata it->second = std::make_unique<NestedAnalysisMap>(op, impl); 945d7eba200SRiver Riddle return {it->second.get()}; 946485746f5SRiver Riddle } 947485746f5SRiver Riddle 948485746f5SRiver Riddle /// Invalidate any non preserved analyses. 94929099e03SRiver Riddle void detail::NestedAnalysisMap::invalidate( 95029099e03SRiver Riddle const detail::PreservedAnalyses &pa) { 9511d87b62aSRiver Riddle // If all analyses were preserved, then there is nothing to do here. 952485746f5SRiver Riddle if (pa.isAll()) 953485746f5SRiver Riddle return; 954485746f5SRiver Riddle 95529099e03SRiver Riddle // Invalidate the analyses for the current operation directly. 95629099e03SRiver Riddle analyses.invalidate(pa); 9571d87b62aSRiver Riddle 95829099e03SRiver Riddle // If no analyses were preserved, then just simply clear out the child 9591d87b62aSRiver Riddle // analysis results. 9601d87b62aSRiver Riddle if (pa.isNone()) { 96129099e03SRiver Riddle childAnalyses.clear(); 9621d87b62aSRiver Riddle return; 9631d87b62aSRiver Riddle } 9641d87b62aSRiver Riddle 96529099e03SRiver Riddle // Otherwise, invalidate each child analysis map. 96629099e03SRiver Riddle SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this); 96729099e03SRiver Riddle while (!mapsToInvalidate.empty()) { 96829099e03SRiver Riddle auto *map = mapsToInvalidate.pop_back_val(); 96929099e03SRiver Riddle for (auto &analysisPair : map->childAnalyses) { 970b3888fa9SRiver Riddle analysisPair.second->invalidate(pa); 97129099e03SRiver Riddle if (!analysisPair.second->childAnalyses.empty()) 97229099e03SRiver Riddle mapsToInvalidate.push_back(analysisPair.second.get()); 97329099e03SRiver Riddle } 97429099e03SRiver Riddle } 975485746f5SRiver Riddle } 97643d0ca84SRiver Riddle 97743d0ca84SRiver Riddle //===----------------------------------------------------------------------===// 97843d0ca84SRiver Riddle // PassInstrumentation 97943d0ca84SRiver Riddle //===----------------------------------------------------------------------===// 98043d0ca84SRiver Riddle 981e5639b3fSMehdi Amini PassInstrumentation::~PassInstrumentation() = default; 9826e983ae8SRiver Riddle 983c2fb9c29SRiver Riddle void PassInstrumentation::runBeforePipeline( 9840a81ace0SKazu Hirata std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {} 985c2fb9c29SRiver Riddle 986c2fb9c29SRiver Riddle void PassInstrumentation::runAfterPipeline( 9870a81ace0SKazu Hirata std::optional<OperationName> name, const PipelineParentInfo &parentInfo) {} 988c2fb9c29SRiver Riddle 9896e983ae8SRiver Riddle //===----------------------------------------------------------------------===// 9906e983ae8SRiver Riddle // PassInstrumentor 9916e983ae8SRiver Riddle //===----------------------------------------------------------------------===// 9926e983ae8SRiver Riddle 9936e983ae8SRiver Riddle namespace mlir { 9946e983ae8SRiver Riddle namespace detail { 9956e983ae8SRiver Riddle struct PassInstrumentorImpl { 9966e983ae8SRiver Riddle /// Mutex to keep instrumentation access thread-safe. 9976e983ae8SRiver Riddle llvm::sys::SmartMutex<true> mutex; 9986e983ae8SRiver Riddle 9996e983ae8SRiver Riddle /// Set of registered instrumentations. 10006e983ae8SRiver Riddle std::vector<std::unique_ptr<PassInstrumentation>> instrumentations; 10016e983ae8SRiver Riddle }; 1002be0a7e9fSMehdi Amini } // namespace detail 1003be0a7e9fSMehdi Amini } // namespace mlir 10046e983ae8SRiver Riddle 10056e983ae8SRiver Riddle PassInstrumentor::PassInstrumentor() : impl(new PassInstrumentorImpl()) {} 1006e5639b3fSMehdi Amini PassInstrumentor::~PassInstrumentor() = default; 10076e983ae8SRiver Riddle 1008120509a6SRiver Riddle /// See PassInstrumentation::runBeforePipeline for details. 10091c649d57SRiver Riddle void PassInstrumentor::runBeforePipeline( 10100a81ace0SKazu Hirata std::optional<OperationName> name, 10111c649d57SRiver Riddle const PassInstrumentation::PipelineParentInfo &parentInfo) { 1012120509a6SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 1013120509a6SRiver Riddle for (auto &instr : impl->instrumentations) 10141c649d57SRiver Riddle instr->runBeforePipeline(name, parentInfo); 1015120509a6SRiver Riddle } 1016120509a6SRiver Riddle 1017120509a6SRiver Riddle /// See PassInstrumentation::runAfterPipeline for details. 10181c649d57SRiver Riddle void PassInstrumentor::runAfterPipeline( 10190a81ace0SKazu Hirata std::optional<OperationName> name, 10201c649d57SRiver Riddle const PassInstrumentation::PipelineParentInfo &parentInfo) { 1021120509a6SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 10221c649d57SRiver Riddle for (auto &instr : llvm::reverse(impl->instrumentations)) 10231c649d57SRiver Riddle instr->runAfterPipeline(name, parentInfo); 1024120509a6SRiver Riddle } 1025120509a6SRiver Riddle 10266e983ae8SRiver Riddle /// See PassInstrumentation::runBeforePass for details. 10274fb971a9SRiver Riddle void PassInstrumentor::runBeforePass(Pass *pass, Operation *op) { 10286e983ae8SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 10296e983ae8SRiver Riddle for (auto &instr : impl->instrumentations) 10304fb971a9SRiver Riddle instr->runBeforePass(pass, op); 10316e983ae8SRiver Riddle } 10326e983ae8SRiver Riddle 10336e983ae8SRiver Riddle /// See PassInstrumentation::runAfterPass for details. 10344fb971a9SRiver Riddle void PassInstrumentor::runAfterPass(Pass *pass, Operation *op) { 10356e983ae8SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 10366e983ae8SRiver Riddle for (auto &instr : llvm::reverse(impl->instrumentations)) 10374fb971a9SRiver Riddle instr->runAfterPass(pass, op); 10386e983ae8SRiver Riddle } 10396e983ae8SRiver Riddle 10406e983ae8SRiver Riddle /// See PassInstrumentation::runAfterPassFailed for details. 10414fb971a9SRiver Riddle void PassInstrumentor::runAfterPassFailed(Pass *pass, Operation *op) { 10426e983ae8SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 10436e983ae8SRiver Riddle for (auto &instr : llvm::reverse(impl->instrumentations)) 10444fb971a9SRiver Riddle instr->runAfterPassFailed(pass, op); 10456e983ae8SRiver Riddle } 10466e983ae8SRiver Riddle 10476e983ae8SRiver Riddle /// See PassInstrumentation::runBeforeAnalysis for details. 1048a517191aSRiver Riddle void PassInstrumentor::runBeforeAnalysis(StringRef name, TypeID id, 10494fb971a9SRiver Riddle Operation *op) { 10506e983ae8SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 10516e983ae8SRiver Riddle for (auto &instr : impl->instrumentations) 10524fb971a9SRiver Riddle instr->runBeforeAnalysis(name, id, op); 10536e983ae8SRiver Riddle } 10546e983ae8SRiver Riddle 10556e983ae8SRiver Riddle /// See PassInstrumentation::runAfterAnalysis for details. 1056a517191aSRiver Riddle void PassInstrumentor::runAfterAnalysis(StringRef name, TypeID id, 10574fb971a9SRiver Riddle Operation *op) { 10586e983ae8SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 10596e983ae8SRiver Riddle for (auto &instr : llvm::reverse(impl->instrumentations)) 10604fb971a9SRiver Riddle instr->runAfterAnalysis(name, id, op); 10616e983ae8SRiver Riddle } 10626e983ae8SRiver Riddle 1063bbe65b46SRiver Riddle /// Add the given instrumentation to the collection. 1064bbe65b46SRiver Riddle void PassInstrumentor::addInstrumentation( 1065bbe65b46SRiver Riddle std::unique_ptr<PassInstrumentation> pi) { 10666e983ae8SRiver Riddle llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 1067bbe65b46SRiver Riddle impl->instrumentations.emplace_back(std::move(pi)); 10686e983ae8SRiver Riddle } 1069