summaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/CallGraphSCCPass.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/lib/Analysis/CallGraphSCCPass.cpp
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'llvm/lib/Analysis/CallGraphSCCPass.cpp')
-rw-r--r--llvm/lib/Analysis/CallGraphSCCPass.cpp74
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
//===----------------------------------------------------------------------===//