LazyCallGraph::LazyCallGraph(LazyCallGraph &&G)
: BPA(std::move(G.BPA)), NodeMap(std::move(G.NodeMap)),
EntryEdges(std::move(G.EntryEdges)), SCCBPA(std::move(G.SCCBPA)),
- SCCMap(std::move(G.SCCMap)), LeafRefSCCs(std::move(G.LeafRefSCCs)),
+ SCCMap(std::move(G.SCCMap)),
LibFunctions(std::move(G.LibFunctions)) {
updateGraphPtrs();
}
EntryEdges = std::move(G.EntryEdges);
SCCBPA = std::move(G.SCCBPA);
SCCMap = std::move(G.SCCMap);
- LeafRefSCCs = std::move(G.LeafRefSCCs);
LibFunctions = std::move(G.LibFunctions);
updateGraphPtrs();
return *this;
"Edge between SCCs violates post-order relationship.");
continue;
}
- assert(TargetSCC.getOuterRefSCC().Parents.count(this) &&
- "Edge to a RefSCC missing us in its parent set.");
}
}
-
- // Check that our parents are actually parents.
- for (RefSCC *ParentRC : Parents) {
- assert(ParentRC != this && "Cannot be our own parent!");
- auto HasConnectingEdge = [&] {
- for (SCC &C : *ParentRC)
- for (Node &N : C)
- for (Edge &E : *N)
- if (G->lookupRefSCC(E.getNode()) == this)
- return true;
- return false;
- };
- assert(HasConnectingEdge() && "No edge connects the parent to us!");
- }
}
#endif
"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.
- TargetC.Parents.insert(this);
-
#ifndef NDEBUG
// Check that the RefSCC is still valid.
verify();
assert(RC != this && "We're merging into the target RefSCC, so it "
"shouldn't be in the range.");
- // Merge the parents which aren't part of the merge into the our parents.
- for (RefSCC *ParentRC : RC->Parents)
- if (!MergeSet.count(ParentRC))
- Parents.insert(ParentRC);
- RC->Parents.clear();
-
// Walk the inner SCCs to update their up-pointer and walk all the edges to
// update any parent sets.
// FIXME: We should try to find a way to avoid this (rather expensive) edge
for (SCC &InnerC : *RC) {
InnerC.OuterRefSCC = this;
SCCIndices[&InnerC] = SCCIndex++;
- for (Node &N : InnerC) {
+ for (Node &N : InnerC)
G->SCCMap[&N] = &InnerC;
- for (Edge &E : *N) {
- RefSCC &ChildRC = *G->lookupRefSCC(E.getNode());
- if (MergeSet.count(&ChildRC))
- continue;
- ChildRC.Parents.erase(RC);
- ChildRC.Parents.insert(this);
- }
- }
}
// Now merge in the SCCs. We can actually move here so try to reuse storage
RefSCC &TargetRC = *G->lookupRefSCC(TargetN);
assert(&TargetRC != this && "The target must not be a member of this RefSCC");
- assert(!is_contained(G->LeafRefSCCs, this) &&
- "Cannot have a leaf RefSCC source.");
-
#ifndef NDEBUG
// In a debug build, verify the RefSCC is valid to start with and when this
// routine finishes.
bool Removed = SourceN->removeEdgeInternal(TargetN);
(void)Removed;
assert(Removed && "Target not in the edge set for this caller?");
-
- bool HasOtherEdgeToChildRC = false;
- bool HasOtherChildRC = false;
- for (SCC *InnerC : SCCs) {
- for (Node &N : *InnerC) {
- for (Edge &E : *N) {
- RefSCC &OtherChildRC = *G->lookupRefSCC(E.getNode());
- if (&OtherChildRC == &TargetRC) {
- HasOtherEdgeToChildRC = true;
- break;
- }
- if (&OtherChildRC != this)
- HasOtherChildRC = true;
- }
- if (HasOtherEdgeToChildRC)
- break;
- }
- if (HasOtherEdgeToChildRC)
- break;
- }
- // Because the SCCs form a DAG, deleting such an edge cannot change the set
- // of SCCs in the graph. However, it may cut an edge of the SCC DAG, making
- // the source SCC no longer connected to the target SCC. If so, we need to
- // update the target SCC's map of its parents.
- if (!HasOtherEdgeToChildRC) {
- bool Removed = TargetRC.Parents.erase(this);
- (void)Removed;
- assert(Removed &&
- "Did not find the source SCC in the target SCC's parent list!");
-
- // It may orphan an SCC if it is the last edge reaching it, but that does
- // not violate any invariants of the graph.
- if (TargetRC.Parents.empty())
- DEBUG(dbgs() << "LCG: Update removing " << SourceN.getFunction().getName()
- << " -> " << TargetN.getFunction().getName()
- << " edge orphaned the callee's SCC!\n");
-
- // It may make the Source SCC a leaf SCC.
- if (!HasOtherChildRC)
- G->LeafRefSCCs.push_back(this);
- }
}
SmallVector<LazyCallGraph::RefSCC *, 1>
}
// If this child isn't currently in this RefSCC, no need to process
- // it. However, we do need to remove this RefSCC from its RefSCC's
- // parent set.
- RefSCC &ChildRC = *G->lookupRefSCC(ChildN);
- ChildRC.Parents.erase(this);
+ // it.
++I;
continue;
}
C->OuterRefSCC = &RC;
}
- // FIXME: We re-walk the edges in each RefSCC to establish whether it is
- // a leaf and connect it to the rest of the graph's parents lists. This is
- // really wasteful. We should instead do this during the DFS to avoid yet
- // another edge walk.
- for (RefSCC *RC : Result)
- G->connectRefSCC(*RC);
-
// Now erase all but the root's SCCs.
SCCs.erase(remove_if(SCCs,
[&](SCC *C) {
SCCIndices[SCCs[i]] = i;
#ifndef NDEBUG
- // Now we need to reconnect the current (root) SCC to the graph. We do this
- // manually because we can special case our leaf handling and detect errors.
- bool IsLeaf = true;
-#endif
- for (SCC *C : SCCs)
- for (Node &N : *C) {
- for (Edge &E : *N) {
- RefSCC &ChildRC = *G->lookupRefSCC(E.getNode());
- if (&ChildRC == this)
- continue;
- ChildRC.Parents.insert(this);
-#ifndef NDEBUG
- IsLeaf = false;
-#endif
- }
- }
-#ifndef NDEBUG
- if (!Result.empty())
- assert(!IsLeaf && "This SCC cannot be a leaf as we have split out new "
- "SCCs by removing this edge.");
- if (none_of(G->LeafRefSCCs, [&](RefSCC *C) { return C == this; }))
- 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)
- for (Node &ParentN : ParentC)
- for (Edge &E : *ParentN) {
- RefSCC &RC = *G->lookupRefSCC(E.getNode());
- if (&RC != ParentRC)
- 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.
- // FIXME: As LeafRefSCCs could be very large, we might want to not walk the
- // entire list if this RefSCC wasn't a leaf before the edge removal.
- if (!Result.empty())
- G->LeafRefSCCs.erase(
- std::remove(G->LeafRefSCCs.begin(), G->LeafRefSCCs.end(), this),
- G->LeafRefSCCs.end());
-
-#ifndef NDEBUG
// Verify all of the new RefSCCs.
for (RefSCC *RC : Result)
RC->verify();
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);
}
void LazyCallGraph::RefSCC::insertTrivialCallEdge(Node &SourceN,
assert(C.size() == 1 && "Dead functions must be in a singular SCC");
assert(RC.size() == 1 && "Dead functions must be in a singular RefSCC");
- // Now remove this RefSCC from any parents sets and the leaf list.
- for (Edge &E : *N)
- if (RefSCC *TargetRC = lookupRefSCC(E.getNode()))
- 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);
[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.
});
}
-// 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) {
- // Walk all edges in the RefSCC (this remains linear as we only do this once
- // when we build the RefSCC) to connect it to the parent sets of its
- // children.
- bool IsLeaf = true;
- for (SCC &C : RC)
- for (Node &N : C)
- for (Edge &E : *N) {
- RefSCC &ChildRC = *lookupRefSCC(E.getNode());
- if (&ChildRC == &RC)
- continue;
- ChildRC.Parents.insert(&RC);
- IsLeaf = false;
- }
-
- // For the SCCs where we find no child SCCs, add them to the leaf list.
- if (IsLeaf)
- LeafRefSCCs.push_back(&RC);
-}
-
AnalysisKey LazyCallGraphAnalysis::Key;
LazyCallGraphPrinterPass::LazyCallGraphPrinterPass(raw_ostream &OS) : OS(OS) {}