[llvm] r294227 - [PM/LCG] Remove the lazy RefSCC formation from the LazyCallGraph during
Laurent Carlier via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 6 14:48:32 PST 2017
Le lundi 6 février 2017, 19:38:06 CET Chandler Carruth via llvm-commits a
écrit :
> Author: chandlerc
> Date: Mon Feb 6 13:38:06 2017
> New Revision: 294227
>
> URL: http://llvm.org/viewvc/llvm-project?rev=294227&view=rev
> Log:
> [PM/LCG] Remove the lazy RefSCC formation from the LazyCallGraph during
> iteration.
>
> The lazy formation of RefSCCs isn't really the most important part of
> the laziness here -- that has to do with walking the functions
> themselves -- and isn't essential to maintain. Originally, there were
> incremental update algorithms that relied on updates happening
> predominantly near the most recent RefSCC formed, but those have been
> replaced with ones that have much tighter general case bounds at this
> point. We do still perform asserts that only scale well due to this
> incrementality, but those are easy to place behind EXPENSIVE_CHECKS.
>
> Removing this simplifies the entire analysis by having a single up-front
> step that builds all of the RefSCCs in a direct Tarjan walk. We can even
> easily replace this with other or better algorithms at will and with
> much less confusion now that there is no iterator-based incremental
> logic involved. This removes a lot of complexity from LCG.
>
> Another advantage of moving in this direction is that it simplifies
> testing the system substantially as we no longer have to worry about
> observing and mutating the graph half-way through the RefSCC formation.
>
> We still need a somewhat special iterator for RefSCCs because we want
> the iterator to remain stable in the face of graph updates. However,
> this now merely involves relative indexing to the current RefSCC's
> position in the sequence which isn't too hard.
>
> Differential Revision: https://reviews.llvm.org/D29381
>
> Modified:
> llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h
> llvm/trunk/include/llvm/Analysis/LazyCallGraph.h
> llvm/trunk/lib/Analysis/CGSCCPassManager.cpp
> llvm/trunk/lib/Analysis/LazyCallGraph.cpp
> llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp
>
> Modified: llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CGSCCP
> assManager.h?rev=294227&r1=294226&r2=294227&view=diff
> ===========================================================================
> === --- llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h (original) +++
> llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h Mon Feb 6 13:38:06
> 2017 @@ -334,6 +334,7 @@ public:
> InvalidSCCSet, nullptr, nullptr};
>
> PreservedAnalyses PA = PreservedAnalyses::all();
> + CG.buildRefSCCs();
> for (auto RCI = CG.postorder_ref_scc_begin(),
> RCE = CG.postorder_ref_scc_end();
> RCI != RCE;) {
>
> Modified: llvm/trunk/include/llvm/Analysis/LazyCallGraph.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LazyCa
> llGraph.h?rev=294227&r1=294226&r2=294227&view=diff
> ===========================================================================
> === --- llvm/trunk/include/llvm/Analysis/LazyCallGraph.h (original)
> +++ llvm/trunk/include/llvm/Analysis/LazyCallGraph.h Mon Feb 6 13:38:06
> 2017 @@ -794,14 +794,10 @@ public:
>
> /// A post-order depth-first RefSCC iterator over the call graph.
> ///
> - /// This iterator triggers the Tarjan DFS-based formation of the RefSCC
> (and - /// SCC) DAG for the call graph, walking it lazily in depth-first
> post-order. - /// That is, it always visits RefSCCs for the target of a
> reference edge - /// prior to visiting the RefSCC for a source of the edge
> (when they are in - /// different RefSCCs).
> - ///
> - /// When forming each RefSCC, the call edges within it are used to form
> SCCs - /// within it, so iterating this also controls the lazy formation
> of SCCs. + /// This iterator walks the cached post-order sequence of
> RefSCCs. However, + /// it trades stability for flexibility. It is
> restricted to a forward + /// iterator but will survive mutations which
> insert new RefSCCs and continue + /// to point to the same RefSCC even if
> it moves in the post-order sequence. class postorder_ref_scc_iterator
>
> : public iterator_facade_base<postorder_ref_scc_iterator,
>
> std::forward_iterator_tag, RefSCC> {
> @@ -825,12 +821,9 @@ public:
> /// populating it if necessary.
> static RefSCC *getRC(LazyCallGraph &G, int Index) {
> if (Index == (int)G.PostOrderRefSCCs.size())
> - if (!G.buildNextRefSCCInPostOrder())
> - // We're at the end.
> - return nullptr;
> + // We're at the end.
> + return nullptr;
>
> - assert(Index < (int)G.PostOrderRefSCCs.size() &&
> - "Built the next post-order RefSCC without growing list!");
> return G.PostOrderRefSCCs[Index];
> }
>
> @@ -866,10 +859,18 @@ public:
> return edge_iterator(EntryEdges.end(), EntryEdges.end());
> }
>
> + void buildRefSCCs();
> +
> postorder_ref_scc_iterator postorder_ref_scc_begin() {
> + if (!EntryEdges.empty())
> + assert(!PostOrderRefSCCs.empty() &&
> + "Must form RefSCCs before iterating them!");
> return postorder_ref_scc_iterator(*this);
> }
> postorder_ref_scc_iterator postorder_ref_scc_end() {
> + if (!EntryEdges.empty())
> + assert(!PostOrderRefSCCs.empty() &&
> + "Must form RefSCCs before iterating them!");
> return postorder_ref_scc_iterator(*this,
>
> postorder_ref_scc_iterator::IsAtEndT()); }
> @@ -1045,18 +1046,6 @@ private:
> /// These are all of the RefSCCs which have no children.
> SmallVector<RefSCC *, 4> LeafRefSCCs;
>
> - /// Stack of nodes in the DFS walk.
> - SmallVector<std::pair<Node *, edge_iterator>, 4> DFSStack;
> -
> - /// Set of entry nodes not-yet-processed into RefSCCs.
> - SmallVector<Function *, 4> RefSCCEntryNodes;
> -
> - /// Stack of nodes the DFS has walked but not yet put into a RefSCC.
> - SmallVector<Node *, 4> PendingRefSCCStack;
> -
> - /// Counter for the next DFS number to assign.
> - int NextDFSNumber;
> -
> /// Helper to insert a new function, with an already looked-up entry in
> /// the NodeMap.
> Node &insertInto(Function &F, Node *&MappedN);
> @@ -1078,6 +1067,23 @@ private:
> return new (RefSCCBPA.Allocate()) RefSCC(std::forward<Ts>(Args)...);
> }
>
> + /// Common logic for building SCCs from a sequence of roots.
> + ///
> + /// This is a very generic implementation of the depth-first walk and SCC
> + /// formation algorithm. It uses a generic sequence of roots and generic
> + /// callbacks for each step. This is designed to be used to implement
> both + /// the RefSCC formation and SCC formation with shared logic.
> + ///
> + /// Currently this is a relatively naive implementation of Tarjan's DFS
> + /// algorithm to form the SCCs.
> + ///
> + /// FIXME: We should consider newer variants such as Nuutila.
> + template <typename RootsT, typename GetBeginT, typename GetEndT,
> + typename GetNodeT, typename FormSCCCallbackT>
> + static void buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,
> + GetEndT &&GetEnd, GetNodeT &&GetNode,
> + FormSCCCallbackT &&FormSCC);
> +
> /// Build the SCCs for a RefSCC out of a list of nodes.
> void buildSCCs(RefSCC &RC, node_stack_range Nodes);
>
> @@ -1098,13 +1104,6 @@ private:
> "Index does not point back at RC!");
> return IndexIt->second;
> }
> -
> - /// Builds the next node in the post-order RefSCC walk of the call graph
> and - /// appends it to the \c PostOrderRefSCCs vector.
> - ///
> - /// Returns true if a new RefSCC was successfully constructed, and false
> if - /// there are no more RefSCCs to build in the graph.
> - bool buildNextRefSCCInPostOrder();
> };
>
> inline LazyCallGraph::Edge::Edge() : Value() {}
>
> Modified: llvm/trunk/lib/Analysis/CGSCCPassManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CGSCCPassManage
> r.cpp?rev=294227&r1=294226&r2=294227&view=diff
> ===========================================================================
> === --- llvm/trunk/lib/Analysis/CGSCCPassManager.cpp (original)
> +++ llvm/trunk/lib/Analysis/CGSCCPassManager.cpp Mon Feb 6 13:38:06 2017
> @@ -117,6 +117,7 @@ bool CGSCCAnalysisManagerModuleProxy::Re
> PA.allAnalysesInSetPreserved<AllAnalysesOn<LazyCallGraph::SCC>>();
>
> // Ok, we have a graph, so we can propagate the invalidation down into
> it. + G->buildRefSCCs();
> for (auto &RC : G->postorder_ref_sccs())
> for (auto &C : RC) {
> Optional<PreservedAnalyses> InnerPA;
>
> Modified: llvm/trunk/lib/Analysis/LazyCallGraph.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyCallGraph.c
> pp?rev=294227&r1=294226&r2=294227&view=diff
> ===========================================================================
> === --- llvm/trunk/lib/Analysis/LazyCallGraph.cpp (original)
> +++ llvm/trunk/lib/Analysis/LazyCallGraph.cpp Mon Feb 6 13:38:06 2017
> @@ -18,6 +18,7 @@
> #include "llvm/IR/PassManager.h"
> #include "llvm/Support/Debug.h"
> #include "llvm/Support/GraphWriter.h"
> +#include <utility>
>
> using namespace llvm;
>
> @@ -114,7 +115,7 @@ LLVM_DUMP_METHOD void LazyCallGraph::Nod
> }
> #endif
>
> -LazyCallGraph::LazyCallGraph(Module &M) : NextDFSNumber(0) {
> +LazyCallGraph::LazyCallGraph(Module &M) {
> DEBUG(dbgs() << "Building CG for module: " << M.getModuleIdentifier()
> << "\n");
> for (Function &F : M)
> @@ -138,19 +139,13 @@ LazyCallGraph::LazyCallGraph(Module &M)
> visitReferences(Worklist, Visited, [&](Function &F) {
> addEdge(EntryEdges, EntryIndexMap, F, LazyCallGraph::Edge::Ref);
> });
> -
> - for (const Edge &E : EntryEdges)
> - RefSCCEntryNodes.push_back(&E.getFunction());
> }
>
> LazyCallGraph::LazyCallGraph(LazyCallGraph &&G)
>
> : BPA(std::move(G.BPA)), NodeMap(std::move(G.NodeMap)),
>
> EntryEdges(std::move(G.EntryEdges)),
> EntryIndexMap(std::move(G.EntryIndexMap)),
> SCCBPA(std::move(G.SCCBPA)), - SCCMap(std::move(G.SCCMap)),
> LeafRefSCCs(std::move(G.LeafRefSCCs)), -
> DFSStack(std::move(G.DFSStack)),
> - RefSCCEntryNodes(std::move(G.RefSCCEntryNodes)),
> - NextDFSNumber(G.NextDFSNumber) {
> + SCCMap(std::move(G.SCCMap)), LeafRefSCCs(std::move(G.LeafRefSCCs)) {
> updateGraphPtrs();
> }
>
> @@ -162,9 +157,6 @@ LazyCallGraph &LazyCallGraph::operator=(
> SCCBPA = std::move(G.SCCBPA);
> SCCMap = std::move(G.SCCMap);
> LeafRefSCCs = std::move(G.LeafRefSCCs);
> - DFSStack = std::move(G.DFSStack);
> - RefSCCEntryNodes = std::move(G.RefSCCEntryNodes);
> - NextDFSNumber = G.NextDFSNumber;
> updateGraphPtrs();
> return *this;
> }
> @@ -828,8 +820,10 @@ void LazyCallGraph::RefSCC::switchOutgoi
> assert(G->lookupRefSCC(SourceN) == this && "Source must be in this
> RefSCC."); assert(G->lookupRefSCC(TargetN) != this &&
> "Target must not be in this RefSCC.");
> +#ifdef EXPENSIVE_CEHCKS
Is this a typo? (instead of EXPENSIVE_CHECKS)
> assert(G->lookupRefSCC(TargetN)->isDescendantOf(*this) &&
> "Target must be a descendant of the Source.");
> +#endif
>
> // Edges between RefSCCs are the same regardless of call or ref, so we
> can // just flip the edge here.
> @@ -848,8 +842,10 @@ void LazyCallGraph::RefSCC::switchOutgoi
> assert(G->lookupRefSCC(SourceN) == this && "Source must be in this
> RefSCC."); assert(G->lookupRefSCC(TargetN) != this &&
> "Target must not be in this RefSCC.");
> +#ifdef EXPENSIVE_CEHCKS
Same here
> assert(G->lookupRefSCC(TargetN)->isDescendantOf(*this) &&
> "Target must be a descendant of the Source.");
> +#endif
>
> // Edges between RefSCCs are the same regardless of call or ref, so we
> can // just flip the edge here.
> @@ -883,8 +879,10 @@ void LazyCallGraph::RefSCC::insertOutgoi
>
> RefSCC &TargetC = *G->lookupRefSCC(TargetN);
> assert(&TargetC != this && "Target must not be in this RefSCC.");
> +#ifdef EXPENSIVE_CEHCKS
idem
> assert(TargetC.isDescendantOf(*this) &&
> "Target must be a descendant of the Source.");
> +#endif
>
> // The only change required is to add this SCC to the parent set of the
> // callee.
> @@ -901,8 +899,10 @@ LazyCallGraph::RefSCC::insertIncomingRef
> assert(G->lookupRefSCC(TargetN) == this && "Target must be in this
> RefSCC."); RefSCC &SourceC = *G->lookupRefSCC(SourceN);
> assert(&SourceC != this && "Source must not be in this RefSCC.");
> +#ifdef EXPENSIVE_CEHCKS
idem
> assert(SourceC.isDescendantOf(*this) &&
> "Source must be a descendant of the Target.");
> +#endif
>
> SmallVector<RefSCC *, 1> DeletedRefSCCs;
>
> @@ -1454,8 +1454,10 @@ void LazyCallGraph::RefSCC::handleTrivia
> return;
> }
>
> +#ifdef EXPENSIVE_CEHCKS
idem
> assert(TargetRC.isDescendantOf(*this) &&
> "Target must be a descendant of the Source.");
> +#endif
> // 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);
> @@ -1467,13 +1469,17 @@ void LazyCallGraph::RefSCC::insertTrivia
> // 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.
> +#ifdef EXPENSIVE_CHECKS
> + // Check that we aren't breaking some invariants of the SCC graph. Note
> that + // this is quadratic in the number of edges in the call 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
> +#endif // EXPENSIVE_CHECKS
> +#endif // NDEBUG
> +
> // First insert it into the source or find the existing edge.
> auto InsertResult = SourceN.EdgeIndexMap.insert(
> {&TargetN.getFunction(), SourceN.Edges.size()});
> @@ -1497,13 +1503,16 @@ void LazyCallGraph::RefSCC::insertTrivia
> // Check that the RefSCC is still valid when we finish.
> auto ExitVerifier = make_scope_exit([this] { verify(); });
>
> +#ifdef EXPENSIVE_CHECKS
> // Check that we aren't breaking some invariants of the RefSCC graph.
> RefSCC &SourceRC = *G->lookupRefSCC(SourceN);
> RefSCC &TargetRC = *G->lookupRefSCC(TargetN);
> if (&SourceRC != &TargetRC)
> assert(SourceRC.isAncestorOf(TargetRC) &&
> "Ref edge is not trivial in the RefSCC graph!");
> -#endif
> +#endif // EXPENSIVE_CHECKS
> +#endif // NDEBUG
> +
> // First insert it into the source or find the existing edge.
> auto InsertResult = SourceN.EdgeIndexMap.insert(
> {&TargetN.getFunction(), SourceN.Edges.size()});
> @@ -1519,14 +1528,14 @@ void LazyCallGraph::RefSCC::insertTrivia
> }
>
> void LazyCallGraph::insertEdge(Node &SourceN, Function &Target, Edge::Kind
> EK) { - assert(SCCMap.empty() && DFSStack.empty() &&
> + assert(SCCMap.empty() &&
> "This method cannot be called after SCCs have been formed!");
>
> return SourceN.insertEdgeInternal(Target, EK);
> }
>
> void LazyCallGraph::removeEdge(Node &SourceN, Function &Target) {
> - assert(SCCMap.empty() && DFSStack.empty() &&
> + assert(SCCMap.empty() &&
> "This method cannot be called after SCCs have been formed!");
>
> return SourceN.removeEdgeInternal(Target);
> @@ -1544,13 +1553,6 @@ void LazyCallGraph::removeDeadFunction(F
> 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!
> @@ -1559,22 +1561,13 @@ void LazyCallGraph::removeDeadFunction(F
> 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
> + if (SCCMap.empty()) {
> + // No SCCs have been formed, 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);
> @@ -1653,34 +1646,18 @@ void LazyCallGraph::updateGraphPtrs() {
> }
> }
>
> -/// Build the internal SCCs for a RefSCC from a sequence of nodes.
> -///
> -/// Appends the SCCs to the provided vector and updates the map with their
> -/// indices. Both the vector and map must be empty when passed into this
> -/// routine.
> -void LazyCallGraph::buildSCCs(RefSCC &RC, node_stack_range Nodes) {
> - assert(RC.SCCs.empty() && "Already built SCCs!");
> - assert(RC.SCCIndices.empty() && "Already mapped SCC indices!");
> -
> - for (Node *N : Nodes) {
> - assert(N->LowLink >= (*Nodes.begin())->LowLink &&
> - "We cannot have a low link in an SCC lower than its root on the
> " - "stack!");
> -
> - // This node will go into the next RefSCC, clear out its DFS and low
> link - // as we scan.
> - N->DFSNumber = N->LowLink = 0;
> - }
> +template <typename RootsT, typename GetBeginT, typename GetEndT,
> + typename GetNodeT, typename FormSCCCallbackT>
> +void LazyCallGraph::buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,
> + GetEndT &&GetEnd, GetNodeT &&GetNode,
> + FormSCCCallbackT &&FormSCC) {
> + typedef decltype(GetBegin(std::declval<Node &>())) EdgeItT;
>
> - // Each RefSCC contains a DAG of the call SCCs. To build these, we do
> - // a direct walk of the call edges using Tarjan's algorithm. We reuse the
> - // internal storage as we won't need it for the outer graph's DFS any
> longer. -
> - SmallVector<std::pair<Node *, call_edge_iterator>, 16> DFSStack;
> + SmallVector<std::pair<Node *, EdgeItT>, 16> DFSStack;
> SmallVector<Node *, 16> PendingSCCStack;
>
> // Scan down the stack and DFS across the call edges.
> - for (Node *RootN : Nodes) {
> + for (Node *RootN : Roots) {
> assert(DFSStack.empty() &&
> "Cannot begin a new root with a non-empty DFS stack!");
> assert(PendingSCCStack.empty() &&
> @@ -1696,25 +1673,23 @@ void LazyCallGraph::buildSCCs(RefSCC &RC
> RootN->DFSNumber = RootN->LowLink = 1;
> int NextDFSNumber = 2;
>
> - DFSStack.push_back({RootN, RootN->call_begin()});
> + DFSStack.push_back({RootN, GetBegin(*RootN)});
> do {
> Node *N;
> - call_edge_iterator I;
> + EdgeItT I;
> std::tie(N, I) = DFSStack.pop_back_val();
> - auto E = N->call_end();
> + auto E = GetEnd(*N);
> while (I != E) {
> - Node &ChildN = *I->getNode();
> + Node &ChildN = GetNode(I);
> if (ChildN.DFSNumber == 0) {
> // We haven't yet visited this child, so descend, pushing the
> current // node onto the stack.
> DFSStack.push_back({N, I});
>
> - assert(!lookupSCC(ChildN) &&
> - "Found a node with 0 DFS number but already in an SCC!");
> ChildN.DFSNumber = ChildN.LowLink = NextDFSNumber++;
> N = &ChildN;
> - I = N->call_begin();
> - E = N->call_end();
> + I = GetBegin(*N);
> + E = GetEnd(*N);
> continue;
> }
>
> @@ -1756,20 +1731,90 @@ void LazyCallGraph::buildSCCs(RefSCC &RC
> }));
> // Form a new SCC out of these nodes and then clear them off our
> pending // stack.
> - RC.SCCs.push_back(createSCC(RC, SCCNodes));
> - for (Node &N : *RC.SCCs.back()) {
> - N.DFSNumber = N.LowLink = -1;
> - SCCMap[&N] = RC.SCCs.back();
> - }
> + FormSCC(SCCNodes);
> PendingSCCStack.erase(SCCNodes.end().base(), PendingSCCStack.end());
> } while (!DFSStack.empty());
> }
> +}
> +
> +/// Build the internal SCCs for a RefSCC from a sequence of nodes.
> +///
> +/// Appends the SCCs to the provided vector and updates the map with their
> +/// indices. Both the vector and map must be empty when passed into this
> +/// routine.
> +void LazyCallGraph::buildSCCs(RefSCC &RC, node_stack_range Nodes) {
> + assert(RC.SCCs.empty() && "Already built SCCs!");
> + assert(RC.SCCIndices.empty() && "Already mapped SCC indices!");
> +
> + for (Node *N : Nodes) {
> + assert(N->LowLink >= (*Nodes.begin())->LowLink &&
> + "We cannot have a low link in an SCC lower than its root on the
> " + "stack!");
> +
> + // This node will go into the next RefSCC, clear out its DFS and low
> link + // as we scan.
> + N->DFSNumber = N->LowLink = 0;
> + }
> +
> + // Each RefSCC contains a DAG of the call SCCs. To build these, we do
> + // a direct walk of the call edges using Tarjan's algorithm. We reuse the
> + // internal storage as we won't need it for the outer graph's DFS any
> longer. + buildGenericSCCs(Nodes, [](Node &N) { return N.call_begin(); },
> + [](Node &N) { return N.call_end(); },
> + [](call_edge_iterator I) -> Node & {
> + // For SCCs, all the nodes should already be formed.
> + return *I->getNode();
> + },
> + [this, &RC](node_stack_range Nodes) {
> + RC.SCCs.push_back(createSCC(RC, Nodes));
> + for (Node &N : *RC.SCCs.back()) {
> + N.DFSNumber = N.LowLink = -1;
> + SCCMap[&N] = RC.SCCs.back();
> + }
> + });
>
> // Wire up the SCC indices.
> for (int i = 0, Size = RC.SCCs.size(); i < Size; ++i)
> RC.SCCIndices[RC.SCCs[i]] = i;
> }
>
> +void LazyCallGraph::buildRefSCCs() {
> + if (EntryEdges.empty() || !PostOrderRefSCCs.empty())
> + // RefSCCs are either non-existent or already built!
> + return;
> +
> + assert(RefSCCIndices.empty() && "Already mapped RefSCC indices!");
> +
> + SmallVector<Node *, 16> Roots;
> + for (Edge &E : *this)
> + Roots.push_back(&E.getNode(*this));
> +
> + // The roots will be popped of a stack, so use reverse to get a less
> + // surprising order. This doesn't change any of the semantics anywhere.
> + std::reverse(Roots.begin(), Roots.end());
> +
> + buildGenericSCCs(
> + Roots, [](Node &N) { return N.begin(); }, [](Node &N) { return
> N.end(); }, + [this](edge_iterator I) -> Node & {
> + // Form the node if we haven't yet.
> + return I->getNode(*this);
> + },
> + [this](node_stack_range Nodes) {
> + RefSCC *NewRC = createRefSCC(*this);
> + buildSCCs(*NewRC, Nodes);
> + connectRefSCC(*NewRC);
> +
> + // Push the new node into the postorder list and remember its
> position + // in the index map.
> + bool Inserted =
> + RefSCCIndices.insert({NewRC, PostOrderRefSCCs.size()}).second;
> + (void)Inserted;
> + assert(Inserted && "Cannot already have this RefSCC in the index
> map!"); + PostOrderRefSCCs.push_back(NewRC);
> + NewRC->verify();
> + });
> +}
> +
> // FIXME: We should move callers of this to embed the parent linking and
> leaf // tracking into their DFS in order to remove a full walk of all
> edges. void LazyCallGraph::connectRefSCC(RefSCC &RC) {
> @@ -1794,106 +1839,6 @@ void LazyCallGraph::connectRefSCC(RefSCC
> LeafRefSCCs.push_back(&RC);
> }
>
> -bool LazyCallGraph::buildNextRefSCCInPostOrder() {
> - if (DFSStack.empty()) {
> - Node *N;
> - do {
> - // If we've handled all candidate entry nodes to the SCC forest,
> we're - // done.
> - if (RefSCCEntryNodes.empty())
> - return false;
> -
> - N = &get(*RefSCCEntryNodes.pop_back_val());
> - } while (N->DFSNumber != 0);
> -
> - // Found a new root, begin the DFS here.
> - N->LowLink = N->DFSNumber = 1;
> - NextDFSNumber = 2;
> - DFSStack.push_back({N, N->begin()});
> - }
> -
> - for (;;) {
> - Node *N;
> - edge_iterator I;
> - std::tie(N, I) = DFSStack.pop_back_val();
> -
> - assert(N->DFSNumber > 0 && "We should always assign a DFS number "
> - "before placing a node onto the stack.");
> -
> - auto E = N->end();
> - while (I != E) {
> - Node &ChildN = I->getNode(*this);
> - if (ChildN.DFSNumber == 0) {
> - // We haven't yet visited this child, so descend, pushing the
> current - // node onto the stack.
> - DFSStack.push_back({N, N->begin()});
> -
> - assert(!SCCMap.count(&ChildN) &&
> - "Found a node with 0 DFS number but already in an SCC!");
> - ChildN.LowLink = ChildN.DFSNumber = NextDFSNumber++;
> - N = &ChildN;
> - I = N->begin();
> - E = N->end();
> - continue;
> - }
> -
> - // If the child has already been added to some child component, it
> - // couldn't impact the low-link of this parent because it isn't
> - // connected, and thus its low-link isn't relevant so skip it.
> - if (ChildN.DFSNumber == -1) {
> - ++I;
> - continue;
> - }
> -
> - // Track the lowest linked child as the lowest link for this node.
> - assert(ChildN.LowLink > 0 && "Must have a positive low-link
> number!"); - if (ChildN.LowLink < N->LowLink)
> - N->LowLink = ChildN.LowLink;
> -
> - // Move to the next edge.
> - ++I;
> - }
> -
> - // We've finished processing N and its descendents, put it on our
> pending - // SCC stack to eventually get merged into an SCC of nodes.
> - PendingRefSCCStack.push_back(N);
> -
> - // If this node is linked to some lower entry, continue walking up the
> - // stack.
> - if (N->LowLink != N->DFSNumber) {
> - assert(!DFSStack.empty() &&
> - "We never found a viable root for an SCC to pop off!");
> - continue;
> - }
> -
> - // Otherwise, form a new RefSCC from the top of the pending node stack.
> - int RootDFSNumber = N->DFSNumber;
> - // Find the range of the node stack by walking down until we pass the
> - // root DFS number.
> - auto RefSCCNodes = node_stack_range(
> - PendingRefSCCStack.rbegin(),
> - find_if(reverse(PendingRefSCCStack), [RootDFSNumber](const Node *N)
> { - return N->DFSNumber < RootDFSNumber;
> - }));
> - // Form a new RefSCC out of these nodes and then clear them off our
> pending - // stack.
> - RefSCC *NewRC = createRefSCC(*this);
> - buildSCCs(*NewRC, RefSCCNodes);
> - connectRefSCC(*NewRC);
> - PendingRefSCCStack.erase(RefSCCNodes.end().base(),
> - PendingRefSCCStack.end());
> -
> - // Push the new node into the postorder list and return true indicating
> we - // successfully grew the postorder sequence by one.
> - bool Inserted =
> - RefSCCIndices.insert({NewRC, PostOrderRefSCCs.size()}).second;
> - (void)Inserted;
> - assert(Inserted && "Cannot already have this RefSCC in the index
> map!"); - PostOrderRefSCCs.push_back(NewRC);
> - return true;
> - }
> -}
> -
> AnalysisKey LazyCallGraphAnalysis::Key;
>
> LazyCallGraphPrinterPass::LazyCallGraphPrinterPass(raw_ostream &OS) :
> OS(OS) {} @@ -1935,6 +1880,7 @@ PreservedAnalyses LazyCallGraphPrinterPa
> for (Function &F : M)
> printNode(OS, G.get(F));
>
> + G.buildRefSCCs();
> for (LazyCallGraph::RefSCC &C : G.postorder_ref_sccs())
> printRefSCC(OS, C);
>
>
> Modified: llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/LazyCallG
> raphTest.cpp?rev=294227&r1=294226&r2=294227&view=diff
> ===========================================================================
> === --- llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp (original) +++
> llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp Mon Feb 6 13:38:06
> 2017 @@ -300,6 +300,7 @@ TEST(LazyCallGraphTest, BasicGraphFormat
> EXPECT_EQ("d1", D3.begin()->getFunction().getName());
>
> // Now lets look at the RefSCCs and SCCs.
> + CG.buildRefSCCs();
> auto J = CG.postorder_ref_scc_begin();
>
> LazyCallGraph::RefSCC &D = *J++;
> @@ -444,6 +445,7 @@ TEST(LazyCallGraphTest, InnerSCCFormatio
> std::vector<std::string> Nodes;
>
> // We should build a single RefSCC for the entire graph.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -528,6 +530,7 @@ TEST(LazyCallGraphTest, MultiArmSCC) {
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -578,6 +581,7 @@ TEST(LazyCallGraphTest, OutgoingEdgeMuta
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
> dbgs() << "Formed RefSCC: " << RC << "\n";
>
> @@ -723,6 +727,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInse
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
> dbgs() << "Formed RefSCC: " << RC << "\n";
>
> @@ -805,102 +810,6 @@ TEST(LazyCallGraphTest, IncomingEdgeInse
> EXPECT_EQ(++I, E);
> }
>
> -TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) {
> - LLVMContext Context;
> - // This is the same fundamental test as the previous, but we perform it
> - // having only partially walked the RefSCCs of the graph.
> - std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
> - LazyCallGraph CG(*M);
> -
> - // Walk the RefSCCs until we find the one containing 'c1'.
> - auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
> - ASSERT_NE(I, E);
> - LazyCallGraph::RefSCC &DRC = *I;
> - ASSERT_NE(&DRC, nullptr);
> - ++I;
> - ASSERT_NE(I, E);
> - LazyCallGraph::RefSCC &CRC = *I;
> - ASSERT_NE(&CRC, nullptr);
> -
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a1")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a2")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a3")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b1")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b2")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b3")));
> - LazyCallGraph::Node &C1 = *CG.lookup(lookupFunction(*M, "c1"));
> - LazyCallGraph::Node &C2 = *CG.lookup(lookupFunction(*M, "c2"));
> - LazyCallGraph::Node &C3 = *CG.lookup(lookupFunction(*M, "c3"));
> - LazyCallGraph::Node &D1 = *CG.lookup(lookupFunction(*M, "d1"));
> - LazyCallGraph::Node &D2 = *CG.lookup(lookupFunction(*M, "d2"));
> - LazyCallGraph::Node &D3 = *CG.lookup(lookupFunction(*M, "d3"));
> - ASSERT_EQ(&CRC, CG.lookupRefSCC(C1));
> - ASSERT_EQ(&CRC, CG.lookupRefSCC(C2));
> - ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
> - ASSERT_EQ(&DRC, CG.lookupRefSCC(D1));
> - ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
> - ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
> - ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
> -
> - auto MergedRCs = CRC.insertIncomingRefEdge(D2, C2);
> - // Make sure we connected the nodes.
> - for (LazyCallGraph::Edge E : D2) {
> - if (E.getNode() == &D3)
> - continue;
> - EXPECT_EQ(&C2, E.getNode());
> - }
> - // And marked the D ref-SCC as no longer valid.
> - EXPECT_EQ(1u, MergedRCs.size());
> - EXPECT_EQ(&DRC, MergedRCs[0]);
> -
> - // Make sure we have the correct nodes in the RefSCCs.
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(C1));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(C2));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(C3));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(D1));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(D2));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(D3));
> -
> - // Verify that the post-order walk reflects the updated but still
> incomplete - // structure.
> - auto J = CG.postorder_ref_scc_begin();
> - EXPECT_NE(J, E);
> - EXPECT_EQ(&CRC, &*J) << "Actual RefSCC: " << *J;
> - EXPECT_EQ(I, J);
> -
> - // Check that we can form the last two RefSCCs now, and even that we can
> do - // it with alternating iterators.
> - ++J;
> - EXPECT_NE(J, E);
> - LazyCallGraph::RefSCC &BRC = *J;
> - EXPECT_NE(&BRC, nullptr);
> - EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b1"))));
> - EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b2"))));
> - EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b3"))));
> - EXPECT_TRUE(BRC.isParentOf(CRC));
> - ++I;
> - EXPECT_EQ(J, I);
> - EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
> -
> - // Increment I this time to form the new RefSCC, flopping back to the
> first - // iterator.
> - ++I;
> - EXPECT_NE(I, E);
> - LazyCallGraph::RefSCC &ARC = *I;
> - EXPECT_NE(&ARC, nullptr);
> - EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a1"))));
> - EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a2"))));
> - EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a3"))));
> - EXPECT_TRUE(ARC.isParentOf(CRC));
> - ++J;
> - EXPECT_EQ(I, J);
> - EXPECT_EQ(&ARC, &*J) << "Actual RefSCC: " << *J;
> - ++I;
> - EXPECT_EQ(E, I);
> - ++J;
> - EXPECT_EQ(E, J);
> -}
> -
> TEST(LazyCallGraphTest, IncomingEdgeInsertionRefGraph) {
> LLVMContext Context;
> // Another variation of the above test but with all the edges switched to
> @@ -910,6 +819,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInse
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
> dbgs() << "Formed RefSCC: " << RC << "\n";
>
> @@ -1016,6 +926,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInse
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
> dbgs() << "Formed RefSCC: " << RC << "\n";
>
> @@ -1092,6 +1003,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInse
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
> dbgs() << "Formed RefSCC: " << RC << "\n";
>
> @@ -1153,6 +1065,7 @@ TEST(LazyCallGraphTest, InlineAndDeleteF
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
> dbgs() << "Formed RefSCC: " << RC << "\n";
>
> @@ -1276,177 +1189,6 @@ TEST(LazyCallGraphTest, InlineAndDeleteF
> EXPECT_EQ(++I, E);
> }
>
> -TEST(LazyCallGraphTest, InlineAndDeleteFunctionMidTraversal) {
> - LLVMContext Context;
> - // This is the same fundamental test as the previous, but we perform it
> - // having only partially walked the RefSCCs of the graph.
> - //
> - // The ascii diagram is repeated here for easy reference.
> - //
> - // d1 |
> - // / \ |
> - // d3--d2 |
> - // / \ |
> - // b1 c1 |
> - // / \ / \ |
> - // b3--b2 c3--c2 |
> - // \ / |
> - // a1 |
> - // / \ |
> - // a3--a2 |
> - //
> - std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
> - LazyCallGraph CG(*M);
> -
> - // Walk the RefSCCs until we find the one containing 'c1'.
> - auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
> - ASSERT_NE(I, E);
> - LazyCallGraph::RefSCC &DRC = *I;
> - ASSERT_NE(&DRC, nullptr);
> - ++I;
> - ASSERT_NE(I, E);
> - LazyCallGraph::RefSCC &CRC = *I;
> - ASSERT_NE(&CRC, nullptr);
> -
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a1")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a2")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a3")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b1")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b2")));
> - ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b3")));
> - LazyCallGraph::Node &C1 = *CG.lookup(lookupFunction(*M, "c1"));
> - LazyCallGraph::Node &C2 = *CG.lookup(lookupFunction(*M, "c2"));
> - LazyCallGraph::Node &C3 = *CG.lookup(lookupFunction(*M, "c3"));
> - LazyCallGraph::Node &D1 = *CG.lookup(lookupFunction(*M, "d1"));
> - LazyCallGraph::Node &D2 = *CG.lookup(lookupFunction(*M, "d2"));
> - LazyCallGraph::Node &D3 = *CG.lookup(lookupFunction(*M, "d3"));
> - ASSERT_EQ(&CRC, CG.lookupRefSCC(C1));
> - ASSERT_EQ(&CRC, CG.lookupRefSCC(C2));
> - ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
> - ASSERT_EQ(&DRC, CG.lookupRefSCC(D1));
> - ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
> - ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
> - ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
> -
> - // Delete d2 from the graph, as if it had been inlined.
> - //
> - // d1 |
> - // / / |
> - // d3--. |
> - // / \ |
> - // b1 c1 |
> - // / \ / \ |
> - // b3--b2 c3--c2 |
> - // \ / |
> - // a1 |
> - // / \ |
> - // a3--a2 |
> -
> - Function &D2F = D2.getFunction();
> - CallInst *C1Call = nullptr, *D1Call = nullptr;
> - for (User *U : D2F.users()) {
> - CallInst *CI = dyn_cast<CallInst>(U);
> - ASSERT_TRUE(CI) << "Expected a call: " << *U;
> - if (CI->getParent()->getParent() == &C1.getFunction()) {
> - ASSERT_EQ(nullptr, C1Call) << "Found too many C1 calls: " << *CI;
> - C1Call = CI;
> - } else if (CI->getParent()->getParent() == &D1.getFunction()) {
> - ASSERT_EQ(nullptr, D1Call) << "Found too many D1 calls: " << *CI;
> - D1Call = CI;
> - } else {
> - FAIL() << "Found an unexpected call instruction: " << *CI;
> - }
> - }
> - ASSERT_NE(C1Call, nullptr);
> - ASSERT_NE(D1Call, nullptr);
> - ASSERT_EQ(&D2F, C1Call->getCalledFunction());
> - ASSERT_EQ(&D2F, D1Call->getCalledFunction());
> - C1Call->setCalledFunction(&D3.getFunction());
> - D1Call->setCalledFunction(&D3.getFunction());
> - ASSERT_EQ(0u, D2F.getNumUses());
> -
> - // Insert new edges first.
> - CRC.insertTrivialCallEdge(C1, D3);
> - DRC.insertTrivialCallEdge(D1, D3);
> -
> - // Then remove the old ones.
> - LazyCallGraph::SCC &DC = *CG.lookupSCC(D2);
> - auto NewCs = DRC.switchInternalEdgeToRef(D1, D2);
> - EXPECT_EQ(&DC, CG.lookupSCC(D2));
> - EXPECT_EQ(NewCs.end(), std::next(NewCs.begin()));
> - LazyCallGraph::SCC &NewDC = *NewCs.begin();
> - EXPECT_EQ(&NewDC, CG.lookupSCC(D1));
> - EXPECT_EQ(&NewDC, CG.lookupSCC(D3));
> - auto NewRCs = DRC.removeInternalRefEdge(D1, D2);
> - EXPECT_EQ(&DRC, CG.lookupRefSCC(D2));
> - EXPECT_EQ(NewRCs.end(), std::next(NewRCs.begin()));
> - LazyCallGraph::RefSCC &NewDRC = **NewRCs.begin();
> - EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D1));
> - EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D3));
> - EXPECT_FALSE(NewDRC.isParentOf(DRC));
> - EXPECT_TRUE(CRC.isParentOf(DRC));
> - EXPECT_TRUE(CRC.isParentOf(NewDRC));
> - EXPECT_TRUE(DRC.isParentOf(NewDRC));
> - CRC.removeOutgoingEdge(C1, D2);
> - EXPECT_FALSE(CRC.isParentOf(DRC));
> - EXPECT_TRUE(CRC.isParentOf(NewDRC));
> - EXPECT_TRUE(DRC.isParentOf(NewDRC));
> -
> - // Now that we've updated the call graph, D2 is dead, so remove it.
> - CG.removeDeadFunction(D2F);
> -
> - // Check that the graph still looks the same.
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(C1));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(C2));
> - EXPECT_EQ(&CRC, CG.lookupRefSCC(C3));
> - EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D1));
> - EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D3));
> - EXPECT_TRUE(CRC.isParentOf(NewDRC));
> -
> - // Verify that the post-order walk reflects the updated but still
> incomplete - // structure.
> - auto J = CG.postorder_ref_scc_begin();
> - EXPECT_NE(J, E);
> - EXPECT_EQ(&NewDRC, &*J) << "Actual RefSCC: " << *J;
> - ++J;
> - EXPECT_NE(J, E);
> - EXPECT_EQ(&CRC, &*J) << "Actual RefSCC: " << *J;
> - EXPECT_EQ(I, J);
> -
> - // Check that we can form the last two RefSCCs now, and even that we can
> do - // it with alternating iterators.
> - ++J;
> - EXPECT_NE(J, E);
> - LazyCallGraph::RefSCC &BRC = *J;
> - EXPECT_NE(&BRC, nullptr);
> - EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b1"))));
> - EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b2"))));
> - EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b3"))));
> - EXPECT_TRUE(BRC.isParentOf(NewDRC));
> - ++I;
> - EXPECT_EQ(J, I);
> - EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
> -
> - // Increment I this time to form the new RefSCC, flopping back to the
> first - // iterator.
> - ++I;
> - EXPECT_NE(I, E);
> - LazyCallGraph::RefSCC &ARC = *I;
> - EXPECT_NE(&ARC, nullptr);
> - EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a1"))));
> - EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a2"))));
> - EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a3"))));
> - EXPECT_TRUE(ARC.isParentOf(BRC));
> - EXPECT_TRUE(ARC.isParentOf(CRC));
> - ++J;
> - EXPECT_EQ(I, J);
> - EXPECT_EQ(&ARC, &*J) << "Actual RefSCC: " << *J;
> - ++I;
> - EXPECT_EQ(E, I);
> - ++J;
> - EXPECT_EQ(E, J);
> -}
> -
> TEST(LazyCallGraphTest, InternalEdgeMutation) {
> LLVMContext Context;
> std::unique_ptr<Module> M = parseAssembly(Context, "define void @a() {\n"
> @@ -1467,6 +1209,7 @@ TEST(LazyCallGraphTest, InternalEdgeMuta
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -1559,6 +1302,7 @@ TEST(LazyCallGraphTest, InternalEdgeRemo
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
> LazyCallGraph::RefSCC &RC = *I;
> EXPECT_EQ(E, std::next(I));
> @@ -1633,6 +1377,7 @@ TEST(LazyCallGraphTest, InternalNoOpEdge
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
> LazyCallGraph::RefSCC &RC = *I;
> EXPECT_EQ(E, std::next(I));
> @@ -1709,6 +1454,7 @@ TEST(LazyCallGraphTest, InternalCallEdge
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -1801,6 +1547,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeT
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -1913,6 +1660,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeT
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -2043,6 +1791,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeT
> LazyCallGraph CG(*M);
>
> // Force the graph to be fully expanded.
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &RC = *I++;
> EXPECT_EQ(CG.postorder_ref_scc_end(), I);
> @@ -2122,6 +1871,7 @@ TEST(LazyCallGraphTest, HandleBlockAddre
> "}\n");
> LazyCallGraph CG(*M);
>
> + CG.buildRefSCCs();
> auto I = CG.postorder_ref_scc_begin();
> LazyCallGraph::RefSCC &FRC = *I++;
> LazyCallGraph::RefSCC &GRC = *I++;
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
--
Laurent Carlier
http://www.archlinux.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170206/453a6c75/attachment.sig>
More information about the llvm-commits
mailing list