template <typename PassT> LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<!std::is_same<PassT, PassManager>::value> addPass(PassT &&Pass) { using PassModelT = detail::PassModel<IRUnitT, PassT, PreservedAnalyses, AnalysisManagerT, ExtraArgTs...>; // Do not use make_unique or emplace_back, they cause too many template // instantiations, causing terrible compile times. Passes.push_back(std::unique_ptr<PassConceptT>( newPassModelT(std::forward<PassT>(Pass)))); }
cases rely on executing nested pass managers. Doing this could reduce implementation complexity and avoid potential invalidation issues that may happen with nested pass managers of the same type.
/// Run all of the passes in this manager over the given unit of IR. /// ExtraArgs are passed to each pass. PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs){ PreservedAnalyses PA = PreservedAnalyses::all();
// Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. // Here we use std::tuple wrapper over getResult which helps to extract // AnalysisManager's arguments out of the whole ExtraArgs set. PassInstrumentation PI = detail::getAnalysisResult<PassInstrumentationAnalysis>( AM, IR, std::tuple<ExtraArgTs...>(ExtraArgs...));
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { auto *P = Passes[Idx].get();
// Check the PassInstrumentation's BeforePass callbacks before running the // pass, skip its execution completely if asked to (callback returns // false). if (!PI.runBeforePass<IRUnitT>(*P, IR)) continue;
// Call onto PassInstrumentation's AfterPass callbacks immediately after // running the pass. PI.runAfterPass<IRUnitT>(*P, IR, PassPA);
// Update the analysis manager as each pass runs and potentially // invalidates analyses. AM.invalidate(IR, PassPA);
// Finally, intersect the preserved analyses to compute the aggregate // preserved set for this pass manager. PA.intersect(std::move(PassPA)); }
// Invalidation was handled after each pass in the above loop for the // current unit of IR. Therefore, the remaining analysis results in the // AnalysisManager are preserved. We mark this with a set so that we don't // need to inspect each one individually. PA.preserveSet<AllAnalysesOn<IRUnitT>>();
template <typename PassT> LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<is_detected<HasRunOnLoopT, PassT>::value> addPass(PassT &&Pass) { using LoopPassModelT = detail::PassModel<Loop, PassT, PreservedAnalyses, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater &>; IsLoopNestPass.push_back(false); // Do not use make_unique or emplace_back, they cause too many template // instantiations, causing terrible compile times. LoopPasses.push_back(std::unique_ptr<LoopPassConceptT>( newLoopPassModelT(std::forward<PassT>(Pass)))); }
template <typename PassT> LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<!is_detected<HasRunOnLoopT, PassT>::value> addPass(PassT &&Pass) { using LoopNestPassModelT = detail::PassModel<LoopNest, PassT, PreservedAnalyses, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater &>; IsLoopNestPass.push_back(true); // Do not use make_unique or emplace_back, they cause too many template // instantiations, causing terrible compile times. LoopNestPasses.push_back(std::unique_ptr<LoopNestPassConceptT>( newLoopNestPassModelT(std::forward<PassT>(Pass)))); }
// Specializations of `addPass` for `RepeatedPass`. These are necessary since // `RepeatedPass` has a templated `run` method that will result in incorrect // detection of `HasRunOnLoopT`. template <typename PassT> LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<is_detected<HasRunOnLoopT, PassT>::value> addPass(RepeatedPass<PassT> &&Pass) { using RepeatedLoopPassModelT = detail::PassModel<Loop, RepeatedPass<PassT>, PreservedAnalyses, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater &>; IsLoopNestPass.push_back(false); // Do not use make_unique or emplace_back, they cause too many template // instantiations, causing terrible compile times. LoopPasses.push_back(std::unique_ptr<LoopPassConceptT>( newRepeatedLoopPassModelT(std::move(Pass)))); }
template <typename PassT> LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<!is_detected<HasRunOnLoopT, PassT>::value> addPass(RepeatedPass<PassT> &&Pass) { using RepeatedLoopNestPassModelT = detail::PassModel<LoopNest, RepeatedPass<PassT>, PreservedAnalyses, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater &>; IsLoopNestPass.push_back(true); // Do not use make_unique or emplace_back, they cause too many template // instantiations, causing terrible compile times. LoopNestPasses.push_back(std::unique_ptr<LoopNestPassConceptT>( newRepeatedLoopNestPassModelT(std::move(Pass)))); }
/// Explicitly specialize the pass manager's run method to handle loop nest /// structure updates. PreservedAnalyses PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &, LPMUpdater &>::run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U) { // Runs loop-nest passes only when the current loop is a top-level one. PreservedAnalyses PA = (L.isOutermost() && !LoopNestPasses.empty()) ? runWithLoopNestPasses(L, AM, AR, U) : runWithoutLoopNestPasses(L, AM, AR, U);
// Invalidation for the current loop should be handled above, and other loop // analysis results shouldn't be impacted by runs over this loop. Therefore, // the remaining analysis results in the AnalysisManager are preserved. We // mark this with a set so that we don't need to inspect each one // individually. PA.preserveSet<AllAnalysesOn<Loop>>();
return PA; }
/// Run either a loop pass or a loop-nest pass. Returns `None` if /// PassInstrumentation's BeforePass returns false. Otherwise, returns the /// preserved analyses of the pass. template <typename IRUnitT, typename PassT> Optional<PreservedAnalyses> runSinglePass(IRUnitT &IR, PassT &Pass, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U, PassInstrumentation &PI);
template <typename IRUnitT, typename PassT> Optional<PreservedAnalyses> LoopPassManager::runSinglePass( IRUnitT &IR, PassT &Pass, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U, PassInstrumentation &PI){ // Get the loop in case of Loop pass and outermost loop in case of LoopNest // pass which is to be passed to BeforePass and AfterPass call backs. const Loop &L = getLoopFromIR(IR); // Check the PassInstrumentation's BeforePass callbacks before running the // pass, skip its execution completely if asked to (callback returns false). if (!PI.runBeforePass<Loop>(*Pass, L)) return None;
// do not pass deleted Loop into the instrumentation if (U.skipCurrentLoop()) PI.runAfterPassInvalidated<IRUnitT>(*Pass, PA); else PI.runAfterPass<Loop>(*Pass, L, PA); return PA; }
/// MachineFunctionPassManager adds/removes below features to/from the base /// PassManager template instantiation. /// /// - Support passes that implement doInitialization/doFinalization. This is for /// machine function passes to work on module level constructs. One such pass /// is AsmPrinter. /// ... /// - The base class `run` method is replaced by an alternative `run` method. /// See details below. /// /// - Support codegening in the SCC order. Users include interprocedural /// register allocation (IPRA). classMachineFunctionPassManager :public PassManager<MachineFunction, MachineFunctionAnalysisManager> { using Base = PassManager<MachineFunction, MachineFunctionAnalysisManager>; ... }
Error MachineFunctionPassManager::run(Module &M, MachineFunctionAnalysisManager &MFAM){ ... // Add a PIC to verify machine functions. if (VerifyMachineFunction) { PassInstrumentation PI = MFAM.getResult<PassInstrumentationAnalysis>(M);
// No need to pop this callback later since MIR pipeline is flat which means // current pipeline is the top-level pipeline. Callbacks are not used after // current pipeline. PI.pushBeforeNonSkippedPassCallback([&MFAM](StringRef PassID, Any IR) { ... }); }
for (auto &F : InitializationFuncs) { if (auto Err = F(M, MFAM)) return Err; }
do { // Run machine module passes ... } while (true);
for (auto &F : FinalizationFuncs) { if (auto Err = F(M, MFAM)) return Err; }
// Explicit specialization and instantiation declarations for the pass manager. // See the comments on the definition of the specialization for details on how // it differs from the primary template. template <> PreservedAnalyses PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, CGSCCUpdateResult &>::run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &G, CGSCCUpdateResult &UR); externtemplateclassPassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, CGSCCUpdateResult &>;
/// The CGSCC pass manager. /// /// See the documentation for the PassManager template for details. It runs /// a sequence of SCC passes over each SCC that the manager is run over. This /// type serves as a convenient way to refer to this construct. using CGSCCPassManager = PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, CGSCCUpdateResult &>;
/// Explicitly specialize the pass manager run method to handle call graph /// updates. template <> PreservedAnalyses PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, CGSCCUpdateResult &>::run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &G, CGSCCUpdateResult &UR) { // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(InitialC, G);
PreservedAnalyses PA = PreservedAnalyses::all();
// The SCC may be refined while we are running passes over it, so set up // a pointer that we can update. LazyCallGraph::SCC *C = &InitialC;
// Get Function analysis manager from its proxy. FunctionAnalysisManager &FAM = AM.getCachedResult<FunctionAnalysisManagerCGSCCProxy>(*C)->getManager();
for (auto &Pass : Passes) { // Check the PassInstrumentation's BeforePass callbacks before running the // pass, skip its execution completely if asked to (callback returns false). if (!PI.runBeforePass(*Pass, *C)) continue;
if (UR.InvalidatedSCCs.count(C)) PI.runAfterPassInvalidated<LazyCallGraph::SCC>(*Pass, PassPA); else PI.runAfterPass<LazyCallGraph::SCC>(*Pass, *C, PassPA);
// Update the SCC if necessary. C = UR.UpdatedC ? UR.UpdatedC : C; if (UR.UpdatedC) { // If C is updated, also create a proxy and update FAM inside the result. auto *ResultFAMCP = &AM.getResult<FunctionAnalysisManagerCGSCCProxy>(*C, G); ResultFAMCP->updateFAM(FAM); }
// If the CGSCC pass wasn't able to provide a valid updated SCC, the // current SCC may simply need to be skipped if invalid. if (UR.InvalidatedSCCs.count(C)) { LLVM_DEBUG(dbgs() << "Skipping invalidated root or island SCC!\n"); break; } // Check that we didn't miss any update scenario. assert(C->begin() != C->end() && "Cannot have an empty SCC!");
// Update the analysis manager as each pass runs and potentially // invalidates analyses. AM.invalidate(*C, PassPA);
// Finally, we intersect the final preserved analyses to compute the // aggregate preserved set for this pass manager. PA.intersect(std::move(PassPA)); }
// Before we mark all of *this* SCC's analyses as preserved below, intersect // this with the cross-SCC preserved analysis set. This is used to allow // CGSCC passes to mutate ancestor SCCs and still trigger proper invalidation // for them. UR.CrossSCCPA.intersect(PA);
// Invalidation was handled after each pass in the above loop for the current // SCC. Therefore, the remaining analysis results in the AnalysisManager are // preserved. We mark this with a set so that we don't need to inspect each // one individually. PA.preserveSet<AllAnalysesOn<LazyCallGraph::SCC>>();
/// createPrinterPass - Get a module printer pass. Pass *createPrinterPass(raw_ostream &O, const std::string &Banner)constoverride{ returncreatePrintModulePass(O, Banner); }
/// run - Execute all of the passes scheduled for execution. Keep track of /// whether any of the passes modifies the module, and if so, return true. boolrun(Module &M);
using llvm::Pass::doInitialization; using llvm::Pass::doFinalization;
/// run - Execute all of the passes scheduled for execution. Keep track of /// whether any of the passes modifies the module, and if so, return true. boolPassManagerImpl::run(Module &M){ bool Changed = false;
dumpArguments(); dumpPasses();
for (ImmutablePass *ImPass : getImmutablePasses()) Changed |= ImPass->doInitialization(M);
initializeAllAnalysisInfo(); for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) { Changed |= getContainedManager(Index)->runOnModule(M); M.getContext().yield(); }
for (ImmutablePass *ImPass : getImmutablePasses()) Changed |= ImPass->doFinalization(M);