summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis/LazyCallGraph.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2016-11-22 19:23:31 +0000
committerChandler Carruth <chandlerc@gmail.com>2016-11-22 19:23:31 +0000
commitbae595b742b4034c8ada98bd995bc395727f5b5e (patch)
tree97742c607c04b711dad533841d54df91f4552f05 /llvm/lib/Analysis/LazyCallGraph.cpp
parent6efb8dd2e396a8d585bb921b7d36be02a422b037 (diff)
downloadbcm5719-llvm-bae595b742b4034c8ada98bd995bc395727f5b5e.tar.gz
bcm5719-llvm-bae595b742b4034c8ada98bd995bc395727f5b5e.zip
[LCG] Add utilities to compute parent and ascestor relationships between
SCCs. These will be fairly expensive routines to call and might be abused in real code, but are quite useful when debugging or in asserts and are reasonable and well formed properties to query. I've used one of them in an assert that was requested in a code review here. In subsequent commits I'll start using these routines more heavily, for example in unittests etc. But this at least gets the groundwork in place. Differential Revision: https://reviews.llvm.org/D25506 llvm-svn: 287682
Diffstat (limited to 'llvm/lib/Analysis/LazyCallGraph.cpp')
-rw-r--r--llvm/lib/Analysis/LazyCallGraph.cpp58
1 files changed, 58 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/LazyCallGraph.cpp b/llvm/lib/Analysis/LazyCallGraph.cpp
index 2552dd8d1f8..9377fcb0d60 100644
--- a/llvm/lib/Analysis/LazyCallGraph.cpp
+++ b/llvm/lib/Analysis/LazyCallGraph.cpp
@@ -187,6 +187,57 @@ void LazyCallGraph::SCC::verify() {
}
#endif
+bool LazyCallGraph::SCC::isParentOf(const SCC &C) const {
+ if (this == &C)
+ return false;
+
+ for (Node &N : *this)
+ for (Edge &E : N.calls())
+ if (Node *CalleeN = E.getNode())
+ if (OuterRefSCC->G->lookupSCC(*CalleeN) == &C)
+ return true;
+
+ // No edges found.
+ return false;
+}
+
+bool LazyCallGraph::SCC::isAncestorOf(const SCC &TargetC) const {
+ if (this == &TargetC)
+ return false;
+
+ LazyCallGraph &G = *OuterRefSCC->G;
+
+ // Start with this SCC.
+ SmallPtrSet<const SCC *, 16> Visited = {this};
+ SmallVector<const SCC *, 16> Worklist = {this};
+
+ // Walk down the graph until we run out of edges or find a path to TargetC.
+ do {
+ const SCC &C = *Worklist.pop_back_val();
+ for (Node &N : C)
+ for (Edge &E : N.calls()) {
+ Node *CalleeN = E.getNode();
+ if (!CalleeN)
+ continue;
+ SCC *CalleeC = G.lookupSCC(*CalleeN);
+ if (!CalleeC)
+ continue;
+
+ // If the callee's SCC is the TargetC, we're done.
+ if (CalleeC == &TargetC)
+ return true;
+
+ // If this is the first time we've reached this SCC, put it on the
+ // worklist to recurse through.
+ if (Visited.insert(CalleeC).second)
+ Worklist.push_back(CalleeC);
+ }
+ } while (!Worklist.empty());
+
+ // No paths found.
+ return false;
+}
+
LazyCallGraph::RefSCC::RefSCC(LazyCallGraph &G) : G(&G) {}
void LazyCallGraph::RefSCC::dump() const {
@@ -1354,6 +1405,13 @@ void LazyCallGraph::RefSCC::insertTrivialCallEdge(Node &SourceN,
#ifndef NDEBUG
// Check that the RefSCC is still valid when we finish.
auto ExitVerifier = make_scope_exit([this] { verify(); });
+
+ // Check that we aren't breaking some invariants of the SCC graph.
+ SCC &SourceC = *G->lookupSCC(SourceN);
+ SCC &TargetC = *G->lookupSCC(TargetN);
+ if (&SourceC != &TargetC)
+ assert(SourceC.isAncestorOf(TargetC) &&
+ "Call edge is not trivial in the SCC graph!");
#endif
// First insert it into the source or find the existing edge.
auto InsertResult = SourceN.EdgeIndexMap.insert(
OpenPOWER on IntegriCloud