xref: /llvm-project/mlir/lib/Pass/Pass.cpp (revision 5b21fd298cb4fc2042a95ffb9284b778f8504e04)
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 &region : 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 &region : 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