mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
302 lines
9.2 KiB
C++
302 lines
9.2 KiB
C++
//===--- CallGraphAnalysis.h - Analysis of the Call Graph ------*- C++ -*--===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILANALYSIS_CALLGRAPHANALYSIS_H
|
|
#define SWIFT_SILANALYSIS_CALLGRAPHANALYSIS_H
|
|
|
|
#include "swift/SILAnalysis/Analysis.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/SIL/CFG.h"
|
|
#include "swift/SIL/SILBasicBlock.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include <vector>
|
|
|
|
namespace swift {
|
|
class CallGraphNode;
|
|
|
|
class CallGraphEdge {
|
|
public:
|
|
typedef llvm::DenseSet<CallGraphNode *> CalleeSetType;
|
|
|
|
private:
|
|
// The call site represented by this call graph edge.
|
|
ApplyInst *CallSite;
|
|
|
|
// The set of functions potentially called from this call site. This
|
|
// might include functions that are not actually callable based on
|
|
// dynamic types. If the int bit is non-zero, the set is complete in
|
|
// the sense that no function outside the set could be called.
|
|
llvm::PointerIntPair<CalleeSetType *, 1> CalleeSet;
|
|
|
|
public:
|
|
/// Create a call graph edge for a call site where we will fill in
|
|
/// the set of potentially called functions later.
|
|
CallGraphEdge(ApplyInst *CallSite) : CallSite(CallSite),
|
|
CalleeSet(new CalleeSetType, 0) {
|
|
// TODO: We will probably have many call sites that can share a
|
|
// callee set so we should optimize allocation and
|
|
// deallocation of these accordingly.
|
|
}
|
|
|
|
/// Create a call graph edge for a call site that is known to have
|
|
/// only a single callee.
|
|
CallGraphEdge(ApplyInst *CallSite, CallGraphNode *Node)
|
|
: CallSite(CallSite),
|
|
// FIXME: Do not allocate memory for the singleton callee case.
|
|
CalleeSet(new CalleeSetType, 0) {
|
|
addCallee(Node);
|
|
markCalleeSetComplete();
|
|
}
|
|
|
|
~CallGraphEdge() {
|
|
delete CalleeSet.getPointer();
|
|
}
|
|
|
|
const ApplyInst *getCallSite() const {
|
|
return CallSite;
|
|
}
|
|
|
|
/// Return a callee set that is known to be complete.
|
|
const CalleeSetType &getCalleeSet() const {
|
|
assert(isCalleeSetComplete() && "Attempt to get an incomplete call set!");
|
|
return *CalleeSet.getPointer();
|
|
}
|
|
|
|
/// Return a callee set that is not known to be complete.
|
|
const CalleeSetType &getKnownCalleeSet() {
|
|
return *CalleeSet.getPointer();
|
|
}
|
|
|
|
/// Add the given function to the set of functions that we could
|
|
/// call from this call site.
|
|
void addCallee(CallGraphNode *Node) {
|
|
assert(!isCalleeSetComplete() &&
|
|
"Attempting to add another callee to a complete call set!");
|
|
CalleeSet.getPointer()->insert(Node);
|
|
}
|
|
|
|
/// Return whether the call set is known to be complete.
|
|
bool isCalleeSetComplete() const {
|
|
return CalleeSet.getInt();
|
|
}
|
|
|
|
private:
|
|
/// Mark the call set as being complete.
|
|
void markCalleeSetComplete() {
|
|
CalleeSet.setInt(1);
|
|
}
|
|
};
|
|
|
|
/// A helper method for use with ArrayRefView. Just returns the CallSite
|
|
/// ApplyInst of E.
|
|
inline ApplyInst *getEdgeApplyInst(CallGraphEdge * const &E) {
|
|
return const_cast<ApplyInst *>(E->getCallSite());
|
|
}
|
|
|
|
class CallGraphNode {
|
|
/// The function represented by this call graph node.
|
|
SILFunction *Function;
|
|
|
|
/// The call graph node ordinal within the SILModule.
|
|
const unsigned Ordinal;
|
|
|
|
/// The known call sites that call into this function. The
|
|
/// caller's call graph node owns these.
|
|
llvm::SmallVector<CallGraphEdge *, 4> Callers;
|
|
|
|
/// The call sites within this function. This CallGraph node owns these.
|
|
llvm::SmallVector<CallGraphEdge *, 4> CallSites;
|
|
|
|
/// Do we know all the potential callers of this function?
|
|
bool CallerSetComplete;
|
|
|
|
public:
|
|
friend class CallGraph;
|
|
|
|
CallGraphNode(SILFunction *Function, unsigned Ordinal) : Function(Function),
|
|
Ordinal(Ordinal),
|
|
CallerSetComplete(false) {
|
|
assert(Function &&
|
|
"Cannot build a call graph node with a null function pointer!");
|
|
}
|
|
|
|
~CallGraphNode() {
|
|
for (auto *CallSite : getCallSites())
|
|
delete CallSite;
|
|
}
|
|
|
|
SILFunction *getFunction() {
|
|
return Function;
|
|
}
|
|
|
|
/// Get the complete set of edges associated with call sites that can call
|
|
/// into this function.
|
|
const llvm::SmallVectorImpl<CallGraphEdge *> &getCallers() const {
|
|
assert(isCallerSetComplete() &&
|
|
"Attempt to get an incomplete caller set!");
|
|
return Callers;
|
|
}
|
|
|
|
// An adaptor that is used to show all of the apply insts which call the
|
|
// SILFunction of this node.
|
|
using CallerCallSiteList = ArrayRefView<CallGraphEdge *, ApplyInst *,
|
|
getEdgeApplyInst>;
|
|
|
|
/// Return the set of apply insts that can call into this function.
|
|
CallerCallSiteList getCallerCallSites() const {
|
|
return CallerCallSiteList(getCallers());
|
|
}
|
|
|
|
/// Get the known set of call graph edges that represent calls into this
|
|
/// function.
|
|
llvm::SmallVectorImpl<CallGraphEdge *> &getKnownCallers() {
|
|
return Callers;
|
|
}
|
|
|
|
/// Return the known set of apply insts that can call into this function.
|
|
CallerCallSiteList getKnownCallerCallSites() {
|
|
return CallerCallSiteList(getKnownCallers());
|
|
}
|
|
|
|
/// Get the known set of call sites in this function.
|
|
llvm::SmallVectorImpl<CallGraphEdge *> &getCallSites() {
|
|
return CallSites;
|
|
}
|
|
|
|
/// Do we know that the set of call sites is complete - i.e. that
|
|
/// there is no other place that we can call from that can reach
|
|
/// this function?
|
|
bool isCallerSetComplete() const {
|
|
return CallerSetComplete;
|
|
}
|
|
|
|
unsigned getOrdinal() const {
|
|
return Ordinal;
|
|
}
|
|
|
|
private:
|
|
/// Mark a set of callers as known to be complete.
|
|
void markCallerSetComplete() {
|
|
assert(!isCallerSetComplete() &&
|
|
"The caller set should only be marked complete once!");
|
|
|
|
CallerSetComplete = true;
|
|
}
|
|
|
|
/// Add an edge representing a call site within this function.
|
|
void addCallSite(CallGraphEdge *CallSite) {
|
|
CallSites.push_back(CallSite);
|
|
}
|
|
|
|
/// Add an edge representing a call site that calls into this function.
|
|
void addCaller(CallGraphEdge *CallerCallSite) {
|
|
Callers.push_back(CallerCallSite);
|
|
}
|
|
};
|
|
|
|
struct CallGraphSCC {
|
|
llvm::SmallVector<CallGraphNode *, 1> SCCNodes;
|
|
};
|
|
|
|
class CallGraph {
|
|
llvm::SmallVector<CallGraphNode *, 16> CallGraphRoots;
|
|
llvm::DenseMap<SILFunction *, CallGraphNode *> FunctionToNodeMap;
|
|
llvm::SmallVector<CallGraphSCC *, 16> BottomUpSCCOrder;
|
|
std::vector<SILFunction *> BottomUpFunctionOrder;
|
|
|
|
public:
|
|
CallGraph(SILModule *M, bool completeModule);
|
|
|
|
~CallGraph() {
|
|
for (auto &MapEntry : FunctionToNodeMap)
|
|
delete MapEntry.second;
|
|
|
|
for (auto *SCC : BottomUpSCCOrder)
|
|
delete SCC;
|
|
}
|
|
|
|
llvm::SmallVectorImpl<CallGraphNode *> &getCallGraphRoots() {
|
|
return CallGraphRoots;
|
|
}
|
|
|
|
CallGraphNode *getCallGraphNode(SILFunction *F) {
|
|
auto Found = FunctionToNodeMap.find(F);
|
|
if (Found == FunctionToNodeMap.end())
|
|
return nullptr;
|
|
|
|
assert(Found->second && "Unexpected null call graph node in map!");
|
|
return Found->second;
|
|
}
|
|
|
|
llvm::SmallVectorImpl<CallGraphSCC *> &getBottomUpSCCOrder() {
|
|
if (BottomUpSCCOrder.empty())
|
|
computeBottomUpSCCOrder();
|
|
|
|
return BottomUpSCCOrder;
|
|
}
|
|
|
|
std::vector<SILFunction *> &getBottomUpFunctionOrder() {
|
|
if (BottomUpFunctionOrder.empty())
|
|
computeBottomUpFunctionOrder();
|
|
|
|
return BottomUpFunctionOrder;
|
|
}
|
|
|
|
private:
|
|
void addCallGraphNode(SILFunction *F, unsigned Ordinal);
|
|
void addEdges(SILFunction *F);
|
|
void addEdgesForApply(ApplyInst *AI, CallGraphNode *CallerNode);
|
|
void computeBottomUpSCCOrder();
|
|
void computeBottomUpFunctionOrder();
|
|
};
|
|
|
|
/// The Call Graph Analysis provides information about the call graph.
|
|
class CallGraphAnalysis : public SILAnalysis {
|
|
SILModule *M;
|
|
std::vector<SILFunction *> BottomUpFunctionOrder;
|
|
CallGraph *CG;
|
|
|
|
public:
|
|
virtual ~CallGraphAnalysis() {
|
|
delete CG;
|
|
}
|
|
CallGraphAnalysis(SILModule *MM) : SILAnalysis(AnalysisKind::CallGraph),
|
|
M(MM), CG(nullptr) {}
|
|
|
|
static bool classof(const SILAnalysis *S) {
|
|
return S->getKind() == AnalysisKind::CallGraph;
|
|
}
|
|
|
|
CallGraph &getCallGraph() {
|
|
if (!CG)
|
|
CG = new CallGraph(M, false);
|
|
|
|
return *CG;
|
|
}
|
|
|
|
virtual void invalidate(InvalidationKind K) {
|
|
if (K >= InvalidationKind::CallGraph) {
|
|
BottomUpFunctionOrder.clear();
|
|
delete CG;
|
|
CG = nullptr;
|
|
}
|
|
}
|
|
|
|
virtual void invalidate(SILFunction*, InvalidationKind K) { invalidate(K); }
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|