Separate the call graph implementation from its interface. This implements
authorChris Lattner <sabre@nondot.org>
Thu, 22 Dec 2005 06:07:52 +0000 (06:07 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 22 Dec 2005 06:07:52 +0000 (06:07 +0000)
the rough idea sketched out in http://nondot.org/sabre/LLVMNotes/CallGraphClass.txt,
allowing new spiffy implementations of the callgraph interface to be built.

Many thanks to Saem Ghani for contributing this!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24944 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/CallGraph.h
include/llvm/Analysis/LinkAllAnalyses.h
lib/Analysis/IPA/CallGraph.cpp

index fee5147761bec22ad700f229e48bf4caa9ca319a..4edb60235624efffb5fcf71e5f71c802572cd98e 100644 (file)
@@ -64,25 +64,13 @@ class CallGraphNode;
 //===----------------------------------------------------------------------===//
 // CallGraph class definition
 //
-class CallGraph : public ModulePass {
+class CallGraph {
+protected:
   Module *Mod;              // The module this call graph represents
 
   typedef std::map<const Function *, CallGraphNode *> FunctionMapTy;
   FunctionMapTy FunctionMap;    // Map from a function to its node
 
-  // Root is root of the call graph, or the external node if a 'main' function
-  // couldn't be found.
-  //
-  CallGraphNode *Root;
-
-  // ExternalCallingNode - This node has edges to all external functions and
-  // those internal functions that have their address taken.
-  CallGraphNode *ExternalCallingNode;
-
-  // CallsExternalNode - This node has edges to it from all functions making
-  // indirect calls or calling an external function.
-  CallGraphNode *CallsExternalNode;
-
 public:
   //===---------------------------------------------------------------------
   // Accessors...
@@ -90,15 +78,6 @@ public:
   typedef FunctionMapTy::iterator iterator;
   typedef FunctionMapTy::const_iterator const_iterator;
 
-  CallGraphNode *getExternalCallingNode() const { return ExternalCallingNode; }
-  CallGraphNode *getCallsExternalNode()   const { return CallsExternalNode; }
-
-  // getRoot - Return the root of the call graph, which is either main, or if
-  // main cannot be found, the external node.
-  //
-        CallGraphNode *getRoot()       { return Root; }
-  const CallGraphNode *getRoot() const { return Root; }
-
   /// getModule - Return the module the call graph corresponds to.
   ///
   Module &getModule() const { return *Mod; }
@@ -108,7 +87,6 @@ public:
   inline const_iterator begin() const { return FunctionMap.begin(); }
   inline const_iterator end()   const { return FunctionMap.end();   }
 
-
   // Subscripting operators, return the call graph node for the provided
   // function
   inline const CallGraphNode *operator[](const Function *F) const {
@@ -122,6 +100,16 @@ public:
     return I->second;
   }
 
+  //Returns the CallGraphNode which is used to represent undetermined calls 
+  // into the callgraph.  Override this if you want behavioural inheritance.
+  virtual CallGraphNode* getExternalCallingNode() const { return 0; }
+  
+  //Return the root/main method in the module, or some other root node, such
+  // as the externalcallingnode.  Overload these if you behavioural 
+  // inheritance.
+  virtual CallGraphNode* getRoot() { return 0; }
+  virtual const CallGraphNode* getRoot() const { return 0; }
+  
   //===---------------------------------------------------------------------
   // Functions to keep a call graph up to date with a function that has been
   // modified.
@@ -147,54 +135,27 @@ public:
   //===---------------------------------------------------------------------
   // Pass infrastructure interface glue code...
   //
-  CallGraph() : Root(0), CallsExternalNode(0) {}
-  ~CallGraph() { destroy(); }
-
-  // runOnModule - Compute the call graph for the specified module.
-  virtual bool runOnModule(Module &M);
-
-  // getAnalysisUsage - This obviously provides a call graph
-  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
-    AU.setPreservesAll();
-  }
-
-  // releaseMemory - Data structures can be large, so free memory aggressively.
-  virtual void releaseMemory() {
-    destroy();
-  }
+protected:
+  CallGraph() {}
+  
+public:
+  virtual ~CallGraph() { destroy(); }
 
-  /// Print the types found in the module.  If the optional Module parameter is
-  /// passed in, then the types are printed symbolically if possible, using the
-  /// symbol table from the module.
+  /// initialize - Call this method before calling other methods, 
+  /// re/initializes the state of the CallGraph.
   ///
-  void print(std::ostream &o, const Module *M) const;
+  void initialize(Module &M);
 
-  /// dump - Print out this call graph.
-  ///
-  void dump() const;
+  virtual void print(std::ostream &o, const Module *M) const;
 
   // stub - dummy function, just ignore it
   static void stub();
-private:
-  //===---------------------------------------------------------------------
-  // Implementation of CallGraph construction
-  //
-
-  // getNodeFor - Return the node for the specified function or create one if it
-  // does not already exist.
-  //
-  CallGraphNode *getNodeFor(Function *F);
-
-  // addToCallGraph - Add a function to the call graph, and link the node to all
-  // of the functions that it calls.
-  //
-  void addToCallGraph(Function *F);
+protected:
 
   // destroy - Release memory for the call graph
-  void destroy();
+  virtual void destroy();
 };
 
-
 //===----------------------------------------------------------------------===//
 // CallGraphNode class definition
 //
@@ -256,15 +217,12 @@ public:
   /// removeCallEdgeTo, so it should not be used unless necessary.
   void removeAnyCallEdgeTo(CallGraphNode *Callee);
 
-private:                    // Stuff to construct the node, used by CallGraph
   friend class CallGraph;
 
   // CallGraphNode ctor - Create a node for the specified function...
   inline CallGraphNode(Function *f) : F(f) {}
 };
 
