|
|
|||
File indexing completed on 2026-05-10 08:43:12
0001 //===- CGSCCPassManager.h - Call graph pass management ----------*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 /// \file 0009 /// 0010 /// This header provides classes for managing passes over SCCs of the call 0011 /// graph. These passes form an important component of LLVM's interprocedural 0012 /// optimizations. Because they operate on the SCCs of the call graph, and they 0013 /// traverse the graph in post-order, they can effectively do pair-wise 0014 /// interprocedural optimizations for all call edges in the program while 0015 /// incrementally refining it and improving the context of these pair-wise 0016 /// optimizations. At each call site edge, the callee has already been 0017 /// optimized as much as is possible. This in turn allows very accurate 0018 /// analysis of it for IPO. 0019 /// 0020 /// A secondary more general goal is to be able to isolate optimization on 0021 /// unrelated parts of the IR module. This is useful to ensure our 0022 /// optimizations are principled and don't miss oportunities where refinement 0023 /// of one part of the module influences transformations in another part of the 0024 /// module. But this is also useful if we want to parallelize the optimizations 0025 /// across common large module graph shapes which tend to be very wide and have 0026 /// large regions of unrelated cliques. 0027 /// 0028 /// To satisfy these goals, we use the LazyCallGraph which provides two graphs 0029 /// nested inside each other (and built lazily from the bottom-up): the call 0030 /// graph proper, and a reference graph. The reference graph is super set of 0031 /// the call graph and is a conservative approximation of what could through 0032 /// scalar or CGSCC transforms *become* the call graph. Using this allows us to 0033 /// ensure we optimize functions prior to them being introduced into the call 0034 /// graph by devirtualization or other technique, and thus ensures that 0035 /// subsequent pair-wise interprocedural optimizations observe the optimized 0036 /// form of these functions. The (potentially transitive) reference 0037 /// reachability used by the reference graph is a conservative approximation 0038 /// that still allows us to have independent regions of the graph. 0039 /// 0040 /// FIXME: There is one major drawback of the reference graph: in its naive 0041 /// form it is quadratic because it contains a distinct edge for each 0042 /// (potentially indirect) reference, even if are all through some common 0043 /// global table of function pointers. This can be fixed in a number of ways 0044 /// that essentially preserve enough of the normalization. While it isn't 0045 /// expected to completely preclude the usability of this, it will need to be 0046 /// addressed. 0047 /// 0048 /// 0049 /// All of these issues are made substantially more complex in the face of 0050 /// mutations to the call graph while optimization passes are being run. When 0051 /// mutations to the call graph occur we want to achieve two different things: 0052 /// 0053 /// - We need to update the call graph in-flight and invalidate analyses 0054 /// cached on entities in the graph. Because of the cache-based analysis 0055 /// design of the pass manager, it is essential to have stable identities for 0056 /// the elements of the IR that passes traverse, and to invalidate any 0057 /// analyses cached on these elements as the mutations take place. 0058 /// 0059 /// - We want to preserve the incremental and post-order traversal of the 0060 /// graph even as it is refined and mutated. This means we want optimization 0061 /// to observe the most refined form of the call graph and to do so in 0062 /// post-order. 0063 /// 0064 /// To address this, the CGSCC manager uses both worklists that can be expanded 0065 /// by passes which transform the IR, and provides invalidation tests to skip 0066 /// entries that become dead. This extra data is provided to every SCC pass so 0067 /// that it can carefully update the manager's traversal as the call graph 0068 /// mutates. 0069 /// 0070 /// We also provide support for running function passes within the CGSCC walk, 0071 /// and there we provide automatic update of the call graph including of the 0072 /// pass manager to reflect call graph changes that fall out naturally as part 0073 /// of scalar transformations. 0074 /// 0075 /// The patterns used to ensure the goals of post-order visitation of the fully 0076 /// refined graph: 0077 /// 0078 /// 1) Sink toward the "bottom" as the graph is refined. This means that any 0079 /// iteration continues in some valid post-order sequence after the mutation 0080 /// has altered the structure. 0081 /// 0082 /// 2) Enqueue in post-order, including the current entity. If the current 0083 /// entity's shape changes, it and everything after it in post-order needs 0084 /// to be visited to observe that shape. 0085 /// 0086 //===----------------------------------------------------------------------===// 0087 0088 #ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H 0089 #define LLVM_ANALYSIS_CGSCCPASSMANAGER_H 0090 0091 #include "llvm/ADT/MapVector.h" 0092 #include "llvm/Analysis/LazyCallGraph.h" 0093 #include "llvm/IR/PassManager.h" 0094 #include "llvm/IR/ValueHandle.h" 0095 #include "llvm/Support/raw_ostream.h" 0096 #include <cassert> 0097 #include <utility> 0098 0099 namespace llvm { 0100 0101 class Function; 0102 template <typename T, unsigned int N> class SmallPriorityWorklist; 0103 struct CGSCCUpdateResult; 0104 0105 class Module; 0106 0107 // Allow debug logging in this inline function. 0108 #define DEBUG_TYPE "cgscc" 0109 0110 /// Extern template declaration for the analysis set for this IR unit. 0111 extern template class AllAnalysesOn<LazyCallGraph::SCC>; 0112 0113 extern template class AnalysisManager<LazyCallGraph::SCC, LazyCallGraph &>; 0114 0115 /// The CGSCC analysis manager. 0116 /// 0117 /// See the documentation for the AnalysisManager template for detail 0118 /// documentation. This type serves as a convenient way to refer to this 0119 /// construct in the adaptors and proxies used to integrate this into the larger 0120 /// pass manager infrastructure. 0121 using CGSCCAnalysisManager = 0122 AnalysisManager<LazyCallGraph::SCC, LazyCallGraph &>; 0123 0124 // Explicit specialization and instantiation declarations for the pass manager. 0125 // See the comments on the definition of the specialization for details on how 0126 // it differs from the primary template. 0127 template <> 0128 PreservedAnalyses 0129 PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, 0130 CGSCCUpdateResult &>::run(LazyCallGraph::SCC &InitialC, 0131 CGSCCAnalysisManager &AM, 0132 LazyCallGraph &G, CGSCCUpdateResult &UR); 0133 extern template class PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, 0134 LazyCallGraph &, CGSCCUpdateResult &>; 0135 0136 /// The CGSCC pass manager. 0137 /// 0138 /// See the documentation for the PassManager template for details. It runs 0139 /// a sequence of SCC passes over each SCC that the manager is run over. This 0140 /// type serves as a convenient way to refer to this construct. 0141 using CGSCCPassManager = 0142 PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, 0143 CGSCCUpdateResult &>; 0144 0145 /// An explicit specialization of the require analysis template pass. 0146 template <typename AnalysisT> 0147 struct RequireAnalysisPass<AnalysisT, LazyCallGraph::SCC, CGSCCAnalysisManager, 0148 LazyCallGraph &, CGSCCUpdateResult &> 0149 : PassInfoMixin<RequireAnalysisPass<AnalysisT, LazyCallGraph::SCC, 0150 CGSCCAnalysisManager, LazyCallGraph &, 0151 CGSCCUpdateResult &>> { 0152 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 0153 LazyCallGraph &CG, CGSCCUpdateResult &) { 0154 (void)AM.template getResult<AnalysisT>(C, CG); 0155 return PreservedAnalyses::all(); 0156 } 0157 void printPipeline(raw_ostream &OS, 0158 function_ref<StringRef(StringRef)> MapClassName2PassName) { 0159 auto ClassName = AnalysisT::name(); 0160 auto PassName = MapClassName2PassName(ClassName); 0161 OS << "require<" << PassName << '>'; 0162 } 0163 }; 0164 0165 /// A proxy from a \c CGSCCAnalysisManager to a \c Module. 0166 using CGSCCAnalysisManagerModuleProxy = 0167 InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>; 0168 0169 /// We need a specialized result for the \c CGSCCAnalysisManagerModuleProxy so 0170 /// it can have access to the call graph in order to walk all the SCCs when 0171 /// invalidating things. 0172 template <> class CGSCCAnalysisManagerModuleProxy::Result { 0173 public: 0174 explicit Result(CGSCCAnalysisManager &InnerAM, LazyCallGraph &G) 0175 : InnerAM(&InnerAM), G(&G) {} 0176 0177 /// Accessor for the analysis manager. 0178 CGSCCAnalysisManager &getManager() { return *InnerAM; } 0179 0180 /// Handler for invalidation of the Module. 0181 /// 0182 /// If the proxy analysis itself is preserved, then we assume that the set of 0183 /// SCCs in the Module hasn't changed. Thus any pointers to SCCs in the 0184 /// CGSCCAnalysisManager are still valid, and we don't need to call \c clear 0185 /// on the CGSCCAnalysisManager. 0186 /// 0187 /// Regardless of whether this analysis is marked as preserved, all of the 0188 /// analyses in the \c CGSCCAnalysisManager are potentially invalidated based 0189 /// on the set of preserved analyses. 0190 bool invalidate(Module &M, const PreservedAnalyses &PA, 0191 ModuleAnalysisManager::Invalidator &Inv); 0192 0193 private: 0194 CGSCCAnalysisManager *InnerAM; 0195 LazyCallGraph *G; 0196 }; 0197 0198 /// Provide a specialized run method for the \c CGSCCAnalysisManagerModuleProxy 0199 /// so it can pass the lazy call graph to the result. 0200 template <> 0201 CGSCCAnalysisManagerModuleProxy::Result 0202 CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager &AM); 0203 0204 // Ensure the \c CGSCCAnalysisManagerModuleProxy is provided as an extern 0205 // template. 0206 extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>; 0207 0208 extern template class OuterAnalysisManagerProxy< 0209 ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>; 0210 0211 /// A proxy from a \c ModuleAnalysisManager to an \c SCC. 0212 using ModuleAnalysisManagerCGSCCProxy = 0213 OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC, 0214 LazyCallGraph &>; 0215 0216 /// Support structure for SCC passes to communicate updates the call graph back 0217 /// to the CGSCC pass manager infrastructure. 0218 /// 0219 /// The CGSCC pass manager runs SCC passes which are allowed to update the call 0220 /// graph and SCC structures. This means the structure the pass manager works 0221 /// on is mutating underneath it. In order to support that, there needs to be 0222 /// careful communication about the precise nature and ramifications of these 0223 /// updates to the pass management infrastructure. 0224 /// 0225 /// All SCC passes will have to accept a reference to the management layer's 0226 /// update result struct and use it to reflect the results of any CG updates 0227 /// performed. 0228 /// 0229 /// Passes which do not change the call graph structure in any way can just 0230 /// ignore this argument to their run method. 0231 struct CGSCCUpdateResult { 0232 /// Worklist of the SCCs queued for processing. 0233 /// 0234 /// When a pass refines the graph and creates new SCCs or causes them to have 0235 /// a different shape or set of component functions it should add the SCCs to 0236 /// this worklist so that we visit them in the refined form. 0237 /// 0238 /// Note that if the SCCs are part of a RefSCC that is added to the \c 0239 /// RCWorklist, they don't need to be added here as visiting the RefSCC will 0240 /// be sufficient to re-visit the SCCs within it. 0241 /// 0242 /// This worklist is in reverse post-order, as we pop off the back in order 0243 /// to observe SCCs in post-order. When adding SCCs, clients should add them 0244 /// in reverse post-order. 0245 SmallPriorityWorklist<LazyCallGraph::SCC *, 1> &CWorklist; 0246 0247 /// The set of invalidated SCCs which should be skipped if they are found 0248 /// in \c CWorklist. 0249 /// 0250 /// This is used to quickly prune out SCCs when they get deleted and happen 0251 /// to already be on the worklist. We use this primarily to avoid scanning 0252 /// the list and removing entries from it. 0253 SmallPtrSetImpl<LazyCallGraph::SCC *> &InvalidatedSCCs; 0254 0255 /// If non-null, the updated current \c SCC being processed. 0256 /// 0257 /// This is set when a graph refinement takes place and the "current" point 0258 /// in the graph moves "down" or earlier in the post-order walk. This will 0259 /// often cause the "current" SCC to be a newly created SCC object and the 0260 /// old one to be added to the above worklist. When that happens, this 0261 /// pointer is non-null and can be used to continue processing the "top" of 0262 /// the post-order walk. 0263 LazyCallGraph::SCC *UpdatedC; 0264 0265 /// Preserved analyses across SCCs. 0266 /// 0267 /// We specifically want to allow CGSCC passes to mutate ancestor IR 0268 /// (changing both the CG structure and the function IR itself). However, 0269 /// this means we need to take special care to correctly mark what analyses 0270 /// are preserved *across* SCCs. We have to track this out-of-band here 0271 /// because within the main `PassManager` infrastructure we need to mark 0272 /// everything within an SCC as preserved in order to avoid repeatedly 0273 /// invalidating the same analyses as we unnest pass managers and adaptors. 0274 /// So we track the cross-SCC version of the preserved analyses here from any 0275 /// code that does direct invalidation of SCC analyses, and then use it 0276 /// whenever we move forward in the post-order walk of SCCs before running 0277 /// passes over the new SCC. 0278 PreservedAnalyses CrossSCCPA; 0279 0280 /// A hacky area where the inliner can retain history about inlining 0281 /// decisions that mutated the call graph's SCC structure in order to avoid 0282 /// infinite inlining. See the comments in the inliner's CG update logic. 0283 /// 0284 /// FIXME: Keeping this here seems like a big layering issue, we should look 0285 /// for a better technique. 0286 SmallDenseSet<std::pair<LazyCallGraph::Node *, LazyCallGraph::SCC *>, 4> 0287 &InlinedInternalEdges; 0288 0289 /// Functions that a pass has considered to be dead to be removed at the end 0290 /// of the call graph walk in batch. 0291 SmallVector<Function *, 4> &DeadFunctions; 0292 0293 /// Weak VHs to keep track of indirect calls for the purposes of detecting 0294 /// devirtualization. 0295 /// 0296 /// This is a map to avoid having duplicate entries. If a Value is 0297 /// deallocated, its corresponding WeakTrackingVH will be nulled out. When 0298 /// checking if a Value is in the map or not, also check if the corresponding 0299 /// WeakTrackingVH is null to avoid issues with a new Value sharing the same 0300 /// address as a deallocated one. 0301 SmallMapVector<Value *, WeakTrackingVH, 16> IndirectVHs; 0302 }; 0303 0304 /// The core module pass which does a post-order walk of the SCCs and 0305 /// runs a CGSCC pass over each one. 0306 /// 0307 /// Designed to allow composition of a CGSCCPass(Manager) and 0308 /// a ModulePassManager. Note that this pass must be run with a module analysis 0309 /// manager as it uses the LazyCallGraph analysis. It will also run the 0310 /// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC 0311 /// pass over the module to enable a \c FunctionAnalysisManager to be used 0312 /// within this run safely. 0313 class ModuleToPostOrderCGSCCPassAdaptor 0314 : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor> { 0315 public: 0316 using PassConceptT = 0317 detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager, 0318 LazyCallGraph &, CGSCCUpdateResult &>; 0319 0320 explicit ModuleToPostOrderCGSCCPassAdaptor(std::unique_ptr<PassConceptT> Pass) 0321 : Pass(std::move(Pass)) {} 0322 0323 ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) 0324 : Pass(std::move(Arg.Pass)) {} 0325 0326 friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, 0327 ModuleToPostOrderCGSCCPassAdaptor &RHS) { 0328 std::swap(LHS.Pass, RHS.Pass); 0329 } 0330 0331 ModuleToPostOrderCGSCCPassAdaptor & 0332 operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) { 0333 swap(*this, RHS); 0334 return *this; 0335 } 0336 0337 /// Runs the CGSCC pass across every SCC in the module. 0338 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 0339 0340 void printPipeline(raw_ostream &OS, 0341 function_ref<StringRef(StringRef)> MapClassName2PassName) { 0342 OS << "cgscc("; 0343 Pass->printPipeline(OS, MapClassName2PassName); 0344 OS << ')'; 0345 } 0346 0347 static bool isRequired() { return true; } 0348 0349 private: 0350 std::unique_ptr<PassConceptT> Pass; 0351 }; 0352 0353 /// A function to deduce a function pass type and wrap it in the 0354 /// templated adaptor. 0355 template <typename CGSCCPassT> 0356 ModuleToPostOrderCGSCCPassAdaptor 0357 createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT &&Pass) { 0358 using PassModelT = 0359 detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, CGSCCAnalysisManager, 0360 LazyCallGraph &, CGSCCUpdateResult &>; 0361 // Do not use make_unique, it causes too many template instantiations, 0362 // causing terrible compile times. 0363 return ModuleToPostOrderCGSCCPassAdaptor( 0364 std::unique_ptr<ModuleToPostOrderCGSCCPassAdaptor::PassConceptT>( 0365 new PassModelT(std::forward<CGSCCPassT>(Pass)))); 0366 } 0367 0368 /// A proxy from a \c FunctionAnalysisManager to an \c SCC. 0369 /// 0370 /// When a module pass runs and triggers invalidation, both the CGSCC and 0371 /// Function analysis manager proxies on the module get an invalidation event. 0372 /// We don't want to fully duplicate responsibility for most of the 0373 /// invalidation logic. Instead, this layer is only responsible for SCC-local 0374 /// invalidation events. We work with the module's FunctionAnalysisManager to 0375 /// invalidate function analyses. 0376 class FunctionAnalysisManagerCGSCCProxy 0377 : public AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy> { 0378 public: 0379 class Result { 0380 public: 0381 explicit Result() : FAM(nullptr) {} 0382 explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} 0383 0384 void updateFAM(FunctionAnalysisManager &FAM) { this->FAM = &FAM; } 0385 /// Accessor for the analysis manager. 0386 FunctionAnalysisManager &getManager() { 0387 assert(FAM); 0388 return *FAM; 0389 } 0390 0391 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, 0392 CGSCCAnalysisManager::Invalidator &Inv); 0393 0394 private: 0395 FunctionAnalysisManager *FAM; 0396 }; 0397 0398 /// Computes the \c FunctionAnalysisManager and stores it in the result proxy. 0399 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &); 0400 0401 private: 0402 friend AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy>; 0403 0404 static AnalysisKey Key; 0405 }; 0406 0407 extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>; 0408 0409 /// A proxy from a \c CGSCCAnalysisManager to a \c Function. 0410 using CGSCCAnalysisManagerFunctionProxy = 0411 OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>; 0412 0413 /// Helper to update the call graph after running a function pass. 0414 /// 0415 /// Function passes can only mutate the call graph in specific ways. This 0416 /// routine provides a helper that updates the call graph in those ways 0417 /// including returning whether any changes were made and populating a CG 0418 /// update result struct for the overall CGSCC walk. 0419 LazyCallGraph::SCC &updateCGAndAnalysisManagerForFunctionPass( 0420 LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, 0421 CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, 0422 FunctionAnalysisManager &FAM); 0423 0424 /// Helper to update the call graph after running a CGSCC pass. 0425 /// 0426 /// CGSCC passes can only mutate the call graph in specific ways. This 0427 /// routine provides a helper that updates the call graph in those ways 0428 /// including returning whether any changes were made and populating a CG 0429 /// update result struct for the overall CGSCC walk. 0430 LazyCallGraph::SCC &updateCGAndAnalysisManagerForCGSCCPass( 0431 LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, 0432 CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, 0433 FunctionAnalysisManager &FAM); 0434 0435 /// Adaptor that maps from a SCC to its functions. 0436 /// 0437 /// Designed to allow composition of a FunctionPass(Manager) and 0438 /// a CGSCCPassManager. Note that if this pass is constructed with a pointer 0439 /// to a \c CGSCCAnalysisManager it will run the 0440 /// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function 0441 /// pass over the SCC to enable a \c FunctionAnalysisManager to be used 0442 /// within this run safely. 0443 class CGSCCToFunctionPassAdaptor 0444 : public PassInfoMixin<CGSCCToFunctionPassAdaptor> { 0445 public: 0446 using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>; 0447 0448 explicit CGSCCToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass, 0449 bool EagerlyInvalidate, bool NoRerun) 0450 : Pass(std::move(Pass)), EagerlyInvalidate(EagerlyInvalidate), 0451 NoRerun(NoRerun) {} 0452 0453 CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) 0454 : Pass(std::move(Arg.Pass)), EagerlyInvalidate(Arg.EagerlyInvalidate), 0455 NoRerun(Arg.NoRerun) {} 0456 0457 friend void swap(CGSCCToFunctionPassAdaptor &LHS, 0458 CGSCCToFunctionPassAdaptor &RHS) { 0459 std::swap(LHS.Pass, RHS.Pass); 0460 } 0461 0462 CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) { 0463 swap(*this, RHS); 0464 return *this; 0465 } 0466 0467 /// Runs the function pass across every function in the module. 0468 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 0469 LazyCallGraph &CG, CGSCCUpdateResult &UR); 0470 0471 void printPipeline(raw_ostream &OS, 0472 function_ref<StringRef(StringRef)> MapClassName2PassName) { 0473 OS << "function"; 0474 if (EagerlyInvalidate || NoRerun) { 0475 OS << "<"; 0476 if (EagerlyInvalidate) 0477 OS << "eager-inv"; 0478 if (EagerlyInvalidate && NoRerun) 0479 OS << ";"; 0480 if (NoRerun) 0481 OS << "no-rerun"; 0482 OS << ">"; 0483 } 0484 OS << '('; 0485 Pass->printPipeline(OS, MapClassName2PassName); 0486 OS << ')'; 0487 } 0488 0489 static bool isRequired() { return true; } 0490 0491 private: 0492 std::unique_ptr<PassConceptT> Pass; 0493 bool EagerlyInvalidate; 0494 bool NoRerun; 0495 }; 0496 0497 /// A function to deduce a function pass type and wrap it in the 0498 /// templated adaptor. 0499 template <typename FunctionPassT> 0500 CGSCCToFunctionPassAdaptor 0501 createCGSCCToFunctionPassAdaptor(FunctionPassT &&Pass, 0502 bool EagerlyInvalidate = false, 0503 bool NoRerun = false) { 0504 using PassModelT = 0505 detail::PassModel<Function, FunctionPassT, FunctionAnalysisManager>; 0506 // Do not use make_unique, it causes too many template instantiations, 0507 // causing terrible compile times. 0508 return CGSCCToFunctionPassAdaptor( 0509 std::unique_ptr<CGSCCToFunctionPassAdaptor::PassConceptT>( 0510 new PassModelT(std::forward<FunctionPassT>(Pass))), 0511 EagerlyInvalidate, NoRerun); 0512 } 0513 0514 // A marker to determine if function passes should be run on a function within a 0515 // CGSCCToFunctionPassAdaptor. This is used to prevent running an expensive 0516 // function pass (manager) on a function multiple times if SCC mutations cause a 0517 // function to be visited multiple times and the function is not modified by 0518 // other SCC passes. 0519 class ShouldNotRunFunctionPassesAnalysis 0520 : public AnalysisInfoMixin<ShouldNotRunFunctionPassesAnalysis> { 0521 public: 0522 static AnalysisKey Key; 0523 struct Result {}; 0524 0525 Result run(Function &F, FunctionAnalysisManager &FAM) { return Result(); } 0526 }; 0527 0528 /// A helper that repeats an SCC pass each time an indirect call is refined to 0529 /// a direct call by that pass. 0530 /// 0531 /// While the CGSCC pass manager works to re-visit SCCs and RefSCCs as they 0532 /// change shape, we may also want to repeat an SCC pass if it simply refines 0533 /// an indirect call to a direct call, even if doing so does not alter the 0534 /// shape of the graph. Note that this only pertains to direct calls to 0535 /// functions where IPO across the SCC may be able to compute more precise 0536 /// results. For intrinsics, we assume scalar optimizations already can fully 0537 /// reason about them. 0538 /// 0539 /// This repetition has the potential to be very large however, as each one 0540 /// might refine a single call site. As a consequence, in practice we use an 0541 /// upper bound on the number of repetitions to limit things. 0542 class DevirtSCCRepeatedPass : public PassInfoMixin<DevirtSCCRepeatedPass> { 0543 public: 0544 using PassConceptT = 0545 detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager, 0546 LazyCallGraph &, CGSCCUpdateResult &>; 0547 0548 explicit DevirtSCCRepeatedPass(std::unique_ptr<PassConceptT> Pass, 0549 int MaxIterations) 0550 : Pass(std::move(Pass)), MaxIterations(MaxIterations) {} 0551 0552 /// Runs the wrapped pass up to \c MaxIterations on the SCC, iterating 0553 /// whenever an indirect call is refined. 0554 PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, 0555 LazyCallGraph &CG, CGSCCUpdateResult &UR); 0556 0557 void printPipeline(raw_ostream &OS, 0558 function_ref<StringRef(StringRef)> MapClassName2PassName) { 0559 OS << "devirt<" << MaxIterations << ">("; 0560 Pass->printPipeline(OS, MapClassName2PassName); 0561 OS << ')'; 0562 } 0563 0564 private: 0565 std::unique_ptr<PassConceptT> Pass; 0566 int MaxIterations; 0567 }; 0568 0569 /// A function to deduce a function pass type and wrap it in the 0570 /// templated adaptor. 0571 template <typename CGSCCPassT> 0572 DevirtSCCRepeatedPass createDevirtSCCRepeatedPass(CGSCCPassT &&Pass, 0573 int MaxIterations) { 0574 using PassModelT = 0575 detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, CGSCCAnalysisManager, 0576 LazyCallGraph &, CGSCCUpdateResult &>; 0577 // Do not use make_unique, it causes too many template instantiations, 0578 // causing terrible compile times. 0579 return DevirtSCCRepeatedPass( 0580 std::unique_ptr<DevirtSCCRepeatedPass::PassConceptT>( 0581 new PassModelT(std::forward<CGSCCPassT>(Pass))), 0582 MaxIterations); 0583 } 0584 0585 // Clear out the debug logging macro. 0586 #undef DEBUG_TYPE 0587 0588 } // end namespace llvm 0589 0590 #endif // LLVM_ANALYSIS_CGSCCPASSMANAGER_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|