41 dbgs() <<
"Starting CGSCC pass manager run.\n";
47 for (
auto &
Pass : Passes) {
49 dbgs() <<
"Running pass: " <<
Pass->name() <<
" on " << *C <<
"\n";
82 dbgs() <<
"Finished CGSCC pass manager run.\n";
116 bool AreSCCAnalysesPreserved =
120 for (
auto &RC :
G->postorder_ref_sccs())
127 if (
auto *OuterProxy =
129 for (
const auto &OuterInvalidationPair :
130 OuterProxy->getOuterInvalidations()) {
131 AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first;
132 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
136 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
137 InnerPA->
abandon(InnerAnalysisID);
144 InnerAM->invalidate(
C, *InnerPA);
150 if (!AreSCCAnalysesPreserved)
151 InnerAM->invalidate(
C, PA);
170 AnalysisKey FunctionAnalysisManagerCGSCCProxy::Key;
182 Module &M = *C.begin()->getFunction().getParent();
184 assert(FAMProxy &&
"The CGSCC pass manager requires that the FAM module "
185 "proxy is run on the module prior to entering the CGSCC "
192 return Result(FAMProxy->getManager());
199 FAM->invalidate(
N.getFunction(), PA);
221 template <
typename SCCRangeT>
223 incorporateNewSCCRange(
const SCCRangeT &NewSCCRange,
LazyCallGraph &
G,
226 bool DebugLogging =
false) {
229 if (NewSCCRange.begin() == NewSCCRange.end())
235 dbgs() <<
"Enqueuing the existing SCC in the worklist:" << *C <<
"\n";
243 "Cannot insert new SCCs without changing current SCC!");
244 C = &*NewSCCRange.
begin();
249 assert(C != &NewC &&
"No need to re-visit the current SCC!");
250 assert(OldC != &NewC &&
"Already handled the original SCC!");
253 dbgs() <<
"Enqueuing a newly formed SCC:" << NewC <<
"\n";
269 RefSCC *RC = &InitialRC;
285 if (
Function *Callee = CS.getCalledFunction())
286 if (Visited.
insert(Callee).second && !Callee->isDeclaration()) {
287 const Edge *
E = N.
lookup(*Callee);
293 assert(E &&
"No function transformations should introduce *new* "
294 "call edges! Any new calls should be modeled as "
295 "promoted existing ref edges!");
296 RetainedEdges.
insert(Callee);
298 PromotedRefTargets.
insert(Callee);
303 for (
Value *
Op :
I.operand_values())
305 if (Visited.
insert(C).second)
309 const Edge *
E = N.
lookup(Referee);
312 assert(E &&
"No function transformations should introduce *new* ref "
313 "edges! Any new ref edges would require IPO which "
314 "function passes aren't allowed to do!");
315 RetainedEdges.
insert(&Referee);
317 DemotedCallTargets.
insert(&Referee);
325 if (!RetainedEdges.
count(&
E.getFunction()))
327 for (
auto DeadTarget : DeadTargets) {
328 Node &TargetN = *DeadTarget.getPointer();
329 bool IsCall = DeadTarget.getInt() ==
Edge::Call;
333 if (&TargetRC != RC) {
336 dbgs() <<
"Deleting outgoing edge from '" << N <<
"' to '" << TargetN
341 dbgs() <<
"Deleting internal " << (IsCall ?
"call" :
"ref")
342 <<
" edge from '" << N <<
"' to '" << TargetN <<
"'\n";
347 RC->switchTrivialInternalEdgeToRef(N, TargetN);
358 C = incorporateNewSCCRange(RC->switchInternalEdgeToRef(N, TargetN),
G,
359 N,
C, AM, UR, DebugLogging);
363 auto NewRefSCCs = RC->removeInternalRefEdge(N, TargetN);
364 if (!NewRefSCCs.empty()) {
377 dbgs() <<
"Enqueuing the existing RefSCC in the update worklist: "
380 assert(G.
lookupSCC(N) == C &&
"Changed the SCC when splitting RefSCCs!");
381 RC = &C->getOuterRefSCC();
383 assert(NewRefSCCs.front() == RC &&
384 "New current RefSCC not first in the returned list!");
386 make_range(std::next(NewRefSCCs.begin()), NewRefSCCs.end()))) {
387 assert(NewRC != RC &&
"Should not encounter the current RefSCC further "
388 "in the postorder list of new RefSCCs.");
391 dbgs() <<
"Enqueuing a new RefSCC in the update worklist: " << *NewRC
400 for (
Function *RefTarget : DemotedCallTargets) {
401 Node &TargetN = *G.
lookup(*RefTarget);
407 if (&TargetRC != RC) {
408 assert(RC->isAncestorOf(TargetRC) &&
409 "Cannot potentially form RefSCC cycles here!");
410 RC->switchOutgoingEdgeToRef(N, TargetN);
412 dbgs() <<
"Switch outgoing call edge to a ref edge from '" << N
413 <<
"' to '" << TargetN <<
"'\n";
421 RC->switchTrivialInternalEdgeToRef(N, TargetN);
433 C = incorporateNewSCCRange(RC->switchInternalEdgeToRef(N, TargetN),
G,
434 N,
C, AM, UR, DebugLogging);
438 for (
Function *CallTarget : PromotedRefTargets) {
439 Node &TargetN = *G.
lookup(*CallTarget);
445 if (&TargetRC != RC) {
446 assert(RC->isAncestorOf(TargetRC) &&
447 "Cannot potentially form RefSCC cycles here!");
448 RC->switchOutgoingEdgeToCall(N, TargetN);
450 dbgs() <<
"Switch outgoing ref edge to a call edge from '" << N
451 <<
"' to '" << TargetN <<
"'\n";
455 dbgs() <<
"Switch an internal ref edge to a call edge from '" << N
456 <<
"' to '" << TargetN <<
"'\n";
462 auto InitialSCCIndex = RC->find(*C) - RC->begin();
463 auto InvalidatedSCCs = RC->switchInternalEdgeToCall(N, TargetN);
464 if (!InvalidatedSCCs.empty()) {
472 for (SCC *InvalidatedC : InvalidatedSCCs) {
473 assert(InvalidatedC != C &&
"Cannot invalidate the current SCC!");
478 AM.
clear(*InvalidatedC);
481 auto NewSCCIndex = RC->find(*C) - RC->begin();
482 if (InitialSCCIndex < NewSCCIndex) {
489 dbgs() <<
"Enqueuing the existing SCC in the worklist: " << *C <<
"\n";
492 RC->begin() + NewSCCIndex))) {
495 dbgs() <<
"Enqueuing a newly earlier in post-order SCC: " << MovedC
503 assert(&C->getOuterRefSCC() == RC &&
"Current SCC not in current RefSCC!");
507 if (RC != &InitialRC)
Pass interface - Implemented by all 'passes'.
void abandon()
Mark an analysis as abandoned.
SCC * lookupSCC(Node &N) const
Lookup a function's SCC in the graph.
void push_back(const T &Elt)
Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &)
Computes the FunctionAnalysisManager and stores it in the result proxy.
bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA)
Trigger the invalidation of some other analysis pass if not already handled and return whether it was...
void removeOutgoingEdge(Node &SourceN, Node &TargetN)
Remove an edge whose source is in this RefSCC and target is not.
SmallPriorityWorklist< LazyCallGraph::RefSCC *, 1 > & RCWorklist
Worklist of the RefSCCs queued for processing.
void intersect(const PreservedAnalyses &Arg)
Intersect this set with another in place.
A Module instance is used to store all the information related to an LLVM module. ...
size_type count(PtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
LazyCallGraph::SCC * UpdatedC
If non-null, the updated current SCC being processed.
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
A RefSCC of the call graph.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A lazily constructed view of the call graph of a module.
Result run(IRUnitT &IR, AnalysisManager< IRUnitT, ExtraArgTs...> &AM, ExtraArgTs...)
Run the analysis pass and create our proxy result object.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
A set of analyses that are preserved following a run of a transformation pass.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs...ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This is an important base class in LLVM.
SmallPtrSetImpl< LazyCallGraph::RefSCC * > & InvalidatedRefSCCs
The set of invalidated RefSCCs which should be skipped if they are found in RCWorklist.
SmallPtrSetImpl< LazyCallGraph::SCC * > & InvalidatedSCCs
The set of invalidated SCCs which should be skipped if they are found in CWorklist.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
LazyCallGraph::RefSCC * UpdatedRC
If non-null, the updated current RefSCC being processed.
PreservedAnalysisChecker getChecker() const
Build a checker for this PreservedAnalyses and the specified analysis type.
RefSCC & getOuterRefSCC() const
A node in the call graph.
A class used to represent edges in the call graph.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
bool areAllPreserved() const
Test whether all analyses are preserved (and none are abandoned).
SmallPriorityWorklist< LazyCallGraph::SCC *, 1 > & CWorklist
Worklist of the SCCs queued for processing.
void clear(IRUnitT &IR)
Clear any cached analysis results for a single unit of IR.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Function & getFunction() const
A SetVector that performs no allocations if smaller than a certain size.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
An analysis over an "inner" IR unit that provides access to an analysis manager over a "outer" IR uni...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
void invalidate(IRUnitT &IR)
Invalidate a specific analysis pass for an IR module.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
const Edge * lookup(Function &F) const
static void visitReferences(SmallVectorImpl< Constant * > &Worklist, SmallPtrSetImpl< Constant * > &Visited, CallbackT Callback)
Recursively visits the defined functions whose address is reachable from every constant in the Workli...
bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA, typename AnalysisManager< IRUnitT, ExtraArgTs...>::Invalidator &Inv)
Handler for invalidation of the outer IR unit, IRUnitT.
Node * lookup(const Function &F) const
Lookup a function in the graph which has already been scanned and added.
Manages a sequence of passes over a particular unit of IR.
void preserveSet()
Mark an analysis set as preserved.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
An analysis pass which computes the call graph for a module.
This header provides classes for managing passes over SCCs of the call graph.
API to communicate dependencies between analyses during invalidation.
bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, CGSCCAnalysisManager::Invalidator &Inv)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This templated class represents "all analyses that operate over \<a particular IR unit\>" (e...
bool allAnalysesInSetPreserved() const
Directly test whether a set of analyses is preserved.
LLVM Value Representation.
An SCC of the call graph.
inst_range instructions(Function *F)
A container for analyses that lazily runs them and caches their results.
RefSCC * lookupRefSCC(Node &N) const
Lookup a function's RefSCC in the graph.
LazyCallGraph::SCC & updateCGAndAnalysisManagerForFunctionPass(LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, bool DebugLogging=false)
Helper to update the call graph after running a function pass.
A special type used by analysis passes to provide an address that identifies that particular analysis...
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...