diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/lib/Analysis/CallGraphSCCPass.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'llvm/lib/Analysis/CallGraphSCCPass.cpp')
-rw-r--r-- | llvm/lib/Analysis/CallGraphSCCPass.cpp | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/llvm/lib/Analysis/CallGraphSCCPass.cpp b/llvm/lib/Analysis/CallGraphSCCPass.cpp index 196ef400bc4e6..91f8029cc326b 100644 --- a/llvm/lib/Analysis/CallGraphSCCPass.cpp +++ b/llvm/lib/Analysis/CallGraphSCCPass.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/AbstractCallSite.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/Intrinsics.h" @@ -225,22 +226,51 @@ bool CGPassManager::RefreshCallGraph(const CallGraphSCC &CurSCC, CallGraph &CG, // invalidated and removed. unsigned NumDirectRemoved = 0, NumIndirectRemoved = 0; + CallGraphNode::iterator CGNEnd = CGN->end(); + + auto RemoveAndCheckForDone = [&](CallGraphNode::iterator I) { + // Just remove the edge from the set of callees, keep track of whether + // I points to the last element of the vector. + bool WasLast = I + 1 == CGNEnd; + CGN->removeCallEdge(I); + + // If I pointed to the last element of the vector, we have to bail out: + // iterator checking rejects comparisons of the resultant pointer with + // end. + if (WasLast) + return true; + + CGNEnd = CGN->end(); + return false; + }; + // Get the set of call sites currently in the function. - for (CallGraphNode::iterator I = CGN->begin(), E = CGN->end(); I != E; ) { + for (CallGraphNode::iterator I = CGN->begin(); I != CGNEnd;) { + // Delete "reference" call records that do not have call instruction. We + // reinsert them as needed later. However, keep them in checking mode. + if (!I->first) { + if (CheckingMode) { + ++I; + continue; + } + if (RemoveAndCheckForDone(I)) + break; + continue; + } + // If this call site is null, then the function pass deleted the call // entirely and the WeakTrackingVH nulled it out. - auto *Call = dyn_cast_or_null<CallBase>(I->first); - if (!I->first || + auto *Call = dyn_cast_or_null<CallBase>(*I->first); + if (!Call || // If we've already seen this call site, then the FunctionPass RAUW'd // one call with another, which resulted in two "uses" in the edge // list of the same call. - Calls.count(I->first) || + Calls.count(Call) || // If the call edge is not from a call or invoke, or it is a // instrinsic call, then the function pass RAUW'd a call with // another value. This can happen when constant folding happens // of well known functions etc. - !Call || (Call->getCalledFunction() && Call->getCalledFunction()->isIntrinsic() && Intrinsic::isLeaf(Call->getCalledFunction()->getIntrinsicID()))) { @@ -253,28 +283,18 @@ bool CGPassManager::RefreshCallGraph(const CallGraphSCC &CurSCC, CallGraph &CG, else ++NumDirectRemoved; - // Just remove the edge from the set of callees, keep track of whether - // I points to the last element of the vector. - bool WasLast = I + 1 == E; - CGN->removeCallEdge(I); - - // If I pointed to the last element of the vector, we have to bail out: - // iterator checking rejects comparisons of the resultant pointer with - // end. - if (WasLast) + if (RemoveAndCheckForDone(I)) break; - E = CGN->end(); continue; } - assert(!Calls.count(I->first) && - "Call site occurs in node multiple times"); + assert(!Calls.count(Call) && "Call site occurs in node multiple times"); if (Call) { Function *Callee = Call->getCalledFunction(); // Ignore intrinsics because they're not really function calls. if (!Callee || !(Callee->isIntrinsic())) - Calls.insert(std::make_pair(I->first, I->second)); + Calls.insert(std::make_pair(Call, I->second)); } ++I; } @@ -292,6 +312,15 @@ bool CGPassManager::RefreshCallGraph(const CallGraphSCC &CurSCC, CallGraph &CG, if (Callee && Callee->isIntrinsic()) continue; + // If we are not in checking mode, insert potential callback calls as + // references. This is not a requirement but helps to iterate over the + // functions in the right order. + if (!CheckingMode) { + forEachCallbackFunction(*Call, [&](Function *CB) { + CGN->addCalledFunction(nullptr, CG.getOrInsertFunction(CB)); + }); + } + // If this call site already existed in the callgraph, just verify it // matches up to expectations and remove it from Calls. DenseMap<Value *, CallGraphNode *>::iterator ExistingIt = @@ -549,7 +578,10 @@ void CallGraphSCC::ReplaceNode(CallGraphNode *Old, CallGraphNode *New) { for (unsigned i = 0; ; ++i) { assert(i != Nodes.size() && "Node not in SCC"); if (Nodes[i] != Old) continue; - Nodes[i] = New; + if (New) + Nodes[i] = New; + else + Nodes.erase(Nodes.begin() + i); break; } @@ -559,6 +591,10 @@ void CallGraphSCC::ReplaceNode(CallGraphNode *Old, CallGraphNode *New) { CGI->ReplaceNode(Old, New); } +void CallGraphSCC::DeleteNode(CallGraphNode *Old) { + ReplaceNode(Old, /*New=*/nullptr); +} + //===----------------------------------------------------------------------===// // CallGraphSCCPass Implementation //===----------------------------------------------------------------------===// |