-
-
 //===----------------------------------------------------------------------===//
 // GraphTraits specializations for call graphs so that they can be treated as
 // graphs by the generic graph algorithms...
@@ -311,6 +269,7 @@ template<> struct GraphTraits<CallGraph*> : public GraphTraits<CallGraphNode*> {
     return *P.second;
   }
 };
+
 template<> struct GraphTraits<const CallGraph*> :
   public GraphTraits<const CallGraphNode*> {
   static NodeType *getEntryNode(const CallGraph *CGN) {
@@ -322,10 +281,13 @@ template<> struct GraphTraits<const CallGraph*> :
   static nodes_iterator nodes_end  (const CallGraph *CG) { return CG->end(); }
 };
 
-// Make sure that any clients of this file link in PostDominators.cpp
+// Make sure that any clients of this file link in CallGraph.cpp
 static IncludeFile
 CALLGRAPH_INCLUDE_FILE((void*)&CallGraph::stub);
 
+extern void BasicCallGraphStub();
+static IncludeFile HDR_INCLUDE_CALLGRAPH_CPP((void*)&BasicCallGraphStub);
+
 } // End llvm namespace
 
 #endif
index 6188c2700142bda24b42f39d19ad411f499cccbd..afb120ed873740c3756a054cf5caeab80372e26c 100644 (file)
@@ -16,7 +16,6 @@
 #define LLVM_ANALYSIS_LINKALLANALYSES_H
 
 #include "llvm/Analysis/AliasSetTracker.h"
-#include "llvm/Analysis/CallGraph.h"
 #include "llvm/Analysis/FindUsedTypes.h"
 #include "llvm/Analysis/IntervalPartition.h"
 #include "llvm/Analysis/PostDominators.h"
