summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r--llvm/lib/Analysis/LazyCallGraph.cpp165
1 files changed, 164 insertions, 1 deletions
diff --git a/llvm/lib/Analysis/LazyCallGraph.cpp b/llvm/lib/Analysis/LazyCallGraph.cpp
index febd756a9a0..2552dd8d1f8 100644
--- a/llvm/lib/Analysis/LazyCallGraph.cpp
+++ b/llvm/lib/Analysis/LazyCallGraph.cpp
@@ -1302,6 +1302,19 @@ LazyCallGraph::RefSCC::removeInternalRefEdge(Node &SourceN, Node &TargetN) {
assert(!IsLeaf && "This SCC cannot be a leaf as it already had child "
"SCCs before we removed this edge.");
#endif
+ // And connect both this RefSCC and all the new ones to the correct parents.
+ // The easiest way to do this is just to re-analyze the old parent set.
+ SmallVector<RefSCC *, 4> OldParents(Parents.begin(), Parents.end());
+ Parents.clear();
+ for (RefSCC *ParentRC : OldParents)
+ for (SCC *ParentC : ParentRC->SCCs)
+ for (Node &ParentN : *ParentC)
+ for (Edge &E : ParentN) {
+ assert(E.getNode() && "Cannot have a missing node in a visited SCC!");
+ RefSCC &RC = *G->lookupRefSCC(*E.getNode());
+ RC.Parents.insert(ParentRC);
+ }
+
// If this SCC stopped being a leaf through this edge removal, remove it from
// the leaf SCC list. Note that this DTRT in the case where this was never
// a leaf.
@@ -1316,6 +1329,69 @@ LazyCallGraph::RefSCC::removeInternalRefEdge(Node &SourceN, Node &TargetN) {
return Result;
}
+void LazyCallGraph::RefSCC::handleTrivialEdgeInsertion(Node &SourceN,
+ Node &TargetN) {
+ // The only trivial case that requires any graph updates is when we add new
+ // ref edge and may connect different RefSCCs along that path. This is only
+ // because of the parents set. Every other part of the graph remains constant
+ // after this edge insertion.
+ assert(G->lookupRefSCC(SourceN) == this && "Source must be in this RefSCC.");
+ RefSCC &TargetRC = *G->lookupRefSCC(TargetN);
+ if (&TargetRC == this) {
+
+ return;
+ }
+
+ assert(TargetRC.isDescendantOf(*this) &&
+ "Target must be a descendant of the Source.");
+ // The only change required is to add this RefSCC to the parent set of the
+ // target. This is a set and so idempotent if the edge already existed.
+ TargetRC.Parents.insert(this);
+}
+
+void LazyCallGraph::RefSCC::insertTrivialCallEdge(Node &SourceN,
+ Node &TargetN) {
+#ifndef NDEBUG
+ // Check that the RefSCC is still valid when we finish.
+ auto ExitVerifier = make_scope_exit([this] { verify(); });
+#endif
+ // First insert it into the source or find the existing edge.
+ auto InsertResult = SourceN.EdgeIndexMap.insert(
+ {&TargetN.getFunction(), SourceN.Edges.size()});
+ if (!InsertResult.second) {
+ // Already an edge, just update it.
+ Edge &E = SourceN.Edges[InsertResult.first->second];
+ if (E.isCall())
+ return; // Nothing to do!
+ E.setKind(Edge::Call);
+ } else {
+ // Create the new edge.
+ SourceN.Edges.emplace_back(TargetN, Edge::Call);
+ }
+
+ // Now that we have the edge, handle the graph fallout.
+ handleTrivialEdgeInsertion(SourceN, TargetN);
+}
+
+void LazyCallGraph::RefSCC::insertTrivialRefEdge(Node &SourceN, Node &TargetN) {
+#ifndef NDEBUG
+ // Check that the RefSCC is still valid when we finish.
+ auto ExitVerifier = make_scope_exit([this] { verify(); });
+#endif
+ // First insert it into the source or find the existing edge.
+ auto InsertResult = SourceN.EdgeIndexMap.insert(
+ {&TargetN.getFunction(), SourceN.Edges.size()});
+ if (!InsertResult.second)
+ // Already an edge, we're done.
+ return;
+
+ // Create the new edge.
+ SourceN.Edges.emplace_back(TargetN, Edge::Ref);
+
+ // Now that we have the edge, handle the graph fallout.
+ handleTrivialEdgeInsertion(SourceN, TargetN);
+}
+
void LazyCallGraph::insertEdge(Node &SourceN, Function &Target, Edge::Kind EK) {
assert(SCCMap.empty() && DFSStack.empty() &&
"This method cannot be called after SCCs have been formed!");
@@ -1330,6 +1406,93 @@ void LazyCallGraph::removeEdge(Node &SourceN, Function &Target) {
return SourceN.removeEdgeInternal(Target);
}
+void LazyCallGraph::removeDeadFunction(Function &F) {
+ // FIXME: This is unnecessarily restrictive. We should be able to remove
+ // functions which recursively call themselves.
+ assert(F.use_empty() &&
+ "This routine should only be called on trivially dead functions!");
+
+ auto EII = EntryIndexMap.find(&F);
+ if (EII != EntryIndexMap.end()) {
+ EntryEdges[EII->second] = Edge();
+ EntryIndexMap.erase(EII);
+ }
+
+ // It's safe to just remove un-visited functions from the RefSCC entry list.
+ // FIXME: This is a linear operation which could become hot and benefit from
+ // an index map.
+ auto RENI = find(RefSCCEntryNodes, &F);
+ if (RENI != RefSCCEntryNodes.end())
+ RefSCCEntryNodes.erase(RENI);
+
+ auto NI = NodeMap.find(&F);
+ if (NI == NodeMap.end())
+ // Not in the graph at all!
+ return;
+
+ Node &N = *NI->second;
+ NodeMap.erase(NI);
+
+ if (SCCMap.empty() && DFSStack.empty()) {
+ // No SCC walk has begun, so removing this is fine and there is nothing
+ // else necessary at this point but clearing out the node.
+ N.clear();
+ return;
+ }
+
+ // Check that we aren't going to break the DFS walk.
+ assert(all_of(DFSStack,
+ [&N](const std::pair<Node *, edge_iterator> &Element) {
+ return Element.first != &N;
+ }) &&
+ "Tried to remove a function currently in the DFS stack!");
+ assert(find(PendingRefSCCStack, &N) == PendingRefSCCStack.end() &&
+ "Tried to remove a function currently pending to add to a RefSCC!");
+
+ // Cannot remove a function which has yet to be visited in the DFS walk, so
+ // if we have a node at all then we must have an SCC and RefSCC.
+ auto CI = SCCMap.find(&N);
+ assert(CI != SCCMap.end() &&
+ "Tried to remove a node without an SCC after DFS walk started!");
+ SCC &C = *CI->second;
+ SCCMap.erase(CI);
+ RefSCC &RC = C.getOuterRefSCC();
+
+ // This node must be the only member of its SCC as it has no callers, and
+ // that SCC must be the only member of a RefSCC as it has no references.
+ // Validate these properties first.
+ assert(C.size() == 1 && "Dead functions must be in a singular SCC");
+ assert(RC.size() == 1 && "Dead functions must be in a singular RefSCC");
+ assert(RC.Parents.empty() && "Cannot have parents of a dead RefSCC!");
+
+ // Now remove this RefSCC from any parents sets and the leaf list.
+ for (Edge &E : N)
+ if (Node *TargetN = E.getNode())
+ if (RefSCC *TargetRC = lookupRefSCC(*TargetN))
+ TargetRC->Parents.erase(&RC);
+ // FIXME: This is a linear operation which could become hot and benefit from
+ // an index map.
+ auto LRI = find(LeafRefSCCs, &RC);
+ if (LRI != LeafRefSCCs.end())
+ LeafRefSCCs.erase(LRI);
+
+ auto RCIndexI = RefSCCIndices.find(&RC);
+ int RCIndex = RCIndexI->second;
+ PostOrderRefSCCs.erase(PostOrderRefSCCs.begin() + RCIndex);
+ RefSCCIndices.erase(RCIndexI);
+ for (int i = RCIndex, Size = PostOrderRefSCCs.size(); i < Size; ++i)
+ RefSCCIndices[PostOrderRefSCCs[i]] = i;
+
+ // Finally clear out all the data structures from the node down through the
+ // components.
+ N.clear();
+ C.clear();
+ RC.clear();
+
+ // Nothing to delete as all the objects are allocated in stable bump pointer
+ // allocators.
+}
+
LazyCallGraph::Node &LazyCallGraph::insertInto(Function &F, Node *&MappedN) {
return *new (MappedN = BPA.Allocate()) Node(*this, F);
}
@@ -1500,7 +1663,7 @@ void LazyCallGraph::connectRefSCC(RefSCC &RC) {
IsLeaf = false;
}
- // For the SCCs where we fine no child SCCs, add them to the leaf list.
+ // For the SCCs where we find no child SCCs, add them to the leaf list.
if (IsLeaf)
LeafRefSCCs.push_back(&RC);
}
OpenPOWER on IntegriCloud