34#define DEBUG_TYPE "cgscc"
38STATISTIC(LargestCGSCC,
"Number of functions in the largest SCC");
87 LargestCGSCC.updateMax(
C->size());
97 ResultFAMCP->updateFAM(
FAM);
102 PA.intersect(PassPA);
108 LLVM_DEBUG(
dbgs() <<
"Skipping invalidated root or island SCC!\n");
113 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
141 AM.
getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager();
160 InlinedInternalEdges;
168 InlinedInternalEdges,
181 "Should always start with an empty RefSCC worklist");
198 "Should always start with an empty SCC worklist");
200 LLVM_DEBUG(
dbgs() <<
"Running an SCC pass across the RefSCC: " << *RC
220 if (InvalidSCCSet.
count(
C)) {
224 if (LastUpdatedC ==
C) {
264 assert(!InvalidSCCSet.
count(
C) &&
"Processing an invalid SCC!");
265 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
293 PA.intersect(PassPA);
299 LLVM_DEBUG(
dbgs() <<
"Skipping invalidated root or island SCC!\n");
304 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
312 CGAM.invalidate(*
C, PassPA);
327 <<
"Re-running SCC passes after a refinement of the "
335 }
while (!CWorklist.
empty());
340 InlinedInternalEdges.
clear();
341 }
while (!RCWorklist.
empty());
345 for (
Function *DeadF : DeadFunctions)
346 DeadF->eraseFromParent();
348#if defined(EXPENSIVE_CHECKS)
357 PA.preserve<CGSCCAnalysisManagerModuleProxy>();
385 assert(CallHandles.empty() &&
"Must start with a clear set of handles.");
388 CallCount CountLocal = {0, 0};
391 CallCounts.
insert(std::make_pair(&
N, CountLocal)).first->second;
394 if (CB->getCalledFunction()) {
410 for (
int Iteration = 0;; ++Iteration) {
422 LLVM_DEBUG(
dbgs() <<
"Skipping invalidated root or island SCC!\n");
437 assert(
C->begin() !=
C->end() &&
"Cannot have an empty SCC!");
442 if (CallBase *CB = dyn_cast<CallBase>(P.second)) {
443 if (CB->getCalledFunction()) {
444 LLVM_DEBUG(dbgs() <<
"Found devirtualized call: " << *CB <<
"\n");
466 for (
auto &Pair : NewCallCounts) {
467 auto &CallCountNew = Pair.second;
468 auto CountIt = CallCounts.find(Pair.first);
469 if (CountIt != CallCounts.end()) {
470 const auto &CallCountOld = CountIt->second;
471 if (CallCountOld.Indirect > CallCountNew.Indirect &&
472 CallCountOld.Direct < CallCountNew.Direct) {
484 if (Iteration >= MaxIterations) {
486 .abort_on_max_devirt_iterations_reached)
489 dbgs() <<
"Found another devirtualization after hitting the max "
490 "number of repetitions ("
491 << MaxIterations <<
") on SCC: " << *
C <<
"\n");
496 dbgs() <<
"Repeating an SCC pass after finding a devirtualization in: "
500 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(
583 ModuleAnalysisManager::Invalidator &Inv) {
596 auto PAC = PA.
getChecker<CGSCCAnalysisManagerModuleProxy>();
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;
628 if (Inv.invalidate(OuterAnalysisID, M, PA)) {
631 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
632 InnerPA->abandon(InnerAnalysisID);
639 InnerAM->invalidate(
C, *InnerPA);
645 if (!AreSCCAnalysesPreserved)
646 InnerAM->invalidate(
C, PA);
654CGSCCAnalysisManagerModuleProxy::Result
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");
691 CGSCCAnalysisManager::Invalidator &Inv) {
707 FAM->invalidate(
N.getFunction(), PA);
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;
731 if (Inv.invalidate(OuterAnalysisID,
C, PA)) {
734 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
735 FunctionPA->abandon(InnerAnalysisID);
742 FAM->invalidate(
F, *FunctionPA);
748 if (!AreFunctionAnalysesPreserved)
749 FAM->invalidate(
F, PA);
791 for (
const auto &OuterInvalidationPair :
792 OuterProxy->getOuterInvalidations()) {
793 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
794 for (
AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
795 PA.abandon(InnerAnalysisID);
799 FAM.invalidate(
F, PA);
813template <
typename SCCRangeT>
814static LazyCallGraph::SCC *
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();
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;
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())
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);
1074 for (
Node *CallTarget : PromotedRefTargets) {
1075 SCC &TargetC = *
G.lookupSCC(*CallTarget);
1076 RefSCC &TargetRC = TargetC.getOuterRefSCC();
1080 if (&TargetRC != RC) {
1081#ifdef EXPENSIVE_CHECKS
1082 assert(RC->isAncestorOf(TargetRC) &&
1083 "Cannot potentially form RefSCC cycles here!");
1085 RC->switchOutgoingEdgeToCall(
N, *CallTarget);
1086 LLVM_DEBUG(
dbgs() <<
"Switch outgoing ref edge to a call edge from '" <<
N
1087 <<
"' to '" << *CallTarget <<
"'\n");
1090 LLVM_DEBUG(
dbgs() <<
"Switch an internal ref edge to a call edge from '"
1091 <<
N <<
"' to '" << *CallTarget <<
"'\n");
1097 bool HasFunctionAnalysisProxy =
false;
1098 auto InitialSCCIndex = RC->find(*
C) - RC->begin();
1099 bool FormedCycle = RC->switchInternalEdgeToCall(
1101 for (SCC *MergedC : MergedSCCs) {
1102 assert(MergedC != &TargetC &&
"Cannot merge away the target SCC!");
1104 HasFunctionAnalysisProxy |=
1106 *MergedC) !=
nullptr;
1124 assert(
G.lookupSCC(
N) ==
C &&
"Failed to update current SCC!");
1129 if (HasFunctionAnalysisProxy)
1139 auto NewSCCIndex = RC->find(*
C) - RC->begin();
1148 if (InitialSCCIndex < NewSCCIndex) {
1154 LLVM_DEBUG(
dbgs() <<
"Enqueuing the existing SCC in the worklist: " << *
C
1158 RC->begin() + NewSCCIndex))) {
1160 LLVM_DEBUG(
dbgs() <<
"Enqueuing a newly earlier in post-order SCC: "
1167 assert(&
C->getOuterRefSCC() == RC &&
"Current SCC not in current RefSCC!");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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.
#define LLVM_EXPORT_TEMPLATE
This header defines various interfaces for pass management in LLVM.
Implements a lazy call graph analysis and related passes for the new pass manager.
CGSCCAnalysisManager CGAM
FunctionAnalysisManager FAM
Provides implementations for PassManager and AnalysisManager template methods.
This file provides a priority worklist.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
This templated class represents "all analyses that operate over <aparticular IR unit>" (e....
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.
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...
LLVM_ABI PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
Runs the function pass across every function in the module.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
LLVM_ABI 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.
LLVM_ABI bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, CGSCCAnalysisManager::Invalidator &Inv)
A proxy from a FunctionAnalysisManager to an SCC.
LLVM_ABI 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(Module &IR, AnalysisManager< Module, ExtraArgTs... > &AM, ExtraArgTs...)
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.
LLVM_ABI void buildRefSCCs()
static LLVM_ABI 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...
LLVM_ABI 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.
LLVM_ABI 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.
std::vector< typename PassConceptT::unique_ptr > Passes
PreservedAnalyses run(LazyCallGraph::SCC &IR, CGSCCAnalysisManager &AM, ExtraArgTs... ExtraArgs)
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.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
void intersect(const PreservedAnalyses &Arg)
Intersect this set with another in place.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
PreservedAnalysisChecker getChecker() const
Build a checker for this PreservedAnalyses and the specified analysis type.
static PreservedAnalyses allInSet()
Construct a preserved analyses object with a single preserved set.
bool empty() const
Determine if the PriorityWorklist is empty or not.
bool insert(const T &X)
Insert a new element into the PriorityWorklist.
void insert_range(Range &&R)
bool insert(const value_type &X)
Insert a new element into the SetVector.
static LLVM_ABI AnalysisKey Key
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.
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.
OuterAnalysisManagerProxy< CGSCCAnalysisManager, Function > CGSCCAnalysisManagerFunctionProxy
A proxy from a CGSCCAnalysisManager to a Function.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI 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.
LLVM_ABI 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...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
const AnalysisOptions & getAnalysisOptions(const LLVMContext &C)
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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
OuterAnalysisManagerProxy< ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph & > ModuleAnalysisManagerCGSCCProxy
A proxy from a ModuleAnalysisManager to an SCC.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
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.