@@ -49,7 +48,6 @@ namespace {
       (void)new llvm::IntervalPartition();
       (void)new llvm::ImmediateDominators();
       (void)new llvm::PostDominatorSet();
-      (void)new llvm::CallGraph();
       (void)new llvm::FindUsedTypes();
       (void)new llvm::ScalarEvolution();
       ((llvm::Function*)0)->viewCFGOnly();
index 3caafd923339c57a1fc2c8da4c699c8cf7c8ade8..03f73fa8d207ae46c3f1c99535f2a9fb503cc9b3 100644 (file)
@@ -7,7 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  This file implements the CallGraph class.
+// This file implements the CallGraph class and provides the BasicCallGraph
+// default implementation.
 //
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Module.h"
 #include "llvm/Instructions.h"
 #include "llvm/Support/CallSite.h"
-#include "llvm/ADT/STLExtras.h"
 #include <iostream>
 using namespace llvm;
 
-static RegisterAnalysis<CallGraph> X("callgraph", "Call Graph Construction");
-
-// getNodeFor - Return the node for the specified function or create one if it
-// does not already exist.
-//
-CallGraphNode *CallGraph::getNodeFor(Function *F) {
-  CallGraphNode *&CGN = FunctionMap[F];
-  if (CGN) return CGN;
-
-  assert((!F || F->getParent() == Mod) && "Function not in current module!");
-  return CGN = new CallGraphNode(F);
-}
+void llvm::BasicCallGraphStub() {}
 
 static bool isOnlyADirectCall(Function *F, CallSite CS) {
   if (!CS.getInstruction()) return false;
@@ -39,125 +28,194 @@ static bool isOnlyADirectCall(Function *F, CallSite CS) {
   return true;
 }
 
-// addToCallGraph - Add a function to the call graph, and link the node to all
-// of the functions that it calls.
+namespace {
+
+//===----------------------------------------------------------------------===//
+// BasicCallGraph class definition
 //
-void CallGraph::addToCallGraph(Function *F) {
-  CallGraphNode *Node = getNodeFor(F);
-
-  // If this function has external linkage, anything could call it...
-  if (!F->hasInternalLinkage()) {
-    ExternalCallingNode->addCalledFunction(Node);
-
-    // Found the entry point?
-    if (F->getName() == "main") {
-      if (Root)    // Found multiple external mains?  Don't pick one.
-        Root = ExternalCallingNode;
-      else
-        Root = Node;          // Found a main, keep track of it!
-    }
+class BasicCallGraph : public CallGraph, public ModulePass {
+  // Root is root of the call graph, or the external node if a 'main' function
+  // couldn't be found.
+  //
+  CallGraphNode *Root;
+
+  // ExternalCallingNode - This node has edges to all external functions and
+  // those internal functions that have their address taken.
+  CallGraphNode *ExternalCallingNode;
+
+  // CallsExternalNode - This node has edges to it from all functions making
+  // indirect calls or calling an external function.
+  CallGraphNode *CallsExternalNode;
+
+public:
+  BasicCallGraph() : Root(0), ExternalCallingNode(0), CallsExternalNode(0) {}
+  ~BasicCallGraph() { destroy(); }
+
+  // runOnModule - Compute the call graph for the specified module.
+  virtual bool runOnModule(Module &M) {
+    destroy();
+    CallGraph::initialize(M);
+    
+    ExternalCallingNode = getNodeFor(0);
+    CallsExternalNode = new CallGraphNode(0);
+    Root = 0;
+  
+    // Add every function to the call graph...
+    for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+      addToCallGraph(I);
+  
+    // If we didn't find a main function, use the external call graph node
+    if (Root == 0) Root = ExternalCallingNode;
+    
+    return false;
+  }
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+    AU.setPreservesAll();
   }
 
-  // If this function is not defined in this translation unit, it could call
-  // anything.
-  if (F->isExternal() && !F->getIntrinsicID())
-    Node->addCalledFunction(CallsExternalNode);
+  virtual void print(std::ostream &o, const Module *M) const {
+    o << "CallGraph Root is: ";
+    if (Function *F = getRoot()->getFunction())
+      o << F->getName() << "\n";
+    else
+      o << "<<null function: 0x" << getRoot() << ">>\n";
+    
+    CallGraph::print(o, M);
+  }
+
+  virtual void releaseMemory() {
+    destroy();
+  }
+  
+  /// dump - Print out this call graph.
+  ///
+  inline void dump() const {
+    print(std::cerr, Mod);
+  }
 
-  // Loop over all of the users of the function... looking for callers...
+  CallGraphNode* getExternalCallingNode() const { return ExternalCallingNode; }
+  CallGraphNode* getCallsExternalNode()   const { return CallsExternalNode; }
+
+  // getRoot - Return the root of the call graph, which is either main, or if
+  // main cannot be found, the external node.
   //
-  bool isUsedExternally = false;
-  for (Value::use_iterator I = F->use_begin(), E = F->use_end(); I != E; ++I) {
-    if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
-      if (isOnlyADirectCall(F, CallSite::get(Inst)))
-        getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
-      else
-        isUsedExternally = true;
-    } else if (GlobalValue *GV = dyn_cast<GlobalValue>(*I)) {
-      for (Value::use_iterator I = GV->use_begin(), E = GV->use_end();
-           I != E; ++I)
-        if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
+  CallGraphNode *getRoot()             { return Root; }
+  const CallGraphNode *getRoot() const { return Root; }
+
+private:
+  //===---------------------------------------------------------------------
+  // Implementation of CallGraph construction
+  //
+  // getNodeFor - Return the node for the specified function or create one if it
+  // does not already exist.
+  //
+
+  CallGraphNode *getNodeFor(Function *F) {
+    CallGraphNode *&CGN = FunctionMap[F];
+    if (CGN) return CGN;
+
+    assert((!F || F->getParent() == Mod) && "Function not in current module!");
+    return CGN = new CallGraphNode(F);
+  }
+  
+  //
+  // addToCallGraph - Add a function to the call graph, and link the node to all
+  // of the functions that it calls.
+  //
+  void addToCallGraph(Function *F) {
+    CallGraphNode *Node = getNodeFor(F);
+
+    // If this function has external linkage, anything could call it...
+    if (!F->hasInternalLinkage()) {
+      ExternalCallingNode->addCalledFunction(Node);
+
+      // Found the entry point?
+      if (F->getName() == "main") {
+        if (Root)    // Found multiple external mains?  Don't pick one.
+          Root = ExternalCallingNode;
+        else
+          Root = Node;          // Found a main, keep track of it!
+      }
+    }
+
+    // If this function is not defined in this translation unit, it could call
+    // anything.
+    if (F->isExternal() && !F->getIntrinsicID())
+      Node->addCalledFunction(CallsExternalNode);
+
+    // Loop over all of the users of the function... looking for callers...
+    //
+    bool isUsedExternally = false;
+    for (Value::use_iterator I = F->use_begin(), E = F->use_end(); I != E; ++I){
+      if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
+        if (isOnlyADirectCall(F, CallSite::get(Inst)))
+          getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
+        else
+          isUsedExternally = true;
+      } else if (GlobalValue *GV = dyn_cast<GlobalValue>(*I)) {
+        for (Value::use_iterator I = GV->use_begin(), E = GV->use_end();
+             I != E; ++I)
+          if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
           if (isOnlyADirectCall(F, CallSite::get(Inst)))
             getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
           else
             isUsedExternally = true;
-        } else {
-          isUsedExternally = true;
-        }
-    } else {                        // Can't classify the user!
-      isUsedExternally = true;
+          } else {
+            isUsedExternally = true;
+          }
+      } else {                        // Can't classify the user!
+        isUsedExternally = true;
+      }
     }
-  }
-  if (isUsedExternally)
-    ExternalCallingNode->addCalledFunction(Node);
+    if (isUsedExternally)
+      ExternalCallingNode->addCalledFunction(Node);
 
   // Look for an indirect function call...
-  for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB)
-    for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II){
+    for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB)
+      for (BasicBlock::iterator II = BB->begin(), IE = BB->end();
+           II != IE; ++II) {
       CallSite CS = CallSite::get(II);
       if (CS.getInstruction() && !CS.getCalledFunction())
         Node->addCalledFunction(CallsExternalNode);
-    }
-}
-
-bool CallGraph::runOnModule(Module &M) {
-  destroy();
+      }
+  }
 
