1//===- CGSCCPassManager.h - Call graph pass management ----------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8/// \file 9/// 10/// This header provides classes for managing passes over SCCs of the call 11/// graph. These passes form an important component of LLVM's interprocedural 12/// optimizations. Because they operate on the SCCs of the call graph, and they 13/// traverse the graph in post-order, they can effectively do pair-wise 14/// interprocedural optimizations for all call edges in the program while 15/// incrementally refining it and improving the context of these pair-wise 16/// optimizations. At each call site edge, the callee has already been 17/// optimized as much as is possible. This in turn allows very accurate 18/// analysis of it for IPO. 19/// 20/// A secondary more general goal is to be able to isolate optimization on 21/// unrelated parts of the IR module. This is useful to ensure our 22/// optimizations are principled and don't miss oportunities where refinement 23/// of one part of the module influence transformations in another part of the 24/// module. But this is also useful if we want to parallelize the optimizations 25/// across common large module graph shapes which tend to be very wide and have 26/// large regions of unrelated cliques. 27/// 28/// To satisfy these goals, we use the LazyCallGraph which provides two graphs 29/// nested inside each other (and built lazily from the bottom-up): the call 30/// graph proper, and a reference graph. The reference graph is super set of 31/// the call graph and is a conservative approximation of what could through 32/// scalar or CGSCC transforms *become* the call graph. Using this allows us to 33/// ensure we optimize functions prior to them being introduced into the call 34/// graph by devirtualization or other technique, and thus ensures that 35/// subsequent pair-wise interprocedural optimizations observe the optimized 36/// form of these functions. The (potentially transitive) reference 37/// reachability used by the reference graph is a conservative approximation 38/// that still allows us to have independent regions of the graph. 39/// 40/// FIXME: There is one major drawback of the reference graph: in its naive 41/// form it is quadratic because it contains a distinct edge for each 42/// (potentially indirect) reference, even if are all through some common 43/// global table of function pointers. This can be fixed in a number of ways 44/// that essentially preserve enough of the normalization. While it isn't 45/// expected to completely preclude the usability of this, it will need to be 46/// addressed. 47/// 48/// 49/// All of these issues are made substantially more complex in the face of 50/// mutations to the call graph while optimization passes are being run. When 51/// mutations to the call graph occur we want to achieve two different things: 52/// 53/// - We need to update the call graph in-flight and invalidate analyses 54/// cached on entities in the graph. Because of the cache-based analysis 55/// design of the pass manager, it is essential to have stable identities for 56/// the elements of the IR that passes traverse, and to invalidate any 57/// analyses cached on these elements as the mutations take place. 58/// 59/// - We want to preserve the incremental and post-order traversal of the 60/// graph even as it is refined and mutated. This means we want optimization 61/// to observe the most refined form of the call graph and to do so in 62/// post-order. 63/// 64/// To address this, the CGSCC manager uses both worklists that can be expanded 65/// by passes which transform the IR, and provides invalidation tests to skip 66/// entries that become dead. This extra data is provided to every SCC pass so 67/// that it can carefully update the manager's traversal as the call graph 68/// mutates. 69/// 70/// We also provide support for running function passes within the CGSCC walk, 71/// and there we provide automatic update of the call graph including of the 72/// pass manager to reflect call graph changes that fall out naturally as part 73/// of scalar transformations. 74/// 75/// The patterns used to ensure the goals of post-order visitation of the fully 76/// refined graph: 77/// 78/// 1) Sink toward the "bottom" as the graph is refined. This means that any 79/// iteration continues in some valid post-order sequence after the mutation 80/// has altered the structure. 81/// 82/// 2) Enqueue in post-order, including the current entity. If the current 83/// entity's shape changes, it and everything after it in post-order needs 84/// to be visited to observe that shape. 85/// 86//===----------------------------------------------------------------------===// 87 88#ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H 89#define LLVM_ANALYSIS_CGSCCPASSMANAGER_H 90 91#include "llvm/ADT/DenseMap.h" 92#include "llvm/ADT/DenseSet.h" 93#include "llvm/ADT/MapVector.h" 94#include "llvm/ADT/PriorityWorklist.h" 95#include "llvm/ADT/STLExtras.h" 96#include "llvm/ADT/SmallPtrSet.h" 97#include "llvm/ADT/SmallVector.h" 98#include "llvm/Analysis/LazyCallGraph.h" 99#include "llvm/IR/Function.h" 100#include "llvm/IR/InstIterator.h" 101#include "llvm/IR/PassManager.h" 102#include "llvm/IR/ValueHandle.h" 103#include "llvm/Support/Debug.h" 104#include "llvm/Support/raw_ostream.h" 105#include <algorithm> 106#include <cassert> 107#include <utility> 108 109namespace llvm { 110 111struct CGSCCUpdateResult; 112class Module; 113 114// Allow debug logging in this inline function. 115#define DEBUG_TYPE "cgscc" 116 117/// Extern template declaration for the analysis set for this IR unit. 118extern template class AllAnalysesOn<LazyCallGraph::SCC>; 119 120extern template class AnalysisManager<LazyCallGraph::SCC, LazyCallGraph &>; 121 122/// The CGSCC analysis manager. 123/// 124/// See the documentation for the AnalysisManager template for detail 125/// documentation. This type serves as a convenient way to refer to this 126/// construct in the adaptors and proxies used to integrate this into the larger 127/// pass manager infrastructure. 128using CGSCCAnalysisManager = 129 AnalysisManager<LazyCallGraph::SCC, LazyCallGraph &>; 130 131// Explicit specialization and instantiation declarations for the pass manager. 132// See the comments on the definition of the specialization for details on how 133// it differs from the primary template. 134template <> 135PreservedAnalyses 136PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, 137 CGSCCUpdateResult &>::run(LazyCallGraph::SCC &InitialC, 138 CGSCCAnalysisManager &AM, 139 LazyCallGraph &G, CGSCCUpdateResult &UR); 140extern template class PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, 141 LazyCallGraph &, CGSCCUpdateResult &>; 142 143/// The CGSCC pass manager. 144/// 145/// See the documentation for the PassManager template for details. It runs 146/// a sequence of SCC passes over each SCC that the manager is run over. This 147/// type serves as a convenient way to refer to this construct. 148using CGSCCPassManager = 149 PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, 150 CGSCCUpdateResult &>; 151 152/// An explicit specialization of the require analysis template pass. 153template <typename AnalysisT> 154struct RequireAnalysisPass<AnalysisT, LazyCallGraph::SCC, CGSCCAnalysisManager, 155 LazyCallGraph &, CGSCCUpdateResult &> 156 : PassInfoMixin<RequireAnalysisPass<AnalysisT, LazyCallGraph::SCC, 157 CGSCCAnalysisManager, LazyCallGraph &, 158 CGSCCUpdateResult &>> { 159 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 160 LazyCallGraph &CG, CGSCCUpdateResult &) { 161 (void)AM.template getResult<AnalysisT>(C, CG); 162 return PreservedAnalyses::all(); 163 } 164}; 165 166/// A proxy from a \c CGSCCAnalysisManager to a \c Module. 167using CGSCCAnalysisManagerModuleProxy = 168 InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>; 169 170/// We need a specialized result for the \c CGSCCAnalysisManagerModuleProxy so 171/// it can have access to the call graph in order to walk all the SCCs when 172/// invalidating things. 173template <> class CGSCCAnalysisManagerModuleProxy::Result { 174public: 175 explicit Result(CGSCCAnalysisManager &InnerAM, LazyCallGraph &G) 176 : InnerAM(&InnerAM), G(&G) {} 177 178 /// Accessor for the analysis manager. 179 CGSCCAnalysisManager &getManager() { return *InnerAM; } 180 181 /// Handler for invalidation of the Module. 182 /// 183 /// If the proxy analysis itself is preserved, then we assume that the set of 184 /// SCCs in the Module hasn't changed. Thus any pointers to SCCs in the 185 /// CGSCCAnalysisManager are still valid, and we don't need to call \c clear 186 /// on the CGSCCAnalysisManager. 187 /// 188 /// Regardless of whether this analysis is marked as preserved, all of the 189 /// analyses in the \c CGSCCAnalysisManager are potentially invalidated based 190 /// on the set of preserved analyses. 191 bool invalidate(Module &M, const PreservedAnalyses &PA, 192 ModuleAnalysisManager::Invalidator &Inv); 193 194private: 195 CGSCCAnalysisManager *InnerAM; 196 LazyCallGraph *G; 197}; 198 199/// Provide a specialized run method for the \c CGSCCAnalysisManagerModuleProxy 200/// so it can pass the lazy call graph to the result. 201template <> 202CGSCCAnalysisManagerModuleProxy::Result 203CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager &AM); 204 205// Ensure the \c CGSCCAnalysisManagerModuleProxy is provided as an extern 206// template. 207extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>; 208 209extern template class OuterAnalysisManagerProxy< 210 ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>; 211 212/// A proxy from a \c ModuleAnalysisManager to an \c SCC. 213using ModuleAnalysisManagerCGSCCProxy = 214 OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC, 215 LazyCallGraph &>; 216 217/// Support structure for SCC passes to communicate updates the call graph back 218/// to the CGSCC pass manager infrsatructure. 219/// 220/// The CGSCC pass manager runs SCC passes which are allowed to update the call 221/// graph and SCC structures. This means the structure the pass manager works 222/// on is mutating underneath it. In order to support that, there needs to be 223/// careful communication about the precise nature and ramifications of these 224/// updates to the pass management infrastructure. 225/// 226/// All SCC passes will have to accept a reference to the management layer's 227/// update result struct and use it to reflect the results of any CG updates 228/// performed. 229/// 230/// Passes which do not change the call graph structure in any way can just 231/// ignore this argument to their run method. 232struct CGSCCUpdateResult { 233 /// Worklist of the RefSCCs queued for processing. 234 /// 235 /// When a pass refines the graph and creates new RefSCCs or causes them to 236 /// have a different shape or set of component SCCs it should add the RefSCCs 237 /// to this worklist so that we visit them in the refined form. 238 /// 239 /// This worklist is in reverse post-order, as we pop off the back in order 240 /// to observe RefSCCs in post-order. When adding RefSCCs, clients should add 241 /// them in reverse post-order. 242 SmallPriorityWorklist<LazyCallGraph::RefSCC *, 1> &RCWorklist; 243 244 /// Worklist of the SCCs queued for processing. 245 /// 246 /// When a pass refines the graph and creates new SCCs or causes them to have 247 /// a different shape or set of component functions it should add the SCCs to 248 /// this worklist so that we visit them in the refined form. 249 /// 250 /// Note that if the SCCs are part of a RefSCC that is added to the \c 251 /// RCWorklist, they don't need to be added here as visiting the RefSCC will 252 /// be sufficient to re-visit the SCCs within it. 253 /// 254 /// This worklist is in reverse post-order, as we pop off the back in order 255 /// to observe SCCs in post-order. When adding SCCs, clients should add them 256 /// in reverse post-order. 257 SmallPriorityWorklist<LazyCallGraph::SCC *, 1> &CWorklist; 258 259 /// The set of invalidated RefSCCs which should be skipped if they are found 260 /// in \c RCWorklist. 261 /// 262 /// This is used to quickly prune out RefSCCs when they get deleted and 263 /// happen to already be on the worklist. We use this primarily to avoid 264 /// scanning the list and removing entries from it. 265 SmallPtrSetImpl<LazyCallGraph::RefSCC *> &InvalidatedRefSCCs; 266 267 /// The set of invalidated SCCs which should be skipped if they are found 268 /// in \c CWorklist. 269 /// 270 /// This is used to quickly prune out SCCs when they get deleted and happen 271 /// to already be on the worklist. We use this primarily to avoid scanning 272 /// the list and removing entries from it. 273 SmallPtrSetImpl<LazyCallGraph::SCC *> &InvalidatedSCCs; 274 275 /// If non-null, the updated current \c RefSCC being processed. 276 /// 277 /// This is set when a graph refinement takes place an the "current" point in 278 /// the graph moves "down" or earlier in the post-order walk. This will often 279 /// cause the "current" RefSCC to be a newly created RefSCC object and the 280 /// old one to be added to the above worklist. When that happens, this 281 /// pointer is non-null and can be used to continue processing the "top" of 282 /// the post-order walk. 283 LazyCallGraph::RefSCC *UpdatedRC; 284 285 /// If non-null, the updated current \c SCC being processed. 286 /// 287 /// This is set when a graph refinement takes place an the "current" point in 288 /// the graph moves "down" or earlier in the post-order walk. This will often 289 /// cause the "current" SCC to be a newly created SCC object and the old one 290 /// to be added to the above worklist. When that happens, this pointer is 291 /// non-null and can be used to continue processing the "top" of the 292 /// post-order walk. 293 LazyCallGraph::SCC *UpdatedC; 294 295 /// Preserved analyses across SCCs. 296 /// 297 /// We specifically want to allow CGSCC passes to mutate ancestor IR 298 /// (changing both the CG structure and the function IR itself). However, 299 /// this means we need to take special care to correctly mark what analyses 300 /// are preserved *across* SCCs. We have to track this out-of-band here 301 /// because within the main `PassManeger` infrastructure we need to mark 302 /// everything within an SCC as preserved in order to avoid repeatedly 303 /// invalidating the same analyses as we unnest pass managers and adaptors. 304 /// So we track the cross-SCC version of the preserved analyses here from any 305 /// code that does direct invalidation of SCC analyses, and then use it 306 /// whenever we move forward in the post-order walk of SCCs before running 307 /// passes over the new SCC. 308 PreservedAnalyses CrossSCCPA; 309 310 /// A hacky area where the inliner can retain history about inlining 311 /// decisions that mutated the call graph's SCC structure in order to avoid 312 /// infinite inlining. See the comments in the inliner's CG update logic. 313 /// 314 /// FIXME: Keeping this here seems like a big layering issue, we should look 315 /// for a better technique. 316 SmallDenseSet<std::pair<LazyCallGraph::Node *, LazyCallGraph::SCC *>, 4> 317 &InlinedInternalEdges; 318 319 /// Weak VHs to keep track of indirect calls for the purposes of detecting 320 /// devirtualization. 321 /// 322 /// This is a map to avoid having duplicate entries. If a Value is 323 /// deallocated, its corresponding WeakTrackingVH will be nulled out. When 324 /// checking if a Value is in the map or not, also check if the corresponding 325 /// WeakTrackingVH is null to avoid issues with a new Value sharing the same 326 /// address as a deallocated one. 327 SmallMapVector<Value *, WeakTrackingVH, 16> IndirectVHs; 328}; 329 330/// The core module pass which does a post-order walk of the SCCs and 331/// runs a CGSCC pass over each one. 332/// 333/// Designed to allow composition of a CGSCCPass(Manager) and 334/// a ModulePassManager. Note that this pass must be run with a module analysis 335/// manager as it uses the LazyCallGraph analysis. It will also run the 336/// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC 337/// pass over the module to enable a \c FunctionAnalysisManager to be used 338/// within this run safely. 339class ModuleToPostOrderCGSCCPassAdaptor 340 : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor> { 341public: 342 using PassConceptT = 343 detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager, 344 LazyCallGraph &, CGSCCUpdateResult &>; 345 346 explicit ModuleToPostOrderCGSCCPassAdaptor(std::unique_ptr<PassConceptT> Pass) 347 : Pass(std::move(Pass)) {} 348 349 ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) 350 : Pass(std::move(Arg.Pass)) {} 351 352 friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, 353 ModuleToPostOrderCGSCCPassAdaptor &RHS) { 354 std::swap(LHS.Pass, RHS.Pass); 355 } 356 357 ModuleToPostOrderCGSCCPassAdaptor & 358 operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) { 359 swap(*this, RHS); 360 return *this; 361 } 362 363 /// Runs the CGSCC pass across every SCC in the module. 364 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 365 366 static bool isRequired() { return true; } 367 368private: 369 std::unique_ptr<PassConceptT> Pass; 370}; 371 372/// A function to deduce a function pass type and wrap it in the 373/// templated adaptor. 374template <typename CGSCCPassT> 375ModuleToPostOrderCGSCCPassAdaptor 376createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) { 377 using PassModelT = detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, 378 PreservedAnalyses, CGSCCAnalysisManager, 379 LazyCallGraph &, CGSCCUpdateResult &>; 380 return ModuleToPostOrderCGSCCPassAdaptor( 381 std::make_unique<PassModelT>(std::move(Pass))); 382} 383 384/// A proxy from a \c FunctionAnalysisManager to an \c SCC. 385/// 386/// When a module pass runs and triggers invalidation, both the CGSCC and 387/// Function analysis manager proxies on the module get an invalidation event. 388/// We don't want to fully duplicate responsibility for most of the 389/// invalidation logic. Instead, this layer is only responsible for SCC-local 390/// invalidation events. We work with the module's FunctionAnalysisManager to 391/// invalidate function analyses. 392class FunctionAnalysisManagerCGSCCProxy 393 : public AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy> { 394public: 395 class Result { 396 public: 397 explicit Result() : FAM(nullptr) {} 398 explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} 399 400 void updateFAM(FunctionAnalysisManager &FAM) { this->FAM = &FAM; } 401 /// Accessor for the analysis manager. 402 FunctionAnalysisManager &getManager() { 403 assert(FAM); 404 return *FAM; 405 } 406 407 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, 408 CGSCCAnalysisManager::Invalidator &Inv); 409 410 private: 411 FunctionAnalysisManager *FAM; 412 }; 413 414 /// Computes the \c FunctionAnalysisManager and stores it in the result proxy. 415 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &); 416 417private: 418 friend AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy>; 419 420 static AnalysisKey Key; 421}; 422 423extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>; 424 425/// A proxy from a \c CGSCCAnalysisManager to a \c Function. 426using CGSCCAnalysisManagerFunctionProxy = 427 OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>; 428 429/// Helper to update the call graph after running a function pass. 430/// 431/// Function passes can only mutate the call graph in specific ways. This 432/// routine provides a helper that updates the call graph in those ways 433/// including returning whether any changes were made and populating a CG 434/// update result struct for the overall CGSCC walk. 435LazyCallGraph::SCC &updateCGAndAnalysisManagerForFunctionPass( 436 LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, 437 CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, 438 FunctionAnalysisManager &FAM); 439 440/// Helper to update the call graph after running a CGSCC pass. 441/// 442/// CGSCC passes can only mutate the call graph in specific ways. This 443/// routine provides a helper that updates the call graph in those ways 444/// including returning whether any changes were made and populating a CG 445/// update result struct for the overall CGSCC walk. 446LazyCallGraph::SCC &updateCGAndAnalysisManagerForCGSCCPass( 447 LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, 448 CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, 449 FunctionAnalysisManager &FAM); 450 451/// Adaptor that maps from a SCC to its functions. 452/// 453/// Designed to allow composition of a FunctionPass(Manager) and 454/// a CGSCCPassManager. Note that if this pass is constructed with a pointer 455/// to a \c CGSCCAnalysisManager it will run the 456/// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function 457/// pass over the SCC to enable a \c FunctionAnalysisManager to be used 458/// within this run safely. 459class CGSCCToFunctionPassAdaptor 460 : public PassInfoMixin<CGSCCToFunctionPassAdaptor> { 461public: 462 using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>; 463 464 explicit CGSCCToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass) 465 : Pass(std::move(Pass)) {} 466 467 CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) 468 : Pass(std::move(Arg.Pass)) {} 469 470 friend void swap(CGSCCToFunctionPassAdaptor &LHS, 471 CGSCCToFunctionPassAdaptor &RHS) { 472 std::swap(LHS.Pass, RHS.Pass); 473 } 474 475 CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) { 476 swap(*this, RHS); 477 return *this; 478 } 479 480 /// Runs the function pass across every function in the module. 481 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 482 LazyCallGraph &CG, CGSCCUpdateResult &UR); 483 484 static bool isRequired() { return true; } 485 486private: 487 std::unique_ptr<PassConceptT> Pass; 488}; 489 490/// A function to deduce a function pass type and wrap it in the 491/// templated adaptor. 492template <typename FunctionPassT> 493CGSCCToFunctionPassAdaptor 494createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) { 495 using PassModelT = 496 detail::PassModel<Function, FunctionPassT, PreservedAnalyses, 497 FunctionAnalysisManager>; 498 return CGSCCToFunctionPassAdaptor( 499 std::make_unique<PassModelT>(std::move(Pass))); 500} 501 502/// A helper that repeats an SCC pass each time an indirect call is refined to 503/// a direct call by that pass. 504/// 505/// While the CGSCC pass manager works to re-visit SCCs and RefSCCs as they 506/// change shape, we may also want to repeat an SCC pass if it simply refines 507/// an indirect call to a direct call, even if doing so does not alter the 508/// shape of the graph. Note that this only pertains to direct calls to 509/// functions where IPO across the SCC may be able to compute more precise 510/// results. For intrinsics, we assume scalar optimizations already can fully 511/// reason about them. 512/// 513/// This repetition has the potential to be very large however, as each one 514/// might refine a single call site. As a consequence, in practice we use an 515/// upper bound on the number of repetitions to limit things. 516class DevirtSCCRepeatedPass : public PassInfoMixin<DevirtSCCRepeatedPass> { 517public: 518 using PassConceptT = 519 detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager, 520 LazyCallGraph &, CGSCCUpdateResult &>; 521 522 explicit DevirtSCCRepeatedPass(std::unique_ptr<PassConceptT> Pass, 523 int MaxIterations) 524 : Pass(std::move(Pass)), MaxIterations(MaxIterations) {} 525 526 /// Runs the wrapped pass up to \c MaxIterations on the SCC, iterating 527 /// whenever an indirect call is refined. 528 PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, 529 LazyCallGraph &CG, CGSCCUpdateResult &UR); 530 531private: 532 std::unique_ptr<PassConceptT> Pass; 533 int MaxIterations; 534}; 535 536/// A function to deduce a function pass type and wrap it in the 537/// templated adaptor. 538template <typename CGSCCPassT> 539DevirtSCCRepeatedPass createDevirtSCCRepeatedPass(CGSCCPassT Pass, 540 int MaxIterations) { 541 using PassModelT = detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, 542 PreservedAnalyses, CGSCCAnalysisManager, 543 LazyCallGraph &, CGSCCUpdateResult &>; 544 return DevirtSCCRepeatedPass(std::make_unique<PassModelT>(std::move(Pass)), 545 MaxIterations); 546} 547 548// Clear out the debug logging macro. 549#undef DEBUG_TYPE 550 551} // end namespace llvm 552 553#endif // LLVM_ANALYSIS_CGSCCPASSMANAGER_H 554