19 #include "llvm/Config/llvm-config.h" 41 #define DEBUG_TYPE "lcg" 43 void LazyCallGraph::EdgeSequence::insertEdgeInternal(Node &TargetN,
45 EdgeIndexMap.insert({&TargetN, Edges.
size()});
49 void LazyCallGraph::EdgeSequence::setEdgeKind(Node &TargetN,
Edge::Kind EK) {
50 Edges[EdgeIndexMap.find(&TargetN)->second].setKind(EK);
53 bool LazyCallGraph::EdgeSequence::removeEdgeInternal(Node &TargetN) {
54 auto IndexMapI = EdgeIndexMap.find(&TargetN);
55 if (IndexMapI == EdgeIndexMap.end())
58 Edges[IndexMapI->second] = Edge();
59 EdgeIndexMap.erase(IndexMapI);
66 if (!EdgeIndexMap.
insert({&N, Edges.size()}).second)
74 assert(!Edges &&
"Must not have already populated the edges for this node!");
77 <<
"' to the graph.\n");
79 Edges = EdgeSequence();
105 if (!
Callee->isDeclaration())
112 for (
Value *
Op :
I.operand_values())
122 addEdge(Edges->Edges, Edges->EdgeIndexMap,
G->get(F),
128 for (
auto *F :
G->LibFunctions)
129 if (!Visited.
count(F))
130 addEdge(Edges->Edges, Edges->EdgeIndexMap,
G->get(*F),
136 void LazyCallGraph::Node::replaceFunction(
Function &NewF) {
137 assert(
F != &NewF &&
"Must not replace a function with itself!");
141 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 143 dbgs() << *
this <<
'\n';
158 if (
F.isDeclaration())
164 LibFunctions.insert(&
F);
166 if (
F.hasLocalLinkage())
172 <<
"' to entry set of the graph.\n");
180 if (GV.hasInitializer())
185 dbgs() <<
" Adding functions referenced by global initializers to the " 188 addEdge(EntryEdges.Edges, EntryEdges.EdgeIndexMap,
get(F),
194 : BPA(
std::move(
G.BPA)), NodeMap(
std::move(
G.NodeMap)),
195 EntryEdges(
std::move(
G.EntryEdges)), SCCBPA(
std::move(
G.SCCBPA)),
196 SCCMap(
std::move(
G.SCCMap)),
197 LibFunctions(
std::move(
G.LibFunctions)) {
202 BPA = std::move(
G.BPA);
203 NodeMap = std::move(
G.NodeMap);
204 EntryEdges = std::move(
G.EntryEdges);
205 SCCBPA = std::move(
G.SCCBPA);
206 SCCMap = std::move(
G.SCCMap);
207 LibFunctions = std::move(
G.LibFunctions);
212 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 214 dbgs() << *
this <<
'\n';
219 void LazyCallGraph::SCC::verify() {
220 assert(OuterRefSCC &&
"Can't have a null RefSCC!");
221 assert(!Nodes.empty() &&
"Can't have an empty SCC!");
223 for (
Node *
N : Nodes) {
224 assert(
N &&
"Can't have a null node!");
225 assert(OuterRefSCC->G->lookupSCC(*
N) ==
this &&
226 "Node does not map to this SCC!");
228 "Must set DFS numbers to -1 when adding a node to an SCC!");
230 "Must set low link to -1 when adding a node to an SCC!");
232 assert(
E.getNode().isPopulated() &&
"Can't have an unpopulated node!");
241 for (
Node &
N : *
this)
243 if (OuterRefSCC->G->lookupSCC(
E.getNode()) == &C)
251 if (
this == &TargetC)
264 for (
Edge &
E :
N->calls()) {
270 if (CalleeC == &TargetC)
275 if (Visited.
insert(CalleeC).second)
278 }
while (!Worklist.
empty());
286 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 288 dbgs() << *
this <<
'\n';
293 void LazyCallGraph::RefSCC::verify() {
294 assert(G &&
"Can't have a null graph!");
295 assert(!SCCs.empty() &&
"Can't have an empty SCC!");
299 for (
SCC *
C : SCCs) {
300 assert(
C &&
"Can't have a null SCC!");
302 assert(&
C->getOuterRefSCC() ==
this &&
303 "SCC doesn't think it is inside this RefSCC!");
304 bool Inserted = SCCSet.insert(
C).second;
305 assert(Inserted &&
"Found a duplicate SCC!");
306 auto IndexIt = SCCIndices.find(
C);
307 assert(IndexIt != SCCIndices.end() &&
308 "Found an SCC that doesn't have an index!");
312 for (
auto &SCCIndexPair : SCCIndices) {
313 SCC *
C = SCCIndexPair.first;
314 int i = SCCIndexPair.second;
315 assert(C &&
"Can't have a null SCC in the indices!");
316 assert(SCCSet.count(C) &&
"Found an index for an SCC not in the RefSCC!");
317 assert(SCCs[i] == C &&
"Index doesn't point to SCC!");
321 for (
int i = 0,
Size = SCCs.size(); i <
Size; ++i) {
322 SCC &SourceSCC = *SCCs[i];
323 for (
Node &
N : SourceSCC)
329 assert(SCCIndices.find(&TargetSCC)->second <= i &&
330 "Edge between SCCs violates post-order relationship.");
365 for (
SCC &
C : DescendantRC)
371 if (!ChildRC || !Visited.
insert(ChildRC).second)
375 }
while (!Worklist.
empty());
442 template <
typename SCCT,
typename PostorderSequenceT,
typename SCCIndexMapT,
443 typename ComputeSourceConnectedSetCallableT,
444 typename ComputeTargetConnectedSetCallableT>
447 SCCT &SourceSCC, SCCT &TargetSCC, PostorderSequenceT &SCCs,
448 SCCIndexMapT &SCCIndices,
449 ComputeSourceConnectedSetCallableT ComputeSourceConnectedSet,
450 ComputeTargetConnectedSetCallableT ComputeTargetConnectedSet) {
451 int SourceIdx = SCCIndices[&SourceSCC];
452 int TargetIdx = SCCIndices[&TargetSCC];
453 assert(SourceIdx < TargetIdx &&
"Cannot have equal indices here!");
458 ComputeSourceConnectedSet(ConnectedSet);
463 auto SourceI = std::stable_partition(
464 SCCs.begin() + SourceIdx, SCCs.begin() + TargetIdx + 1,
465 [&ConnectedSet](SCCT *
C) {
return !ConnectedSet.
count(
C); });
466 for (
int i = SourceIdx, e = TargetIdx + 1; i < e; ++i)
467 SCCIndices.find(SCCs[i])->second = i;
471 if (!ConnectedSet.
count(&TargetSCC)) {
472 assert(SourceI > (SCCs.begin() + SourceIdx) &&
473 "Must have moved the source to fix the post-order.");
474 assert(*std::prev(SourceI) == &TargetSCC &&
475 "Last SCC to move should have bene the target.");
479 return make_range(std::prev(SourceI), std::prev(SourceI));
482 assert(SCCs[TargetIdx] == &TargetSCC &&
483 "Should not have moved target if connected!");
484 SourceIdx = SourceI - SCCs.begin();
485 assert(SCCs[SourceIdx] == &SourceSCC &&
486 "Bad updated index computation for the source SCC!");
492 if (SourceIdx + 1 < TargetIdx) {
493 ConnectedSet.
clear();
494 ComputeTargetConnectedSet(ConnectedSet);
498 auto TargetI = std::stable_partition(
499 SCCs.begin() + SourceIdx + 1, SCCs.begin() + TargetIdx + 1,
500 [&ConnectedSet](SCCT *
C) {
return ConnectedSet.
count(
C); });
501 for (
int i = SourceIdx + 1, e = TargetIdx + 1; i < e; ++i)
502 SCCIndices.find(SCCs[i])->second = i;
503 TargetIdx = std::prev(TargetI) - SCCs.begin();
504 assert(SCCs[TargetIdx] == &TargetSCC &&
505 "Should always end with the target!");
512 return make_range(SCCs.begin() + SourceIdx, SCCs.begin() + TargetIdx);
519 assert(!(*SourceN)[TargetN].isCall() &&
"Must start with a ref edge!");
534 if (&SourceSCC == &TargetSCC) {
545 int SourceIdx = SCCIndices[&SourceSCC];
546 int TargetIdx = SCCIndices[&TargetSCC];
547 if (TargetIdx < SourceIdx) {
559 ConnectedSet.insert(&SourceSCC);
560 auto IsConnected = [&](
SCC &
C) {
562 for (
Edge &
E :
N->calls())
563 if (ConnectedSet.count(G->
lookupSCC(
E.getNode())))
570 make_range(SCCs.begin() + SourceIdx + 1, SCCs.begin() + TargetIdx + 1))
572 ConnectedSet.insert(
C);
585 ConnectedSet.insert(&TargetSCC);
598 if (SCCIndices.find(&EdgeC)->second <= SourceIdx)
602 if (ConnectedSet.insert(&EdgeC).second)
605 }
while (!Worklist.
empty());
613 SourceSCC, TargetSCC, SCCs, SCCIndices, ComputeSourceConnectedSet,
614 ComputeTargetConnectedSet);
618 MergeCB(
makeArrayRef(MergeRange.begin(), MergeRange.end()));
622 if (
empty(MergeRange)) {
640 for (
SCC *
C : MergeRange) {
642 "We merge *into* the target and shouldn't process it here!");
644 TargetSCC.Nodes.append(
C->Nodes.begin(),
C->Nodes.end());
646 G->SCCMap[
N] = &TargetSCC;
653 int IndexOffset = MergeRange.end() - MergeRange.begin();
654 auto EraseEnd = SCCs.erase(MergeRange.begin(), MergeRange.end());
656 SCCIndices[
C] -= IndexOffset;
667 assert((*SourceN)[TargetN].isCall() &&
"Must start with a call edge!");
677 "Source must be in this RefSCC.");
679 "Target must be in this RefSCC.");
681 "Source and Target must be in separate SCCs for this to be trivial!");
684 SourceN->setEdgeKind(TargetN,
Edge::Ref);
689 assert((*SourceN)[TargetN].isCall() &&
"Must start with a call edge!");
699 "Source must be in this RefSCC.");
701 "Target must be in this RefSCC.");
704 assert(G->
lookupSCC(SourceN) == &TargetSCC &&
"Source and Target must be in " 705 "the same SCC to require the " 709 SourceN->setEdgeKind(TargetN,
Edge::Ref);
723 SCC &OldSCC = TargetSCC;
730 Worklist.
swap(OldSCC.Nodes);
731 for (
Node *
N : Worklist) {
732 N->DFSNumber =
N->LowLink = 0;
744 TargetN.DFSNumber = TargetN.LowLink = -1;
745 OldSCC.Nodes.push_back(&TargetN);
746 G->SCCMap[&TargetN] = &OldSCC;
749 for (
Node *RootN : Worklist) {
751 "Cannot begin a new root with a non-empty DFS stack!");
753 "Cannot begin a new root with pending nodes for an SCC!");
756 if (RootN->DFSNumber != 0) {
757 assert(RootN->DFSNumber == -1 &&
758 "Shouldn't have any mid-DFS root nodes!");
762 RootN->DFSNumber = RootN->LowLink = 1;
763 int NextDFSNumber = 2;
765 DFSStack.
push_back({RootN, (*RootN)->call_begin()});
770 auto E = (*N)->call_end();
772 Node &ChildN = I->getNode();
773 if (ChildN.DFSNumber == 0) {
778 assert(!G->SCCMap.count(&ChildN) &&
779 "Found a node with 0 DFS number but already in an SCC!");
780 ChildN.DFSNumber = ChildN.LowLink = NextDFSNumber++;
782 I = (*N)->call_begin();
783 E = (*N)->call_end();
788 if (ChildN.DFSNumber == -1) {
794 int OldSize = OldSCC.
size();
795 OldSCC.Nodes.push_back(N);
796 OldSCC.Nodes.append(PendingSCCStack.
begin(), PendingSCCStack.
end());
797 PendingSCCStack.
clear();
798 while (!DFSStack.
empty())
801 N.DFSNumber = N.LowLink = -1;
802 G->SCCMap[&
N] = &OldSCC;
816 assert(ChildN.LowLink > 0 &&
"Must have a positive low-link number!");
817 if (ChildN.LowLink < N->LowLink)
818 N->LowLink = ChildN.LowLink;
833 if (N->LowLink != N->DFSNumber)
838 int RootDFSNumber = N->DFSNumber;
844 return N->DFSNumber < RootDFSNumber;
849 NewSCCs.
push_back(G->createSCC(*
this, SCCNodes));
851 N.DFSNumber = N.LowLink = -1;
852 G->SCCMap[&
N] = NewSCCs.
back();
854 PendingSCCStack.
erase(SCCNodes.end().base(), PendingSCCStack.
end());
855 }
while (!DFSStack.
empty());
862 int OldIdx = SCCIndices[&OldSCC];
863 SCCs.insert(SCCs.begin() + OldIdx, NewSCCs.
begin(), NewSCCs.
end());
867 for (
int Idx = OldIdx,
Size = SCCs.size(); Idx <
Size; ++Idx)
868 SCCIndices[SCCs[Idx]] = Idx;
871 SCCs.begin() + OldIdx + NewSCCs.
size());
876 assert(!(*SourceN)[TargetN].isCall() &&
"Must start with a ref edge!");
880 "Target must not be in this RefSCC.");
881 #ifdef EXPENSIVE_CHECKS 883 "Target must be a descendant of the Source.");
898 assert((*SourceN)[TargetN].isCall() &&
"Must start with a call edge!");
902 "Target must not be in this RefSCC.");
903 #ifdef EXPENSIVE_CHECKS 905 "Target must be a descendant of the Source.");
910 SourceN->setEdgeKind(TargetN,
Edge::Ref);
923 SourceN->insertEdgeInternal(TargetN,
Edge::Ref);
934 SourceN->insertEdgeInternal(TargetN, EK);
939 "Target must not be in this RefSCC.");
940 #ifdef EXPENSIVE_CHECKS 942 "Target must be a descendant of the Source.");
955 assert(&SourceC !=
this &&
"Source must not be in this RefSCC.");
956 #ifdef EXPENSIVE_CHECKS 957 assert(SourceC.isDescendantOf(*
this) &&
958 "Source must be a descendant of the Target.");
970 int SourceIdx = G->RefSCCIndices[&SourceC];
971 int TargetIdx = G->RefSCCIndices[
this];
972 assert(SourceIdx < TargetIdx &&
973 "Postorder list doesn't see edge as incoming!");
983 Set.insert(&SourceC);
984 auto IsConnected = [&](
RefSCC &RC) {
995 G->PostOrderRefSCCs.begin() + TargetIdx + 1))
1014 if (G->getRefSCCIndex(EdgeRC) <= SourceIdx)
1018 if (Set.insert(&EdgeRC).second)
1021 }
while (!Worklist.
empty());
1030 SourceC, *
this, G->PostOrderRefSCCs, G->RefSCCIndices,
1031 ComputeSourceConnectedSet, ComputeTargetConnectedSet);
1044 for (
RefSCC *RC : MergeRange) {
1045 assert(RC !=
this &&
"We're merging into the target RefSCC, so it " 1046 "shouldn't be in the range.");
1052 for (
SCC &InnerC : *RC) {
1053 InnerC.OuterRefSCC =
this;
1054 SCCIndices[&InnerC] = SCCIndex++;
1055 for (
Node &
N : InnerC)
1056 G->SCCMap[&
N] = &InnerC;
1061 if (MergedSCCs.
empty())
1062 MergedSCCs = std::move(RC->SCCs);
1064 MergedSCCs.
append(RC->SCCs.begin(), RC->SCCs.end());
1066 DeletedRefSCCs.push_back(RC);
1070 for (
SCC &InnerC : *
this)
1071 SCCIndices[&InnerC] = SCCIndex++;
1072 MergedSCCs.
append(SCCs.begin(), SCCs.end());
1073 SCCs = std::move(MergedSCCs);
1076 for (
RefSCC *RC : MergeRange)
1077 G->RefSCCIndices.erase(RC);
1078 int IndexOffset = MergeRange.end() - MergeRange.begin();
1080 G->PostOrderRefSCCs.erase(MergeRange.begin(), MergeRange.end());
1082 G->RefSCCIndices[RC] -= IndexOffset;
1086 SourceN->insertEdgeInternal(TargetN,
Edge::Ref);
1092 return DeletedRefSCCs;
1097 "The source must be a member of this RefSCC.");
1099 "The target must not be a member of this RefSCC");
1109 bool Removed = SourceN->removeEdgeInternal(TargetN);
1111 assert(Removed &&
"Target not in the edge set for this caller?");
1134 for (
Node *TargetN : TargetNs) {
1135 assert(!(*SourceN)[*TargetN].isCall() &&
1136 "Cannot remove a call edge, it must first be made a ref edge");
1138 bool Removed = SourceN->removeEdgeInternal(*TargetN);
1140 assert(Removed &&
"Target not in the edge set for this caller?");
1145 [&](
Node *TargetN) {
return &SourceN == TargetN; }))
1152 return G->
lookupSCC(*TargetN) == &SourceC;
1162 int PostOrderNumber = 0;
1167 for (
SCC *
C : SCCs) {
1169 N.DFSNumber =
N.LowLink = 0;
1171 Worklist.
append(C->Nodes.begin(), C->Nodes.end());
1177 const int NumRefSCCNodes = Worklist.
size();
1183 "Cannot begin a new root with a non-empty DFS stack!");
1185 "Cannot begin a new root with pending nodes for an SCC!");
1189 if (RootN->DFSNumber != 0) {
1190 assert(RootN->DFSNumber == -1 &&
1191 "Shouldn't have any mid-DFS root nodes!");
1195 RootN->DFSNumber = RootN->LowLink = 1;
1196 int NextDFSNumber = 2;
1198 DFSStack.
push_back({RootN, (*RootN)->begin()});
1203 auto E = (*N)->end();
1205 assert(N->DFSNumber != 0 &&
"We should always assign a DFS number " 1206 "before processing a node.");
1209 Node &ChildN = I->getNode();
1210 if (ChildN.DFSNumber == 0) {
1217 ChildN.LowLink = ChildN.DFSNumber = NextDFSNumber++;
1219 I = ChildN->
begin();
1223 if (ChildN.DFSNumber == -1) {
1232 assert(ChildN.LowLink != 0 &&
1233 "Low-link must not be zero with a non-zero DFS number.");
1234 if (ChildN.LowLink >= 0 && ChildN.LowLink < N->LowLink)
1235 N->LowLink = ChildN.LowLink;
1245 if (N->LowLink != N->DFSNumber) {
1247 "We never found a viable root for a RefSCC to pop off!");
1252 int RefSCCNumber = PostOrderNumber++;
1253 int RootDFSNumber = N->DFSNumber;
1259 if (N->DFSNumber < RootDFSNumber)
1267 N->LowLink = RefSCCNumber;
1270 auto RefSCCNodes =
make_range(StackRI.base(), PendingRefSCCStack.
end());
1276 if (
llvm::size(RefSCCNodes) == NumRefSCCNodes) {
1278 for (
Node *N : RefSCCNodes)
1286 PendingRefSCCStack.
erase(RefSCCNodes.begin(), PendingRefSCCStack.
end());
1287 }
while (!DFSStack.
empty());
1289 assert(DFSStack.
empty() &&
"Didn't flush the entire DFS stack!");
1290 assert(PendingRefSCCStack.
empty() &&
"Didn't flush all pending nodes!");
1291 }
while (!Worklist.
empty());
1293 assert(PostOrderNumber > 1 &&
1294 "Should never finish the DFS when the existing RefSCC remains valid!");
1300 for (
int i = 0; i < PostOrderNumber; ++i)
1310 int Idx = G->getRefSCCIndex(*
this);
1311 G->PostOrderRefSCCs.erase(G->PostOrderRefSCCs.begin() + Idx);
1312 G->PostOrderRefSCCs.insert(G->PostOrderRefSCCs.begin() + Idx, Result.
begin(),
1314 for (
int i : seq<int>(Idx, G->PostOrderRefSCCs.size()))
1315 G->RefSCCIndices[G->PostOrderRefSCCs[i]] = i;
1317 for (
SCC *
C : SCCs) {
1319 int SCCNumber =
C->begin()->LowLink;
1323 assert(
N.LowLink == SCCNumber &&
1324 "Cannot have different numbers for nodes in the same SCC!");
1328 RefSCC &RC = *Result[SCCNumber];
1329 int SCCIndex = RC.SCCs.size();
1330 RC.SCCs.push_back(C);
1331 RC.SCCIndices[
C] = SCCIndex;
1332 C->OuterRefSCC = &RC;
1343 for (
RefSCC *RC : Result)
1351 void LazyCallGraph::RefSCC::handleTrivialEdgeInsertion(
Node &SourceN,
1359 if (&TargetRC ==
this)
1362 #ifdef EXPENSIVE_CHECKS 1363 assert(TargetRC.isDescendantOf(*
this) &&
1364 "Target must be a descendant of the Source.");
1374 #ifdef EXPENSIVE_CHECKS 1379 if (&SourceC != &TargetC)
1380 assert(SourceC.isAncestorOf(TargetC) &&
1381 "Call edge is not trivial in the SCC graph!");
1382 #endif // EXPENSIVE_CHECKS 1387 SourceN->EdgeIndexMap.insert({&TargetN, SourceN->Edges.
size()});
1388 if (!InsertResult.second) {
1390 Edge &
E = SourceN->Edges[InsertResult.first->second];
1400 handleTrivialEdgeInsertion(SourceN, TargetN);
1408 #ifdef EXPENSIVE_CHECKS 1412 if (&SourceRC != &TargetRC)
1413 assert(SourceRC.isAncestorOf(TargetRC) &&
1414 "Ref edge is not trivial in the RefSCC graph!");
1415 #endif // EXPENSIVE_CHECKS 1420 SourceN->EdgeIndexMap.insert({&TargetN, SourceN->Edges.
size()});
1421 if (!InsertResult.second)
1429 handleTrivialEdgeInsertion(SourceN, TargetN);
1440 "Cannot replace the function of a node outside this RefSCC.");
1442 assert(G->NodeMap.find(&NewF) == G->NodeMap.end() &&
1443 "Must not have already walked the new function!'");
1451 assert(&OldF != &NewF &&
"Cannot replace a function with itself!");
1453 "Must have moved all uses from the old function to the new!");
1456 N.replaceFunction(NewF);
1459 G->NodeMap.erase(&OldF);
1460 G->NodeMap[&NewF] = &
N;
1465 "This method cannot be called after SCCs have been formed!");
1467 return SourceN->insertEdgeInternal(TargetN, EK);
1472 "This method cannot be called after SCCs have been formed!");
1474 bool Removed = SourceN->removeEdgeInternal(TargetN);
1476 assert(Removed &&
"Target not in the edge set for this caller?");
1483 "This routine should only be called on trivially dead functions!");
1488 "Must not remove lib functions from the call graph!");
1490 auto NI = NodeMap.find(&F);
1491 if (NI == NodeMap.end())
1495 Node &
N = *NI->second;
1499 EntryEdges.removeEdgeInternal(N);
1501 if (SCCMap.empty()) {
1510 auto CI = SCCMap.find(&N);
1511 assert(CI != SCCMap.end() &&
1512 "Tried to remove a node without an SCC after DFS walk started!");
1513 SCC &
C = *CI->second;
1515 RefSCC &RC = C.getOuterRefSCC();
1520 assert(C.size() == 1 &&
"Dead functions must be in a singular SCC");
1521 assert(RC.
size() == 1 &&
"Dead functions must be in a singular RefSCC");
1523 auto RCIndexI = RefSCCIndices.find(&RC);
1524 int RCIndex = RCIndexI->second;
1525 PostOrderRefSCCs.erase(PostOrderRefSCCs.begin() + RCIndex);
1526 RefSCCIndices.erase(RCIndexI);
1527 for (
int i = RCIndex,
Size = PostOrderRefSCCs.size(); i <
Size; ++i)
1528 RefSCCIndices[PostOrderRefSCCs[i]] = i;
1544 return *
new (MappedN = BPA.Allocate())
Node(*
this, F);
1547 void LazyCallGraph::updateGraphPtrs() {
1550 for (
auto &FunctionNodePair : NodeMap)
1551 FunctionNodePair.second->G =
this;
1553 for (
auto *RC : PostOrderRefSCCs)
1557 template <
typename RootsT,
typename GetBeginT,
typename GetEndT,
1558 typename GetNodeT,
typename FormSCCCallbackT>
1559 void LazyCallGraph::buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,
1560 GetEndT &&GetEnd, GetNodeT &&GetNode,
1561 FormSCCCallbackT &&FormSCC) {
1562 using EdgeItT = decltype(GetBegin(std::declval<Node &>()));
1568 for (
Node *RootN : Roots) {
1570 "Cannot begin a new root with a non-empty DFS stack!");
1572 "Cannot begin a new root with pending nodes for an SCC!");
1575 if (RootN->DFSNumber != 0) {
1576 assert(RootN->DFSNumber == -1 &&
1577 "Shouldn't have any mid-DFS root nodes!");
1581 RootN->DFSNumber = RootN->LowLink = 1;
1582 int NextDFSNumber = 2;
1584 DFSStack.
push_back({RootN, GetBegin(*RootN)});
1589 auto E = GetEnd(*N);
1591 Node &ChildN = GetNode(I);
1592 if (ChildN.DFSNumber == 0) {
1597 ChildN.DFSNumber = ChildN.LowLink = NextDFSNumber++;
1607 if (ChildN.DFSNumber == -1) {
1613 assert(ChildN.LowLink > 0 &&
"Must have a positive low-link number!");
1614 if (ChildN.LowLink < N->LowLink)
1615 N->LowLink = ChildN.LowLink;
1627 if (N->LowLink != N->DFSNumber)
1632 int RootDFSNumber = N->DFSNumber;
1636 PendingSCCStack.
rbegin(),
1638 return N->DFSNumber < RootDFSNumber;
1643 PendingSCCStack.
erase(SCCNodes.end().base(), PendingSCCStack.
end());
1644 }
while (!DFSStack.
empty());
1654 assert(RC.SCCs.empty() &&
"Already built SCCs!");
1655 assert(RC.SCCIndices.empty() &&
"Already mapped SCC indices!");
1657 for (
Node *
N : Nodes) {
1658 assert(
N->LowLink >= (*Nodes.begin())->LowLink &&
1659 "We cannot have a low link in an SCC lower than its root on the " 1664 N->DFSNumber =
N->LowLink = 0;
1675 RC.SCCs.push_back(createSCC(RC, Nodes));
1676 for (
Node &N : *RC.SCCs.back()) {
1677 N.DFSNumber = N.LowLink = -1;
1678 SCCMap[&
N] = RC.SCCs.back();
1683 for (
int i = 0,
Size = RC.SCCs.size(); i <
Size; ++i)
1684 RC.SCCIndices[RC.SCCs[i]] = i;
1688 if (EntryEdges.
empty() || !PostOrderRefSCCs.empty())
1692 assert(RefSCCIndices.empty() &&
"Already mapped RefSCC indices!");
1695 for (
Edge &
E : *
this)
1712 RefSCC *NewRC = createRefSCC(*
this);
1713 buildSCCs(*NewRC, Nodes);
1718 RefSCCIndices.insert({NewRC, PostOrderRefSCCs.size()}).
second;
1720 assert(Inserted &&
"Cannot already have this RefSCC in the index map!");
1721 PostOrderRefSCCs.push_back(NewRC);
1735 OS <<
" " << (
E.isCall() ?
"call" :
"ref ") <<
" -> " 1736 <<
E.getFunction().getName() <<
"\n";
1743 OS <<
" SCC with " << Size <<
" functions:\n";
1746 OS <<
" " <<
N.getFunction().getName() <<
"\n";
1751 OS <<
" RefSCC with " << Size <<
" call SCCs:\n";
1783 OS <<
" " << Name <<
" -> \"" 1786 OS <<
" [style=dashed,label=\"ref\"]";
This routine provides some synthesis utilities to produce sequences of values.
void insertEdge(Node &SourceN, Node &TargetN, Edge::Kind EK)
Update the call graph after inserting a new edge.
iterator_range< call_iterator > calls()
void removeOutgoingEdge(Node &SourceN, Node &TargetN)
Remove an edge whose source is in this RefSCC and target is not.
void removeEdge(Node &SourceN, Node &TargetN)
Update the call graph after deleting an edge.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This class represents lattice values for constants.
EdgeSequence & populate()
Populate the edges of this node if necessary.
A Module instance is used to store all the information related to an LLVM module. ...
Kind
The kind of edge in the graph.
void push_back(const T &Elt)
The edge sequence object.
This provides a very simple, boring adaptor for a begin and end iterator into a range type...
SCC * lookupSCC(Node &N) const
Lookup a function's SCC in the graph.
Implements a lazy call graph analysis and related passes for the new pass manager.
Function & getFunction() const
An efficient, type-erasing, non-owning reference to a callable.
LLVM_NODISCARD detail::scope_exit< typename std::decay< Callable >::type > make_scope_exit(Callable &&F)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
Node & get(Function &F)
Get a graph node for a given function, scanning it to populate the graph data as necessary.
static void printNode(raw_ostream &OS, LazyCallGraph::Node &N)
RefSCC * lookupRefSCC(Node &N) const
Lookup a function's RefSCC in the graph.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
RefSCC & getOuterRefSCC() const
bool isAncestorOf(const SCC &C) const
Test if this SCC is an ancestor of C.
StringRef getName() const
amdgpu Simplify well known AMD library false Value Value const Twine & Name
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
LazyCallGraph(Module &M, TargetLibraryInfo &TLI)
Construct a graph for the given module.
bool switchInternalEdgeToCall(Node &SourceN, Node &TargetN, function_ref< void(ArrayRef< SCC *> MergedSCCs)> MergeCB={})
Make an existing internal ref edge into a call edge.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
call_iterator call_begin()
bool isLibFunction(Function &F) const
Test whether a function is a known and defined library function tracked by the call graph...
static StringRef getName(Value *V)
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.
void insertTrivialCallEdge(Node &SourceN, Node &TargetN)
A convenience wrapper around the above to handle trivial cases of inserting a new call edge...
A lazily constructed view of the call graph of a module.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LazyCallGraph & operator=(LazyCallGraph &&RHS)
void replaceNodeFunction(Node &N, Function &NewF)
Directly replace a node's function with a new function.
amdgpu Simplify well known AMD library false Value * Callee
static void addEdge(SmallVectorImpl< LazyCallGraph::Edge > &Edges, DenseMap< LazyCallGraph::Node *, int > &EdgeIndexMap, LazyCallGraph::Node &N, LazyCallGraph::Edge::Kind EK)
void switchOutgoingEdgeToCall(Node &SourceN, Node &TargetN)
Make an existing outgoing ref edge into a call edge.
static bool isKnownLibFunction(Function &F, TargetLibraryInfo &TLI)
A set of analyses that are preserved following a run of a transformation pass.
LLVM Basic Block Representation.
An iterator used for the edges to both entry nodes and child nodes.
LazyCallGraphDOTPrinterPass(raw_ostream &OS)
std::string EscapeString(const std::string &Label)
void swap(SmallVectorImpl &RHS)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This is an important base class in LLVM.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
Node & getNode() const
Get the call graph node referenced by this edge.
void switchOutgoingEdgeToRef(Node &SourceN, Node &TargetN)
Make an existing outgoing call edge into a ref edge.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void insertInternalRefEdge(Node &SourceN, Node &TargetN)
Insert a ref edge from one node in this RefSCC to another in this RefSCC.
static void printNodeDOT(raw_ostream &OS, LazyCallGraph::Node &N)
SmallVector< RefSCC *, 1 > insertIncomingRefEdge(Node &SourceN, Node &TargetN)
Insert an edge whose source is in a descendant RefSCC and target is in this RefSCC.
A node in the call graph.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
A class used to represent edges in the call graph.
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
iterator erase(const_iterator CI)
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
bool isParentOf(const RefSCC &RC) const
Test if this RefSCC is a parent of RC.
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
bool verify(const TargetRegisterInfo &TRI) const
Check that information hold by this instance make sense for the given TRI.
constexpr bool empty(const T &RangeOrContainer)
Test whether RangeOrContainer is empty. Similar to C++17 std::empty.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
void removeDeadFunction(Function &F)
Remove a dead function from the call graph (typically to delete it).
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
bool isParentOf(const SCC &C) const
Test if this SCC is a parent of C.
bool isFunctionVectorizable(StringRef F, unsigned VF) const
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Provides information about what library functions are available for the current target.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LLVM_NODISCARD T pop_back_val()
SmallVector< RefSCC *, 1 > removeInternalRefEdge(Node &SourceN, ArrayRef< Node *> TargetNs)
Remove a list of ref edges which are entirely within this RefSCC.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
A range adaptor for a pair of iterators.
An iterator over specifically call edges.
void insertOutgoingEdge(Node &SourceN, Node &TargetN, Edge::Kind EK)
Insert an edge whose parent is in this RefSCC and child is in some child RefSCC.
bool getLibFunc(StringRef funcName, LibFunc &F) const
Searches for a particular function name.
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
void switchTrivialInternalEdgeToRef(Node &SourceN, Node &TargetN)
Make an existing internal call edge between separate SCCs into a ref edge.
iterator_range< iterator > switchInternalEdgeToRef(Node &SourceN, Node &TargetN)
Make an existing internal call edge within a single SCC into a ref edge.
LazyCallGraphPrinterPass(raw_ostream &OS)
bool isAncestorOf(const RefSCC &RC) const
Test if this RefSCC is an ancestor of RC.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
void emplace_back(ArgTypes &&... Args)
LLVM_NODISCARD bool empty() const
StringRef getName() const
Return a constant reference to the value's name.
static void printRefSCC(raw_ostream &OS, LazyCallGraph::RefSCC &C)
static void printSCC(raw_ostream &OS, LazyCallGraph::SCC &C)
An analysis pass which computes the call graph for a module.
void insertTrivialRefEdge(Node &SourceN, Node &TargetN)
A convenience wrapper around the above to handle trivial cases of inserting a new ref edge...
reverse_iterator rbegin()
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static iterator_range< typename PostorderSequenceT::iterator > updatePostorderSequenceForEdgeInsertion(SCCT &SourceSCC, SCCT &TargetSCC, PostorderSequenceT &SCCs, SCCIndexMapT &SCCIndices, ComputeSourceConnectedSetCallableT ComputeSourceConnectedSet, ComputeTargetConnectedSetCallableT ComputeTargetConnectedSet)
Generic helper that updates a postorder sequence of SCCs for a potentially cycle-introducing edge ins...
LLVM Value Representation.
An SCC of the call graph.
This class implements an extremely fast bulk output stream that can only output to a stream...
A container for analyses that lazily runs them and caches their results.
This header defines various interfaces for pass management in LLVM.
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 isDescendantOf(const RefSCC &RC) const
Test if this RefSCC is a descendant of RC.
iterator_range< postorder_ref_scc_iterator > postorder_ref_sccs()
A special type used by analysis passes to provide an address that identifies that particular analysis...
bool isCall() const
Test whether the edge represents a direct call to a function.