//===--- 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 namespace swift { class CallGraphNode; class CallGraphEdge { public: typedef llvm::DenseSet 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 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(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 Callers; /// The call sites within this function. This CallGraph node owns these. llvm::SmallVector 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 &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; /// 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 &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 &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 SCCNodes; }; class CallGraph { llvm::SmallVector CallGraphRoots; llvm::DenseMap FunctionToNodeMap; llvm::SmallVector BottomUpSCCOrder; std::vector BottomUpFunctionOrder; public: CallGraph(SILModule *M, bool completeModule); ~CallGraph() { for (auto &MapEntry : FunctionToNodeMap) delete MapEntry.second; for (auto *SCC : BottomUpSCCOrder) delete SCC; } llvm::SmallVectorImpl &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 &getBottomUpSCCOrder() { if (BottomUpSCCOrder.empty()) computeBottomUpSCCOrder(); return BottomUpSCCOrder; } std::vector &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 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