-  Mod = &M;
-  ExternalCallingNode = getNodeFor(0);
-  CallsExternalNode = new CallGraphNode(0);
-  Root = 0;
+  //
+  // destroy - Release memory for the call graph
+  virtual void destroy() {
+    if (!CallsExternalNode) {
+      delete CallsExternalNode;
+      CallsExternalNode = 0;
+    }
+  }
+};
 
-  // Add every function to the call graph...
-  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
-    addToCallGraph(I);
+RegisterAnalysisGroup<CallGraph> X("Call Graph");
+RegisterOpt<BasicCallGraph> Y("basiccg", "Basic CallGraph Construction");
+RegisterAnalysisGroup<CallGraph, BasicCallGraph, true> Z;
 
-  // If we didn't find a main function, use the external call graph node
-  if (Root == 0) Root = ExternalCallingNode;
+} //End anonymous namespace
 
-  return false;
+void CallGraph::initialize(Module &M) {
+  destroy();
+  Mod = &M;
 }
 
 void CallGraph::destroy() {
-  for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
-       I != E; ++I)
-    delete I->second;
-  FunctionMap.clear();
-  delete CallsExternalNode;
-  CallsExternalNode = 0;
-}
-
-void CallGraphNode::print(std::ostream &OS) const {
-  if (Function *F = getFunction())
-    OS << "Call graph node for function: '" << F->getName() <<"'\n";
-  else
-    OS << "Call graph node <<null function: 0x" << this << ">>:\n";
-
-  for (const_iterator I = begin(), E = end(); I != E; ++I)
-    if ((*I)->getFunction())
-      OS << "  Calls function '" << (*I)->getFunction()->getName() << "'\n";
-    else
-      OS << "  Calls external node\n";
-  OS << "\n";
+  if(!FunctionMap.size()) {
+    for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
+        I != E; ++I)
+      delete I->second;
+    FunctionMap.clear();
+  }
 }
 
