34#define DEBUG_TYPE "cgscc"
42 "abort-on-max-devirt-iterations-reached",
43 cl::desc(
"Abort when the max iterations for devirtualization CGSCC repeat "
95 ResultFAMCP->updateFAM(
FAM);
100 PA.intersect(PassPA);
106 LLVM_DEBUG(
dbgs() <<
"Skipping invalidated root or island SCC!\n");
111 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
158 InlinedInternalEdges;
166 InlinedInternalEdges,
179 "Should always start with an empty RefSCC worklist");
196 "Should always start with an empty SCC worklist");
198 LLVM_DEBUG(
dbgs() <<
"Running an SCC pass across the RefSCC: " << *RC
218 if (InvalidSCCSet.
count(
C)) {
222 if (LastUpdatedC ==
C) {
262 assert(!InvalidSCCSet.
count(
C) &&
"Processing an invalid SCC!");
263 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
291 PA.intersect(PassPA);
297 LLVM_DEBUG(
dbgs() <<
"Skipping invalidated root or island SCC!\n");
302 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
325 <<
"Re-running SCC passes after a refinement of the "
333 }
while (!CWorklist.
empty());
338 InlinedInternalEdges.
clear();
339 }
while (!RCWorklist.
empty());
343 for (
Function *DeadF : DeadFunctions)
344 DeadF->eraseFromParent();
346#if defined(EXPENSIVE_CHECKS)
383 assert(CallHandles.empty() &&
"Must start with a clear set of handles.");
386 CallCount CountLocal = {0, 0};
389 CallCounts.
insert(std::make_pair(&
N.getFunction(), CountLocal))
392 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
393 if (CB->getCalledFunction()) {
409 for (
int Iteration = 0;; ++Iteration) {
421 LLVM_DEBUG(
dbgs() <<
"Skipping invalidated root or island SCC!\n");
436 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
441 if (CallBase *CB = dyn_cast<CallBase>(P.second)) {
442 if (CB->getCalledFunction()) {
443 LLVM_DEBUG(dbgs() <<
"Found devirtualized call: " << *CB <<
"\n");
465 for (
auto &Pair : NewCallCounts) {
466 auto &CallCountNew = Pair.second;
467 auto CountIt = CallCounts.find(Pair.first);
468 if (CountIt != CallCounts.end()) {
469 const auto &CallCountOld = CountIt->second;
470 if (CallCountOld.Indirect > CallCountNew.Indirect &&
471 CallCountOld.Direct < CallCountNew.Direct) {
483 if (Iteration >= MaxIterations) {
487 dbgs() <<
"Found another devirtualization after hitting the max "
488 "number of repetitions ("
489 << MaxIterations <<
") on SCC: " << *
C <<
"\n");
494 dbgs() <<
"Repeating an SCC pass after finding a devirtualization in: "
498 CallCounts = std::move(NewCallCounts);
524 LLVM_DEBUG(
dbgs() <<
"Running function passes across an SCC: " <<
C <<
"\n");
564 "Current SCC not updated to the SCC containing the current node!");
581bool CGSCCAnalysisManagerModuleProxy::Result::invalidate(
610 bool AreSCCAnalysesPreserved =
615 for (
auto &RC :
G->postorder_ref_sccs())
617 std::optional<PreservedAnalyses> InnerPA;
622 if (
auto *OuterProxy =
624 for (
const auto &OuterInvalidationPair :
625 OuterProxy->getOuterInvalidations()) {
626 AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first;
627 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
631 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
632 InnerPA->
abandon(InnerAnalysisID);
639 InnerAM->invalidate(
C, *InnerPA);
645 if (!AreSCCAnalysesPreserved)
646 InnerAM->invalidate(
C, PA);
675 Module &M = *
C.begin()->getFunction().getParent();
679 "The CGSCC pass manager requires that the FAM module proxy is run "
680 "on the module prior to entering the CGSCC walk");
713 bool AreFunctionAnalysesPreserved =
720 std::optional<PreservedAnalyses> FunctionPA;
725 if (
auto *OuterProxy =
727 for (
const auto &OuterInvalidationPair :
728 OuterProxy->getOuterInvalidations()) {
729 AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first;
730 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
734 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
735 FunctionPA->
abandon(InnerAnalysisID);
748 if (!AreFunctionAnalysesPreserved)
791 for (
const auto &OuterInvalidationPair :
792 OuterProxy->getOuterInvalidations()) {
793 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
794 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
795 PA.abandon(InnerAnalysisID);
813template <
typename SCCRangeT>
820 if (NewSCCRange.empty())
825 LLVM_DEBUG(
dbgs() <<
"Enqueuing the existing SCC in the worklist:" << *
C
832 assert(
C != &*NewSCCRange.begin() &&
833 "Cannot insert new SCCs without changing current SCC!");
834 C = &*NewSCCRange.begin();
835 assert(
G.lookupSCC(
N) ==
C &&
"Failed to update current SCC!");
842 FAM = &FAMProxy->getManager();
851 auto PA = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>();
860 assert(
C != &NewC &&
"No need to re-visit the current SCC!");
861 assert(OldC != &NewC &&
"Already handled the original SCC!");
863 LLVM_DEBUG(
dbgs() <<
"Enqueuing a newly formed SCC:" << NewC <<
"\n");
887 RefSCC *RC = &InitialRC;
904 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
905 if (
Function *Callee = CB->getCalledFunction()) {
906 if (Visited.
insert(Callee).second && !Callee->isDeclaration()) {
907 Node *CalleeN =
G.lookup(*Callee);
909 "Visited function should already have an associated node");
910 Edge *E =
N->lookup(*CalleeN);
912 "No function transformations should introduce *new* "
913 "call edges! Any new calls should be modeled as "
914 "promoted existing ref edges!");
915 bool Inserted = RetainedEdges.
insert(CalleeN).second;
917 assert(Inserted &&
"We should never visit a function twice.");
919 NewCallEdges.
insert(CalleeN);
920 else if (!E->isCall())
921 PromotedRefTargets.
insert(CalleeN);
929 else if (!Entry->second)
937 for (
Value *
Op :
I.operand_values())
938 if (
auto *OpC = dyn_cast<Constant>(
Op))
939 if (Visited.
insert(OpC).second)
942 auto VisitRef = [&](
Function &Referee) {
943 Node *RefereeN =
G.lookup(Referee);
945 "Visited function should already have an associated node");
946 Edge *E =
N->lookup(*RefereeN);
948 "No function transformations should introduce *new* ref "
949 "edges! Any new ref edges would require IPO which "
950 "function passes aren't allowed to do!");
951 bool Inserted = RetainedEdges.
insert(RefereeN).second;
953 assert(Inserted &&
"We should never visit a function twice.");
955 NewRefEdges.
insert(RefereeN);
956 else if (E->isCall())
957 DemotedCallTargets.
insert(RefereeN);
962 for (
Node *RefTarget : NewRefEdges) {
963 SCC &TargetC = *
G.lookupSCC(*RefTarget);
964 RefSCC &TargetRC = TargetC.getOuterRefSCC();
967#ifdef EXPENSIVE_CHECKS
968 assert((RC == &TargetRC ||
969 RC->isAncestorOf(TargetRC)) &&
"New ref edge is not trivial!");
971 RC->insertTrivialRefEdge(
N, *RefTarget);
975 for (
Node *CallTarget : NewCallEdges) {
976 SCC &TargetC = *
G.lookupSCC(*CallTarget);
977 RefSCC &TargetRC = TargetC.getOuterRefSCC();
980#ifdef EXPENSIVE_CHECKS
981 assert((RC == &TargetRC ||
982 RC->isAncestorOf(TargetRC)) &&
"New call edge is not trivial!");
986 RC->insertTrivialRefEdge(
N, *CallTarget);
990 for (
auto *LibFn :
G.getLibFunctions())
993 if (!Visited.
count(LibFn))
1000 for (Edge &E : *
N) {
1001 if (RetainedEdges.
count(&E.getNode()))
1004 SCC &TargetC = *
G.lookupSCC(E.getNode());
1005 RefSCC &TargetRC = TargetC.getOuterRefSCC();
1006 if (&TargetRC == RC && E.isCall()) {
1007 if (
C != &TargetC) {
1009 RC->switchTrivialInternalEdgeToRef(
N, E.getNode());
1022 SCC &TargetC = *
G.lookupSCC(*TargetN);
1023 RefSCC &TargetRC = TargetC.getOuterRefSCC();
1027 if (&TargetRC == RC)
1031 << *TargetN <<
"'\n");
1032 RC->removeOutgoingEdge(
N, *TargetN);
1039 for (
Node *RefTarget : DemotedCallTargets) {
1040 SCC &TargetC = *
G.lookupSCC(*RefTarget);
1041 RefSCC &TargetRC = TargetC.getOuterRefSCC();
1045 if (&TargetRC != RC) {
1046#ifdef EXPENSIVE_CHECKS
1047 assert(RC->isAncestorOf(TargetRC) &&
1048 "Cannot potentially form RefSCC cycles here!");
1050 RC->switchOutgoingEdgeToRef(
N, *RefTarget);
1051 LLVM_DEBUG(
dbgs() <<
"Switch outgoing call edge to a ref edge from '" <<
N
1052 <<
"' to '" << *RefTarget <<
"'\n");
1058 if (
C != &TargetC) {
1060 RC->switchTrivialInternalEdgeToRef(
N, *RefTarget);
1071 for (
Node *E : NewCallEdges)
1072 PromotedRefTargets.
insert(E);
1075 for (
Node *CallTarget : PromotedRefTargets) {
1076 SCC &TargetC = *
G.lookupSCC(*CallTarget);
1077 RefSCC &TargetRC = TargetC.getOuterRefSCC();
1081 if (&TargetRC != RC) {
1082#ifdef EXPENSIVE_CHECKS
1083 assert(RC->isAncestorOf(TargetRC) &&
1084 "Cannot potentially form RefSCC cycles here!");
1086 RC->switchOutgoingEdgeToCall(
N, *CallTarget);
1087 LLVM_DEBUG(
dbgs() <<
"Switch outgoing ref edge to a call edge from '" <<
N
1088 <<
"' to '" << *CallTarget <<
"'\n");
1091 LLVM_DEBUG(
dbgs() <<
"Switch an internal ref edge to a call edge from '"
1092 <<
N <<
"' to '" << *CallTarget <<
"'\n");
1098 bool HasFunctionAnalysisProxy =
false;
1099 auto InitialSCCIndex = RC->find(*
C) - RC->begin();
1100 bool FormedCycle = RC->switchInternalEdgeToCall(
1102 for (SCC *MergedC : MergedSCCs) {
1103 assert(MergedC != &TargetC &&
"Cannot merge away the target SCC!");
1105 HasFunctionAnalysisProxy |=
1107 *MergedC) !=
nullptr;
1115 auto PA = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>();
1125 assert(
G.lookupSCC(
N) ==
C &&
"Failed to update current SCC!");
1130 if (HasFunctionAnalysisProxy)
1136 auto PA = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>();
1140 auto NewSCCIndex = RC->find(*
C) - RC->begin();
1149 if (InitialSCCIndex < NewSCCIndex) {
1155 LLVM_DEBUG(
dbgs() <<
"Enqueuing the existing SCC in the worklist: " << *
C
1159 RC->begin() + NewSCCIndex))) {
1161 LLVM_DEBUG(
dbgs() <<
"Enqueuing a newly earlier in post-order SCC: "
1168 assert(&
C->getOuterRefSCC() == RC &&
"Current SCC not in current RefSCC!");
Expand Atomic instructions
static LazyCallGraph::SCC & updateCGAndAnalysisManagerForPass(LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, FunctionAnalysisManager &FAM, bool FunctionPass)
static LazyCallGraph::SCC * incorporateNewSCCRange(const SCCRangeT &NewSCCRange, LazyCallGraph &G, LazyCallGraph::Node &N, LazyCallGraph::SCC *C, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR)
Helper function to update both the CGSCCAnalysisManager AM and the CGSCCPassManager's CGSCCUpdateResu...
static void updateNewSCCFunctionAnalyses(LazyCallGraph::SCC &C, LazyCallGraph &G, CGSCCAnalysisManager &AM, FunctionAnalysisManager &FAM)
When a new SCC is created for the graph we first update the FunctionAnalysisManager in the Proxy's re...
This header provides classes for managing passes over SCCs of the call graph.
Implements a lazy call graph analysis and related passes for the new pass manager.
CGSCCAnalysisManager CGAM
Function const char * Passes
FunctionAnalysisManager FAM
Provides implementations for PassManager and AnalysisManager template methods.
This header defines various interfaces for pass management in LLVM.
This file provides a priority worklist.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This templated class represents "all analyses that operate over <a particular IR unit>" (e....
API to communicate dependencies between analyses during invalidation.
bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA)
Trigger the invalidation of some other analysis pass if not already handled and return whether it was...
A container for analyses that lazily runs them and caches their results.
void invalidate(IRUnitT &IR, const PreservedAnalyses &PA)
Invalidate cached analyses for an IR unit.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
We need a specialized result for the CGSCCAnalysisManagerModuleProxy so it can have access to the cal...
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
Runs the function pass across every function in the module.
This class represents an Operation in the Expression.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
Runs the wrapped pass up to MaxIterations on the SCC, iterating whenever an indirect call is refined.
bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, CGSCCAnalysisManager::Invalidator &Inv)
A proxy from a FunctionAnalysisManager to an SCC.
Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &)
Computes the FunctionAnalysisManager and stores it in the result proxy.
FunctionPass class - This class is used to implement most global optimizations.
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
Result run(IRUnitT &IR, AnalysisManager< IRUnitT, ExtraArgTs... > &AM, ExtraArgTs...)
Run the analysis pass and create our proxy result object.
An analysis pass which computes the call graph for a module.
A class used to represent edges in the call graph.
A node in the call graph.
A RefSCC of the call graph.
An SCC of the call graph.
RefSCC & getOuterRefSCC() const
A lazily constructed view of the call graph of a module.
static void visitReferences(SmallVectorImpl< Constant * > &Worklist, SmallPtrSetImpl< Constant * > &Visited, function_ref< void(Function &)> Callback)
Recursively visits the defined functions whose address is reachable from every constant in the Workli...
void removeDeadFunctions(ArrayRef< Function * > DeadFs)
Remove dead functions from the call graph.
SCC * lookupSCC(Node &N) const
Lookup a function's SCC in the graph.
iterator_range< postorder_ref_scc_iterator > postorder_ref_sccs()
void verify()
Verify that every RefSCC is valid.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Runs the CGSCC pass across every SCC in the module.
A Module instance is used to store all the information related to an LLVM module.
An analysis over an "inner" IR unit that provides access to an analysis manager over a "outer" IR uni...
Pseudo-analysis pass that exposes the PassInstrumentation to pass managers.
This class provides instrumentation entry points for the Pass Manager, doing calls to callbacks regis...
void runAfterPassInvalidated(const PassT &Pass, const PreservedAnalyses &PA) const
AfterPassInvalidated instrumentation point - takes Pass instance that has just been executed.
void runAfterPass(const PassT &Pass, const IRUnitT &IR, const PreservedAnalyses &PA) const
AfterPass instrumentation point - takes Pass instance that has just been executed and constant refere...
bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const
BeforePass instrumentation point - takes Pass instance to be executed and constant reference to IR it...
Manages a sequence of passes over a particular unit of IR.
Pass interface - Implemented by all 'passes'.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
bool areAllPreserved() const
Test whether all analyses are preserved (and none are abandoned).
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
bool allAnalysesInSetPreserved() const
Directly test whether a set of analyses is preserved.
void intersect(const PreservedAnalyses &Arg)
Intersect this set with another in place.
void preserveSet()
Mark an analysis set as preserved.
PreservedAnalysisChecker getChecker() const
Build a checker for this PreservedAnalyses and the specified analysis type.
void abandon()
Mark an analysis as abandoned.
void preserve()
Mark an analysis as preserved.
bool empty() const
Determine if the PriorityWorklist is empty or not.
bool insert(const T &X)
Insert a new element into the PriorityWorklist.
bool insert(const value_type &X)
Insert a new element into the SetVector.
Implements a dense probed hash-table based set with some number of buckets stored inline.
A version of PriorityWorklist that selects small size optimized data structures for the vector and ma...
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM Value Representation.
Value handle that is nullable, but tries to track the Value.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
LazyCallGraph::SCC & updateCGAndAnalysisManagerForFunctionPass(LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, FunctionAnalysisManager &FAM)
Helper to update the call graph after running a function pass.
LazyCallGraph::SCC & updateCGAndAnalysisManagerForCGSCCPass(LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, FunctionAnalysisManager &FAM)
Helper to update the call graph after running a CGSCC pass.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static cl::opt< bool > AbortOnMaxDevirtIterationsReached("abort-on-max-devirt-iterations-reached", cl::desc("Abort when the max iterations for devirtualization CGSCC repeat " "pass is reached"))
A special type used by analysis passes to provide an address that identifies that particular analysis...
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
SmallMapVector< Value *, WeakTrackingVH, 16 > IndirectVHs
Weak VHs to keep track of indirect calls for the purposes of detecting devirtualization.
SmallPriorityWorklist< LazyCallGraph::SCC *, 1 > & CWorklist
Worklist of the SCCs queued for processing.
SmallPtrSetImpl< LazyCallGraph::SCC * > & InvalidatedSCCs
The set of invalidated SCCs which should be skipped if they are found in CWorklist.
LazyCallGraph::SCC * UpdatedC
If non-null, the updated current SCC being processed.
PreservedAnalyses CrossSCCPA
Preserved analyses across SCCs.
A MapVector that performs no allocations if smaller than a certain size.