24 #define DEBUG_TYPE "lcg"
29 if (!EdgeIndexMap.
insert({&F, Edges.
size()}).second)
32 DEBUG(
dbgs() <<
" Added callable function: " <<
F.getName() <<
"\n");
37 : G(&G), F(F), DFSNumber(0), LowLink(0) {
39 <<
"' to the graph.\n");
65 if (!Callee->isDeclaration())
66 if (Callees.
insert(Callee).second) {
74 Worklist.push_back(
C);
80 visitReferences(Worklist, Visited, [&](
Function &F) {
81 addEdge(Edges, EdgeIndexMap, F, LazyCallGraph::Edge::Ref);
86 if (Node *
N = G->
lookup(Target))
87 return insertEdgeInternal(*
N, EK);
93 void LazyCallGraph::Node::insertEdgeInternal(Node &TargetN,
Edge::Kind EK) {
94 EdgeIndexMap.insert({&TargetN.getFunction(), Edges.size()});
95 Edges.emplace_back(TargetN, EK);
99 Edges[EdgeIndexMap.find(&TargetF)->second].setKind(EK);
102 void LazyCallGraph::Node::removeEdgeInternal(
Function &Target) {
103 auto IndexMapI = EdgeIndexMap.find(&Target);
104 assert(IndexMapI != EdgeIndexMap.end() &&
105 "Target not in the edge set for this caller?");
107 Edges[IndexMapI->second] = Edge();
108 EdgeIndexMap.erase(IndexMapI);
111 void LazyCallGraph::Node::dump()
const {
112 dbgs() << *
this <<
'\n';
119 if (!F.isDeclaration() && !F.hasLocalLinkage())
120 if (EntryIndexMap.insert({&F, EntryEdges.
size()}).second) {
121 DEBUG(
dbgs() <<
" Adding '" << F.getName()
122 <<
"' to entry set of the graph.\n");
123 EntryEdges.emplace_back(F, Edge::Ref);
130 if (GV.hasInitializer())
131 if (Visited.
insert(GV.getInitializer()).second)
134 DEBUG(
dbgs() <<
" Adding functions referenced by global initializers to the "
136 visitReferences(Worklist, Visited, [&](
Function &F) {
140 for (
const Edge &
E : EntryEdges)
141 RefSCCEntryNodes.push_back(&
E.getFunction());
145 : BPA(std::move(G.BPA)), NodeMap(std::move(G.NodeMap)),
146 EntryEdges(std::move(G.EntryEdges)),
147 EntryIndexMap(std::move(G.EntryIndexMap)), SCCBPA(std::move(G.SCCBPA)),
148 SCCMap(std::move(G.SCCMap)), LeafRefSCCs(std::move(G.LeafRefSCCs)),
149 DFSStack(std::move(G.DFSStack)),
150 RefSCCEntryNodes(std::move(G.RefSCCEntryNodes)),
151 NextDFSNumber(G.NextDFSNumber) {
156 BPA = std::move(G.BPA);
157 NodeMap = std::move(G.NodeMap);
158 EntryEdges = std::move(G.EntryEdges);
159 EntryIndexMap = std::move(G.EntryIndexMap);
160 SCCBPA = std::move(G.SCCBPA);
161 SCCMap = std::move(G.SCCMap);
162 LeafRefSCCs = std::move(G.LeafRefSCCs);
163 DFSStack = std::move(G.DFSStack);
164 RefSCCEntryNodes = std::move(G.RefSCCEntryNodes);
165 NextDFSNumber = G.NextDFSNumber;
170 void LazyCallGraph::SCC::dump()
const {
171 dbgs() << *
this <<
'\n';
175 void LazyCallGraph::SCC::verify() {
176 assert(OuterRefSCC &&
"Can't have a null RefSCC!");
177 assert(!Nodes.empty() &&
"Can't have an empty SCC!");
179 for (Node *
N : Nodes) {
180 assert(
N &&
"Can't have a null node!");
181 assert(OuterRefSCC->G->lookupSCC(*
N) ==
this &&
182 "Node does not map to this SCC!");
184 "Must set DFS numbers to -1 when adding a node to an SCC!");
186 "Must set low link to -1 when adding a node to an SCC!");
188 assert(
E.getNode() &&
"Can't have an edge to a raw function!");
197 for (
Node &
N : *
this)
199 if (
Node *CalleeN =
E.getNode())
200 if (OuterRefSCC->G->lookupSCC(*CalleeN) == &
C)
208 if (
this == &TargetC)
221 for (
Edge &
E :
N.calls()) {
222 Node *CalleeN =
E.getNode();
230 if (CalleeC == &TargetC)
235 if (Visited.
insert(CalleeC).second)
238 }
while (!Worklist.
empty());
246 void LazyCallGraph::RefSCC::dump()
const {
247 dbgs() << *
this <<
'\n';
251 void LazyCallGraph::RefSCC::verify() {
252 assert(G &&
"Can't have a null graph!");
253 assert(!SCCs.empty() &&
"Can't have an empty SCC!");
257 for (SCC *
C : SCCs) {
258 assert(
C &&
"Can't have a null SCC!");
260 assert(&
C->getOuterRefSCC() ==
this &&
261 "SCC doesn't think it is inside this RefSCC!");
262 bool Inserted = SCCSet.insert(
C).second;
263 assert(Inserted &&
"Found a duplicate SCC!");
264 auto IndexIt = SCCIndices.find(
C);
265 assert(IndexIt != SCCIndices.end() &&
266 "Found an SCC that doesn't have an index!");
270 for (
auto &SCCIndexPair : SCCIndices) {
271 SCC *
C = SCCIndexPair.first;
272 int i = SCCIndexPair.second;
273 assert(C &&
"Can't have a null SCC in the indices!");
274 assert(SCCSet.count(C) &&
"Found an index for an SCC not in the RefSCC!");
275 assert(SCCs[i] == C &&
"Index doesn't point to SCC!");
279 for (
int i = 0, Size = SCCs.size(); i < Size; ++
i) {
280 SCC &SourceSCC = *SCCs[
i];
281 for (Node &
N : SourceSCC)
286 if (&TargetSCC.getOuterRefSCC() ==
this) {
287 assert(SCCIndices.find(&TargetSCC)->second <= i &&
288 "Edge between SCCs violates post-order relationship.");
291 assert(TargetSCC.getOuterRefSCC().Parents.count(
this) &&
292 "Edge to a RefSCC missing us in its parent set.");
297 for (RefSCC *ParentRC : Parents) {
298 assert(ParentRC !=
this &&
"Cannot be our own parent!");
299 auto HasConnectingEdge = [&] {
300 for (SCC &C : *ParentRC)
307 assert(HasConnectingEdge() &&
"No edge connects the parent to us!");
320 for (
const RefSCC *ParentC : AncestorC->Parents)
322 }
while (!AncestorWorklist.
empty());
389 template <
typename SCCT,
typename PostorderSequenceT,
typename SCCIndexMapT,
390 typename ComputeSourceConnectedSetCallableT,
391 typename ComputeTargetConnectedSetCallableT>
394 SCCT &SourceSCC, SCCT &TargetSCC, PostorderSequenceT &SCCs,
395 SCCIndexMapT &SCCIndices,
396 ComputeSourceConnectedSetCallableT ComputeSourceConnectedSet,
397 ComputeTargetConnectedSetCallableT ComputeTargetConnectedSet) {
398 int SourceIdx = SCCIndices[&SourceSCC];
399 int TargetIdx = SCCIndices[&TargetSCC];
400 assert(SourceIdx < TargetIdx &&
"Cannot have equal indices here!");
405 ComputeSourceConnectedSet(ConnectedSet);
410 auto SourceI = std::stable_partition(
411 SCCs.begin() + SourceIdx, SCCs.begin() + TargetIdx + 1,
412 [&ConnectedSet](SCCT *
C) {
return !ConnectedSet.
count(C); });
413 for (
int i = SourceIdx, e = TargetIdx + 1; i < e; ++
i)
414 SCCIndices.find(SCCs[i])->second =
i;
418 if (!ConnectedSet.
count(&TargetSCC)) {
419 assert(SourceI > (SCCs.begin() + SourceIdx) &&
420 "Must have moved the source to fix the post-order.");
421 assert(*std::prev(SourceI) == &TargetSCC &&
422 "Last SCC to move should have bene the target.");
426 return make_range(std::prev(SourceI), std::prev(SourceI));
429 assert(SCCs[TargetIdx] == &TargetSCC &&
430 "Should not have moved target if connected!");
431 SourceIdx = SourceI - SCCs.begin();
432 assert(SCCs[SourceIdx] == &SourceSCC &&
433 "Bad updated index computation for the source SCC!");
439 if (SourceIdx + 1 < TargetIdx) {
440 ConnectedSet.
clear();
441 ComputeTargetConnectedSet(ConnectedSet);
445 auto TargetI = std::stable_partition(
446 SCCs.begin() + SourceIdx + 1, SCCs.begin() + TargetIdx + 1,
447 [&ConnectedSet](SCCT *
C) {
return ConnectedSet.
count(C); });
448 for (
int i = SourceIdx + 1, e = TargetIdx + 1; i < e; ++
i)
449 SCCIndices.find(SCCs[i])->second =
i;
450 TargetIdx = std::prev(TargetI) - SCCs.begin();
451 assert(SCCs[TargetIdx] == &TargetSCC &&
452 "Should always end with the target!");
459 return make_range(SCCs.begin() + SourceIdx, SCCs.begin() + TargetIdx);
464 assert(!SourceN[TargetN].isCall() &&
"Must start with a ref edge!");
479 if (&SourceSCC == &TargetSCC) {
490 int SourceIdx = SCCIndices[&SourceSCC];
491 int TargetIdx = SCCIndices[&TargetSCC];
492 if (TargetIdx < SourceIdx) {
504 ConnectedSet.insert(&SourceSCC);
505 auto IsConnected = [&](
SCC &
C) {
507 for (
Edge &
E : N.calls()) {
508 assert(
E.getNode() &&
"Must have formed a node within an SCC!");
509 if (ConnectedSet.count(G->
lookupSCC(*
E.getNode())))
517 make_range(SCCs.begin() + SourceIdx + 1, SCCs.begin() + TargetIdx + 1))
519 ConnectedSet.insert(C);
532 ConnectedSet.insert(&TargetSCC);
539 assert(
E.getNode() &&
"Must have formed a node within an SCC!");
546 if (SCCIndices.find(&EdgeC)->second <= SourceIdx)
550 if (ConnectedSet.insert(&EdgeC).second)
553 }
while (!Worklist.
empty());
561 SourceSCC, TargetSCC, SCCs, SCCIndices, ComputeSourceConnectedSet,
562 ComputeTargetConnectedSet);
566 if (MergeRange.begin() == MergeRange.end()) {
584 for (
SCC *C : MergeRange) {
586 "We merge *into* the target and shouldn't process it here!");
588 TargetSCC.Nodes.append(C->Nodes.begin(), C->Nodes.end());
589 for (
Node *N : C->Nodes)
590 G->SCCMap[
N] = &TargetSCC;
597 int IndexOffset = MergeRange.end() - MergeRange.begin();
598 auto EraseEnd = SCCs.erase(MergeRange.begin(), MergeRange.end());
600 SCCIndices[
C] -= IndexOffset;
611 assert(SourceN[TargetN].isCall() &&
"Must start with a call edge!");
621 "Source must be in this RefSCC.");
623 "Target must be in this RefSCC.");
625 "Source and Target must be in separate SCCs for this to be trivial!");
633 assert(SourceN[TargetN].isCall() &&
"Must start with a call edge!");
643 "Source must be in this RefSCC.");
645 "Target must be in this RefSCC.");
648 assert(G->
lookupSCC(SourceN) == &TargetSCC &&
"Source and Target must be in "
649 "the same SCC to require the "
667 SCC &OldSCC = TargetSCC;
674 Worklist.
swap(OldSCC.Nodes);
675 for (
Node *N : Worklist) {
676 N->DFSNumber = N->LowLink = 0;
688 TargetN.DFSNumber = TargetN.LowLink = -1;
689 OldSCC.Nodes.push_back(&TargetN);
690 G->SCCMap[&TargetN] = &OldSCC;
693 for (
Node *RootN : Worklist) {
695 "Cannot begin a new root with a non-empty DFS stack!");
697 "Cannot begin a new root with pending nodes for an SCC!");
700 if (RootN->DFSNumber != 0) {
701 assert(RootN->DFSNumber == -1 &&
702 "Shouldn't have any mid-DFS root nodes!");
706 RootN->DFSNumber = RootN->LowLink = 1;
707 int NextDFSNumber = 2;
709 DFSStack.
push_back({RootN, RootN->call_begin()});
716 Node &ChildN = *I->getNode();
717 if (ChildN.DFSNumber == 0) {
722 assert(!G->SCCMap.count(&ChildN) &&
723 "Found a node with 0 DFS number but already in an SCC!");
724 ChildN.DFSNumber = ChildN.LowLink = NextDFSNumber++;
732 if (ChildN.DFSNumber == -1) {
738 int OldSize = OldSCC.
size();
739 OldSCC.Nodes.push_back(N);
740 OldSCC.Nodes.append(PendingSCCStack.
begin(), PendingSCCStack.
end());
741 PendingSCCStack.
clear();
742 while (!DFSStack.
empty())
745 N.DFSNumber = N.LowLink = -1;
746 G->SCCMap[&
N] = &OldSCC;
760 assert(ChildN.LowLink > 0 &&
"Must have a positive low-link number!");
761 if (ChildN.LowLink < N->LowLink)
762 N->LowLink = ChildN.LowLink;
777 if (N->LowLink != N->DFSNumber)
782 int RootDFSNumber = N->DFSNumber;
788 return N->DFSNumber < RootDFSNumber;
793 NewSCCs.
push_back(G->createSCC(*
this, SCCNodes));
795 N.DFSNumber = N.LowLink = -1;
796 G->SCCMap[&
N] = NewSCCs.
back();
798 PendingSCCStack.
erase(SCCNodes.end().base(), PendingSCCStack.
end());
799 }
while (!DFSStack.
empty());
806 int OldIdx = SCCIndices[&OldSCC];
807 SCCs.insert(SCCs.begin() + OldIdx, NewSCCs.
begin(), NewSCCs.
end());
811 for (
int Idx = OldIdx, Size = SCCs.size(); Idx < Size; ++Idx)
812 SCCIndices[SCCs[Idx]] = Idx;
815 SCCs.begin() + OldIdx + NewSCCs.
size());
820 assert(!SourceN[TargetN].isCall() &&
"Must start with a ref edge!");
824 "Target must not be in this RefSCC.");
826 "Target must be a descendant of the Source.");
840 assert(SourceN[TargetN].isCall() &&
"Must start with a call edge!");
844 "Target must not be in this RefSCC.");
846 "Target must be a descendant of the Source.");
863 SourceN.insertEdgeInternal(TargetN,
Edge::Ref);
874 SourceN.insertEdgeInternal(TargetN, EK);
879 assert(&TargetC !=
this &&
"Target must not be in this RefSCC.");
880 assert(TargetC.isDescendantOf(*
this) &&
881 "Target must be a descendant of the Source.");
885 TargetC.Parents.insert(
this);
897 assert(&SourceC !=
this &&
"Source must not be in this RefSCC.");
898 assert(SourceC.isDescendantOf(*
this) &&
899 "Source must be a descendant of the Target.");
910 int SourceIdx = G->RefSCCIndices[&SourceC];
911 int TargetIdx = G->RefSCCIndices[
this];
912 assert(SourceIdx < TargetIdx &&
913 "Postorder list doesn't see edge as incoming!");
923 Set.insert(&SourceC);
931 int ParentIdx = G->getRefSCCIndex(ParentRC);
932 assert(ParentIdx > SourceIdx &&
"Parent cannot precede source in postorder!");
933 if (ParentIdx > TargetIdx)
935 if (Set.insert(&ParentRC).second)
939 }
while (!Worklist.
empty());
955 assert(
E.getNode() &&
"Must have formed a node!");
957 if (G->getRefSCCIndex(EdgeRC) <= SourceIdx)
961 if (Set.insert(&EdgeRC).second)
964 }
while (!Worklist.
empty());
973 SourceC, *
this, G->PostOrderRefSCCs, G->RefSCCIndices,
974 ComputeSourceConnectedSet, ComputeTargetConnectedSet);
987 for (
RefSCC *RC : MergeRange) {
988 assert(RC !=
this &&
"We're merging into the target RefSCC, so it "
989 "shouldn't be in the range.");
992 for (
RefSCC *ParentRC : RC->Parents)
993 if (!MergeSet.count(ParentRC))
994 Parents.insert(ParentRC);
1001 for (
SCC &InnerC : *RC) {
1002 InnerC.OuterRefSCC =
this;
1003 SCCIndices[&InnerC] = SCCIndex++;
1004 for (
Node &N : InnerC) {
1005 G->SCCMap[&
N] = &InnerC;
1008 "Cannot have a null node within a visited SCC!");
1010 if (MergeSet.count(&ChildRC))
1012 ChildRC.Parents.erase(RC);
1013 ChildRC.Parents.insert(
this);
1020 if (MergedSCCs.
empty())
1021 MergedSCCs = std::move(RC->SCCs);
1023 MergedSCCs.
append(RC->SCCs.begin(), RC->SCCs.end());
1025 DeletedRefSCCs.push_back(RC);
1029 for (
SCC &InnerC : *
this)
1030 SCCIndices[&InnerC] = SCCIndex++;
1031 MergedSCCs.
append(SCCs.begin(), SCCs.end());
1032 SCCs = std::move(MergedSCCs);
1035 for (
RefSCC *RC : MergeRange)
1036 G->RefSCCIndices.erase(RC);
1037 int IndexOffset = MergeRange.end() - MergeRange.begin();
1039 G->PostOrderRefSCCs.erase(MergeRange.begin(), MergeRange.end());
1041 G->RefSCCIndices[RC] -= IndexOffset;
1045 SourceN.insertEdgeInternal(TargetN,
Edge::Ref);
1051 return DeletedRefSCCs;
1056 "The source must be a member of this RefSCC.");
1059 assert(&TargetRC !=
this &&
"The target must not be a member of this RefSCC");
1062 "Cannot have a leaf RefSCC source.");
1072 SourceN.removeEdgeInternal(TargetN.
getFunction());
1074 bool HasOtherEdgeToChildRC =
false;
1075 bool HasOtherChildRC =
false;
1076 for (
SCC *InnerC : SCCs) {
1077 for (
Node &N : *InnerC) {
1079 assert(
E.getNode() &&
"Cannot have a missing node in a visited SCC!");
1081 if (&OtherChildRC == &TargetRC) {
1082 HasOtherEdgeToChildRC =
true;
1085 if (&OtherChildRC !=
this)
1086 HasOtherChildRC =
true;
1088 if (HasOtherEdgeToChildRC)
1091 if (HasOtherEdgeToChildRC)
1098 if (!HasOtherEdgeToChildRC) {
1099 bool Removed = TargetRC.Parents.erase(
this);
1102 "Did not find the source SCC in the target SCC's parent list!");
1106 if (TargetRC.Parents.empty())
1109 <<
" edge orphaned the callee's SCC!\n");
1112 if (!HasOtherChildRC)
1113 G->LeafRefSCCs.push_back(
this);
1119 assert(!SourceN[TargetN].isCall() &&
1120 "Cannot remove a call edge, it must first be made a ref edge");
1130 SourceN.removeEdgeInternal(TargetN.
getFunction());
1136 if (&SourceN == &TargetN)
1143 if (&SourceC == &TargetC)
1151 const int RootPostOrderNumber = 0;
1152 int PostOrderNumber = RootPostOrderNumber + 1;
1168 for (
Node &N : TargetC)
1169 PostOrderMapping[&
N] = RootPostOrderNumber;
1174 for (
SCC *C : SCCs) {
1179 N.DFSNumber = N.LowLink = 0;
1181 Worklist.
append(C->Nodes.begin(), C->Nodes.end());
1184 auto MarkNodeForSCCNumber = [&PostOrderMapping](
Node &
N,
int Number) {
1185 N.DFSNumber = N.LowLink = -1;
1186 PostOrderMapping[&
N] =
Number;
1193 "Cannot begin a new root with a non-empty DFS stack!");
1195 "Cannot begin a new root with pending nodes for an SCC!");
1199 if (RootN->DFSNumber != 0) {
1200 assert(RootN->DFSNumber == -1 &&
1201 "Shouldn't have any mid-DFS root nodes!");
1205 RootN->DFSNumber = RootN->LowLink = 1;
1206 int NextDFSNumber = 2;
1208 DFSStack.
push_back({RootN, RootN->begin()});
1215 assert(N->DFSNumber != 0 &&
"We should always assign a DFS number "
1216 "before processing a node.");
1219 Node &ChildN = I->getNode(*G);
1220 if (ChildN.DFSNumber == 0) {
1227 ChildN.LowLink = ChildN.DFSNumber = NextDFSNumber++;
1233 if (ChildN.DFSNumber == -1) {
1239 auto PostOrderI = PostOrderMapping.
find(&ChildN);
1240 if (PostOrderI != PostOrderMapping.
end() &&
1241 PostOrderI->second == RootPostOrderNumber) {
1242 MarkNodeForSCCNumber(*N, RootPostOrderNumber);
1243 while (!PendingRefSCCStack.
empty())
1244 MarkNodeForSCCNumber(*PendingRefSCCStack.
pop_back_val(),
1245 RootPostOrderNumber);
1246 while (!DFSStack.
empty())
1248 RootPostOrderNumber);
1258 ChildRC.Parents.erase(
this);
1265 assert(ChildN.LowLink != 0 &&
1266 "Low-link must not be zero with a non-zero DFS number.");
1267 if (ChildN.LowLink >= 0 && ChildN.LowLink < N->LowLink)
1268 N->LowLink = ChildN.LowLink;
1281 if (N->LowLink != N->DFSNumber) {
1283 "We never found a viable root for a RefSCC to pop off!");
1288 int RootDFSNumber = N->DFSNumber;
1292 PendingRefSCCStack.
rbegin(),
1294 return N->DFSNumber < RootDFSNumber;
1300 int RefSCCNumber = PostOrderNumber++;
1301 for (
Node *N : RefSCCNodes)
1302 MarkNodeForSCCNumber(*N, RefSCCNumber);
1304 PendingRefSCCStack.
erase(RefSCCNodes.end().base(),
1305 PendingRefSCCStack.
end());
1306 }
while (!DFSStack.
empty());
1308 assert(DFSStack.
empty() &&
"Didn't flush the entire DFS stack!");
1309 assert(PendingRefSCCStack.
empty() &&
"Didn't flush all pending nodes!");
1310 }
while (!Worklist.
empty());
1317 for (
int i = 1; i < PostOrderNumber; ++
i)
1329 if (!Result.
empty()) {
1330 int Idx = G->getRefSCCIndex(*
this);
1331 G->PostOrderRefSCCs.insert(G->PostOrderRefSCCs.begin() + Idx,
1333 for (
int i : seq<int>(Idx, G->PostOrderRefSCCs.size()))
1334 G->RefSCCIndices[G->PostOrderRefSCCs[
i]] =
i;
1335 assert(G->PostOrderRefSCCs[G->getRefSCCIndex(*
this)] ==
this &&
1336 "Failed to update this RefSCC's index after insertion!");
1339 for (
SCC *C : SCCs) {
1340 auto PostOrderI = PostOrderMapping.
find(&*C->begin());
1341 assert(PostOrderI != PostOrderMapping.
end() &&
1342 "Cannot have missing mappings for nodes!");
1343 int SCCNumber = PostOrderI->second;
1346 assert(PostOrderMapping.
find(&N)->second == SCCNumber &&
1347 "Cannot have different numbers for nodes in the same SCC!");
1353 RefSCC &RC = *Result[SCCNumber - 1];
1354 int SCCIndex = RC.SCCs.size();
1355 RC.SCCs.push_back(C);
1356 RC.SCCIndices[
C] = SCCIndex;
1357 C->OuterRefSCC = &RC;
1364 for (
RefSCC *RC : Result)
1365 G->connectRefSCC(*RC);
1371 RootPostOrderNumber;
1375 for (
int i = 0, Size = SCCs.size(); i < Size; ++
i)
1376 SCCIndices[SCCs[i]] = i;
1384 for (
Node &N : *C) {
1386 assert(
E.getNode() &&
"Cannot have a missing node in a visited SCC!");
1388 if (&ChildRC ==
this)
1390 ChildRC.Parents.insert(
this);
1397 if (!Result.empty())
1398 assert(!IsLeaf &&
"This SCC cannot be a leaf as we have split out new "
1399 "SCCs by removing this edge.");
1400 if (
none_of(G->LeafRefSCCs, [&](
RefSCC *C) {
return C ==
this; }))
1401 assert(!IsLeaf &&
"This SCC cannot be a leaf as it already had child "
1402 "SCCs before we removed this edge.");
1408 for (
RefSCC *ParentRC : OldParents)
1409 for (
SCC &ParentC : *ParentRC)
1410 for (
Node &ParentN : ParentC)
1411 for (
Edge &
E : ParentN) {
1412 assert(
E.getNode() &&
"Cannot have a missing node in a visited SCC!");
1414 if (&RC != ParentRC)
1415 RC.Parents.insert(ParentRC);
1423 if (!Result.empty())
1424 G->LeafRefSCCs.erase(
1425 std::remove(G->LeafRefSCCs.begin(), G->LeafRefSCCs.end(),
this),
1426 G->LeafRefSCCs.end());
1430 for (RefSCC *RC : Result)
1438 void LazyCallGraph::RefSCC::handleTrivialEdgeInsertion(Node &SourceN,
1446 if (&TargetRC ==
this) {
1451 assert(TargetRC.isDescendantOf(*
this) &&
1452 "Target must be a descendant of the Source.");
1455 TargetRC.Parents.insert(
this);
1467 if (&SourceC != &TargetC)
1468 assert(SourceC.isAncestorOf(TargetC) &&
1469 "Call edge is not trivial in the SCC graph!");
1472 auto InsertResult = SourceN.EdgeIndexMap.insert(
1474 if (!InsertResult.second) {
1476 Edge &
E = SourceN.Edges[InsertResult.first->second];
1486 handleTrivialEdgeInsertion(SourceN, TargetN);
1497 if (&SourceRC != &TargetRC)
1498 assert(SourceRC.isAncestorOf(TargetRC) &&
1499 "Ref edge is not trivial in the RefSCC graph!");
1502 auto InsertResult = SourceN.EdgeIndexMap.insert(
1504 if (!InsertResult.second)
1512 handleTrivialEdgeInsertion(SourceN, TargetN);
1516 assert(SCCMap.empty() && DFSStack.empty() &&
1517 "This method cannot be called after SCCs have been formed!");
1519 return SourceN.insertEdgeInternal(Target, EK);
1523 assert(SCCMap.empty() && DFSStack.empty() &&
1524 "This method cannot be called after SCCs have been formed!");
1526 return SourceN.removeEdgeInternal(Target);
1533 "This routine should only be called on trivially dead functions!");
1535 auto EII = EntryIndexMap.find(&F);
1536 if (EII != EntryIndexMap.end()) {
1537 EntryEdges[EII->second] =
Edge();
1538 EntryIndexMap.erase(EII);
1544 auto RENI =
find(RefSCCEntryNodes, &F);
1545 if (RENI != RefSCCEntryNodes.end())
1546 RefSCCEntryNodes.erase(RENI);
1548 auto NI = NodeMap.find(&F);
1549 if (NI == NodeMap.end())
1553 Node &N = *NI->second;
1556 if (SCCMap.empty() && DFSStack.empty()) {
1565 [&N](
const std::pair<Node *, edge_iterator> &Element) {
1566 return Element.first != &
N;
1568 "Tried to remove a function currently in the DFS stack!");
1569 assert(
find(PendingRefSCCStack, &N) == PendingRefSCCStack.end() &&
1570 "Tried to remove a function currently pending to add to a RefSCC!");
1574 auto CI = SCCMap.find(&N);
1575 assert(CI != SCCMap.end() &&
1576 "Tried to remove a node without an SCC after DFS walk started!");
1577 SCC &C = *CI->second;
1579 RefSCC &RC = C.getOuterRefSCC();
1584 assert(C.size() == 1 &&
"Dead functions must be in a singular SCC");
1585 assert(RC.
size() == 1 &&
"Dead functions must be in a singular RefSCC");
1586 assert(RC.Parents.empty() &&
"Cannot have parents of a dead RefSCC!");
1590 if (
Node *TargetN =
E.getNode())
1592 TargetRC->Parents.erase(&RC);
1595 auto LRI =
find(LeafRefSCCs, &RC);
1596 if (LRI != LeafRefSCCs.end())
1597 LeafRefSCCs.erase(LRI);
1599 auto RCIndexI = RefSCCIndices.find(&RC);
1600 int RCIndex = RCIndexI->second;
1601 PostOrderRefSCCs.erase(PostOrderRefSCCs.begin() + RCIndex);
1602 RefSCCIndices.erase(RCIndexI);
1603 for (
int i = RCIndex, Size = PostOrderRefSCCs.size(); i < Size; ++
i)
1604 RefSCCIndices[PostOrderRefSCCs[i]] = i;
1617 return *
new (MappedN = BPA.Allocate()) Node(*
this, F);
1620 void LazyCallGraph::updateGraphPtrs() {
1624 for (Edge &
E : EntryEdges)
1625 if (Node *EntryN =
E.getNode())
1628 while (!Worklist.
empty()) {
1631 for (Edge &
E : N->Edges)
1632 if (Node *TargetN = E.getNode())
1641 while (!Worklist.
empty()) {
1644 for (RefSCC &ParentC : C.parents())
1655 void LazyCallGraph::buildSCCs(RefSCC &RC, node_stack_range Nodes) {
1656 assert(RC.SCCs.empty() &&
"Already built SCCs!");
1657 assert(RC.SCCIndices.empty() &&
"Already mapped SCC indices!");
1659 for (Node *N : Nodes) {
1660 assert(N->LowLink >= (*Nodes.begin())->LowLink &&
1661 "We cannot have a low link in an SCC lower than its root on the "
1666 N->DFSNumber = N->LowLink = 0;
1677 for (Node *RootN : Nodes) {
1679 "Cannot begin a new root with a non-empty DFS stack!");
1681 "Cannot begin a new root with pending nodes for an SCC!");
1684 if (RootN->DFSNumber != 0) {
1685 assert(RootN->DFSNumber == -1 &&
1686 "Shouldn't have any mid-DFS root nodes!");
1690 RootN->DFSNumber = RootN->LowLink = 1;
1691 int NextDFSNumber = 2;
1693 DFSStack.
push_back({RootN, RootN->call_begin()});
1696 call_edge_iterator
I;
1698 auto E = N->call_end();
1700 Node &ChildN = *I->getNode();
1701 if (ChildN.DFSNumber == 0) {
1707 "Found a node with 0 DFS number but already in an SCC!");
1708 ChildN.DFSNumber = ChildN.LowLink = NextDFSNumber++;
1710 I = N->call_begin();
1718 if (ChildN.DFSNumber == -1) {
1724 assert(ChildN.LowLink > 0 &&
"Must have a positive low-link number!");
1725 if (ChildN.LowLink < N->LowLink)
1726 N->LowLink = ChildN.LowLink;
1738 if (N->LowLink != N->DFSNumber)
1743 int RootDFSNumber = N->DFSNumber;
1747 PendingSCCStack.
rbegin(),
1748 find_if(
reverse(PendingSCCStack), [RootDFSNumber](
const Node *N) {
1749 return N->DFSNumber < RootDFSNumber;
1753 RC.SCCs.push_back(createSCC(RC, SCCNodes));
1754 for (Node &N : *RC.SCCs.back()) {
1755 N.DFSNumber = N.LowLink = -1;
1756 SCCMap[&
N] = RC.SCCs.back();
1758 PendingSCCStack.
erase(SCCNodes.end().base(), PendingSCCStack.
end());
1759 }
while (!DFSStack.
empty());
1763 for (
int i = 0, Size = RC.SCCs.size(); i < Size; ++
i)
1764 RC.SCCIndices[RC.SCCs[i]] = i;
1769 void LazyCallGraph::connectRefSCC(RefSCC &RC) {
1778 "Cannot have a missing node in a visited part of the graph!");
1780 if (&ChildRC == &RC)
1782 ChildRC.Parents.insert(&RC);
1788 LeafRefSCCs.push_back(&RC);
1791 bool LazyCallGraph::buildNextRefSCCInPostOrder() {
1792 if (DFSStack.
empty()) {
1797 if (RefSCCEntryNodes.empty())
1800 N = &
get(*RefSCCEntryNodes.pop_back_val());
1801 }
while (N->DFSNumber != 0);
1804 N->LowLink = N->DFSNumber = 1;
1814 assert(N->DFSNumber > 0 &&
"We should always assign a DFS number "
1815 "before placing a node onto the stack.");
1819 Node &ChildN = I->getNode(*
this);
1820 if (ChildN.DFSNumber == 0) {
1825 assert(!SCCMap.count(&ChildN) &&
1826 "Found a node with 0 DFS number but already in an SCC!");
1827 ChildN.LowLink = ChildN.DFSNumber = NextDFSNumber++;
1837 if (ChildN.DFSNumber == -1) {
1843 assert(ChildN.LowLink > 0 &&
"Must have a positive low-link number!");
1844 if (ChildN.LowLink < N->LowLink)
1845 N->LowLink = ChildN.LowLink;
1853 PendingRefSCCStack.push_back(N);
1857 if (N->LowLink != N->DFSNumber) {
1859 "We never found a viable root for an SCC to pop off!");
1864 int RootDFSNumber = N->DFSNumber;
1867 auto RefSCCNodes = node_stack_range(
1868 PendingRefSCCStack.rbegin(),
1869 find_if(
reverse(PendingRefSCCStack), [RootDFSNumber](
const Node *N) {
1870 return N->DFSNumber < RootDFSNumber;
1874 RefSCC *NewRC = createRefSCC(*
this);
1875 buildSCCs(*NewRC, RefSCCNodes);
1876 connectRefSCC(*NewRC);
1877 PendingRefSCCStack.erase(RefSCCNodes.end().base(),
1878 PendingRefSCCStack.end());
1883 RefSCCIndices.insert({NewRC, PostOrderRefSCCs.size()}).second;
1885 assert(Inserted &&
"Cannot already have this RefSCC in the index map!");
1886 PostOrderRefSCCs.push_back(NewRC);
1898 OS <<
" " << (
E.isCall() ?
"call" :
"ref ") <<
" -> "
1899 <<
E.getFunction().getName() <<
"\n";
1905 ptrdiff_t Size = std::distance(C.
begin(), C.
end());
1906 OS <<
" SCC with " << Size <<
" functions:\n";
1909 OS <<
" " << N.getFunction().getName() <<
"\n";
1913 ptrdiff_t Size = std::distance(C.
begin(), C.
end());
1914 OS <<
" RefSCC with " << Size <<
" call SCCs:\n";
1945 OS <<
" " << Name <<
" -> \""
1948 OS <<
" [style=dashed,label=\"ref\"]";
SCC * lookupSCC(Node &N) const
Lookup a function's SCC in the graph.
void push_back(const T &Elt)
This routine provides some synthesis utilities to produce sequences of values.
bool isChildOf(const RefSCC &C) const
Test if this RefSCC is a child of C.
void removeOutgoingEdge(Node &SourceN, Node &TargetN)
Remove an edge whose source is in this RefSCC and target is not.
ValueT lookup(const KeyT &Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
A Module instance is used to store all the information related to an LLVM module. ...
auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range))
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly...
Kind
The kind of edge in the graph.
std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
Implements a lazy call graph analysis and related passes for the new pass manager.
static void addEdge(SmallVectorImpl< LazyCallGraph::Edge > &Edges, DenseMap< Function *, int > &EdgeIndexMap, Function &F, LazyCallGraph::Edge::Kind EK)
size_type count(PtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
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)
edge_iterator begin() const
StringRef getName() const
Return a constant reference to the value's name.
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)
SmallVector< SCC *, 1 > switchInternalEdgeToCall(Node &SourceN, Node &TargetN)
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...
bool isAncestorOf(const SCC &C) const
Test if this SCC is an ancestor of C.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly...
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
bool isDescendantOf(const RefSCC &C) const
Test if this RefSCC is a descendant of C.
edge_iterator end() const
LLVM_NODISCARD bool empty() const
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 isCall() const
Test whether the edge represents a direct call to a function.
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.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
iterator_range< parent_iterator > parents() const
LazyCallGraph & operator=(LazyCallGraph &&RHS)
void removeEdge(Node &Caller, Function &Callee)
Update the call graph after deleting an edge.
void switchOutgoingEdgeToCall(Node &SourceN, Node &TargetN)
Make an existing outgoing ref edge into a call edge.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
bool verify(const TargetRegisterInfo &TRI) const
Check that information hold by this instance make sense for the given TRI.
void insertEdge(Node &Caller, Function &Callee, Edge::Kind EK)
Update the call graph after inserting a new edge.
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.
LLVM Basic Block Representation.
LazyCallGraphDOTPrinterPass(raw_ostream &OS)
std::string EscapeString(const std::string &Label)
void swap(SmallVectorImpl &RHS)
This is an important base class in LLVM.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
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 > removeInternalRefEdge(Node &SourceN, Node &TargetN)
Remove a ref edge which is entirely within this RefSCC.
SmallVector< RefSCC *, 1 > insertIncomingRefEdge(Node &SourceN, Node &TargetN)
Insert an edge whose source is in a descendant RefSCC and target is in this RefSCC.
RefSCC & getOuterRefSCC() const
A node in the call graph.
A class used to represent edges in the call graph.
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
iterator erase(const_iterator CI)
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
A lazy iterator used for both the entry nodes and child nodes.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Function & getFunction() const
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 find(R &&Range, const T &Val) -> decltype(std::begin(Range))
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
static const char * Target
LLVM_NODISCARD T pop_back_val()
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.
A range adaptor for a pair of iterators.
Target - Wrapper for Target specific information.
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.
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)
Node * lookup(const Function &F) const
Lookup a function in the graph which has already been scanned and added.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
void emplace_back(ArgTypes &&...Args)
call_edge_iterator call_end() const
static void printRefSCC(raw_ostream &OS, LazyCallGraph::RefSCC &C)
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
iterator find(const KeyT &Val)
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())
A lazy iterator over specifically call edges.
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.
bool isParentOf(const SCC &C) const
Test if this SCC is a parent of C.
RefSCC * lookupRefSCC(Node &N) const
Lookup a function's RefSCC in the graph.
This header defines various interfaces for pass management in LLVM.
auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
LazyCallGraph(Module &M)
Construct a graph for the given module.
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...
call_edge_iterator call_begin() const
iterator_range< call_edge_iterator > calls() const
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.