-void CallGraphNode::dump() const { print(std::cerr); }
-
 void CallGraph::print(std::ostream &OS, const Module *M) const {
-  OS << "CallGraph Root is: ";
-  if (Function *F = getRoot()->getFunction())
-    OS << F->getName() << "\n";
-  else
-    OS << "<<null function: 0x" << getRoot() << ">>\n";
-
   for (CallGraph::const_iterator I = begin(), E = end(); I != E; ++I)
     I->second->print(OS);
 }
 
-void CallGraph::dump() const {
-  print(std::cerr, 0);
-}
-
-
 //===----------------------------------------------------------------------===//
 // Implementations of public modification methods
 //
@@ -193,9 +251,24 @@ void CallGraph::changeFunction(Function *OldF, Function *NewF) {
   FunctionMap.erase(I);
 }
 
-
 void CallGraph::stub() {}
 
+void CallGraphNode::print(std::ostream &OS) const {
+  if (Function *F = getFunction())
+    OS << "Call graph node for function: '" << F->getName() <<"'\n";
+  else
+    OS << "Call graph node <<null function: 0x" << this << ">>:\n";
+
+  for (const_iterator I = begin(), E = end(); I != E; ++I)
+    if ((*I)->getFunction())
+      OS << "  Calls function '" << (*I)->getFunction()->getName() << "'\n";
+  else
+    OS << "  Calls external node\n";
+  OS << "\n";
+}
+
+void CallGraphNode::dump() const { print(std::cerr); }
+
 void CallGraphNode::removeCallEdgeTo(CallGraphNode *Callee) {
   for (unsigned i = CalledFunctions.size(); ; --i) {
     assert(i && "Cannot find callee to remove!");