[llvm-commits] [poolalloc] r98832 - /poolalloc/trunk/lib/DSA/DSCallGraph.cpp

Andrew Lenharth andrewl at lenharth.org
Thu Mar 18 09:57:13 PDT 2010


Author: alenhar2
Date: Thu Mar 18 11:57:12 2010
New Revision: 98832

URL: http://llvm.org/viewvc/llvm-project?rev=98832&view=rev
Log:
Forgot this

Added:
    poolalloc/trunk/lib/DSA/DSCallGraph.cpp

Added: poolalloc/trunk/lib/DSA/DSCallGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DSCallGraph.cpp?rev=98832&view=auto
==============================================================================
--- poolalloc/trunk/lib/DSA/DSCallGraph.cpp (added)
+++ poolalloc/trunk/lib/DSA/DSCallGraph.cpp Thu Mar 18 11:57:12 2010
@@ -0,0 +1,219 @@
+//===- DSCallGraph.cpp - Implement the Call Graph Support class -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Call Graph
+//
+//===----------------------------------------------------------------------===//
+
+#include "dsa/DSCallGraph.h"
+
+#include "llvm/Function.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/CommandLine.h"
+
+#include <algorithm>
+
+static bool _hasPointers(const llvm::FunctionType* T) {
+  if (T->isVarArg()) return true;
+  if (T->getReturnType()->isPointerTy()) return true;
+  for (unsigned x = 0; x < T->getNumParams(); ++x)
+    if (T->getParamType(x)->isPointerTy())
+      return true;
+  return false;
+}
+
+bool DSCallGraph::hasPointers(const llvm::Function* F) {
+  return _hasPointers(F->getFunctionType());
+}
+
+bool DSCallGraph::hasPointers(llvm::CallSite& CS) {
+  if (CS.getCalledFunction())
+    return hasPointers(CS.getCalledFunction());
+
+  const llvm::Value* Callee = CS.getCalledValue();
+  const llvm::Type* T = Callee->getType();
+  if (const llvm::PointerType* PT = llvm::dyn_cast<llvm::PointerType>(T))
+    T = PT->getElementType();
+  return _hasPointers(llvm::cast<llvm::FunctionType>(T));
+}
+
+unsigned DSCallGraph::tarjan_rec(const llvm::Function* F, TFStack& Stack,
+                                 unsigned &NextID, TFMap& ValMap) {
+  assert(!ValMap.count(F) && "Shouldn't revisit functions!");
+  unsigned Min = NextID++, MyID = Min;
+  ValMap[F] = Min;
+  Stack.push_back(F);
+
+  // The edges out of the current node are the call site targets...
+  for (flat_iterator ii = flat_callee_begin(F),
+       ee = flat_callee_end(F); ii != ee; ++ii) {
+    if (!(*ii)->isDeclaration()) {
+      unsigned M = Min;
+      // Have we visited the destination function yet?
+      TFMap::iterator It = ValMap.find(*ii);
+      if (It == ValMap.end()) // No, visit it now.
+        M = tarjan_rec(*ii, Stack, NextID, ValMap);
+      else if (std::find(Stack.begin(), Stack.end(), *ii) != Stack.end())
+        M = It->second;
+      if (M < Min) Min = M;
+    }
+  }
+
+  assert(ValMap[F] == MyID && "SCC construction assumption wrong!");
+  if (Min != MyID)
+    return Min; // This is part of a larger SCC!
+
+  // If this is a new SCC, process it now.
+  if (F == Stack.back()) {
+    // single node case
+    Stack.pop_back();
+    SCCs.insert(F);
+  } else {
+    // Take care that the leader is not an external function
+    std::vector<const llvm::Function*> microSCC;
+    const llvm::Function* NF = 0;
+    const llvm::Function* Leader = 0;
+    do {
+      NF = Stack.back();
+      Stack.pop_back();
+      microSCC.push_back(NF);
+      if (!Leader && !NF->isDeclaration()) Leader = NF;
+    } while (NF != F);
+    //Leader is not an extern function
+    //No multi-function SCC can not have a defined function, as all externs
+    //are treated as having no callees
+    assert(Leader && "No Leader?");
+    SCCs.insert(Leader);
+    Leader = SCCs.getLeaderValue(Leader);
+    assert(!Leader->isDeclaration() && "extern leader");
+    for (std::vector<const llvm::Function*>::iterator ii = microSCC.begin(),
+         ee = microSCC.end(); ii != ee; ++ii) {
+      SCCs.insert(*ii);
+      const llvm::Function* Temp = SCCs.getLeaderValue(*ii);
+      //Order Matters
+      SCCs.unionSets(Leader, Temp);
+      assert (SCCs.getLeaderValue(Leader) == Leader && "SCC construction wrong");
+      assert (SCCs.getLeaderValue(Temp) == Leader && "SCC construction wrong");
+    }
+  }
+
+  return MyID;
+}
+
+void DSCallGraph::buildSCCs() {
+  TFStack Stack;
+  TFMap ValMap;
+  unsigned NextID = 1;
+
+  for (flat_key_iterator ii = flat_key_begin(), ee = flat_key_end();
+       ii != ee; ++ii)
+    if (!ValMap.count(*ii))
+      tarjan_rec(*ii, Stack, NextID, ValMap);
+          
+  removeECFunctions();
+}
+
+static void removeECs(DSCallGraph::FuncSet& F, 
+                      llvm::EquivalenceClasses<const llvm::Function*>& ECs) {
+  DSCallGraph::FuncSet result;
+  for (DSCallGraph::FuncSet::const_iterator ii = F.begin(), ee = F.end();
+       ii != ee; ++ii)
+    result.insert(ECs.getLeaderValue(*ii));
+
+  F.swap(result);
+}
+
+void DSCallGraph::removeECFunctions() {
+  //First the callers
+  for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(),
+       ee = SimpleCallees.end(); ii != ee;) {
+    const llvm::Function* Leader = SCCs.getLeaderValue(ii->first);
+    if (Leader == ii->first) {
+      // This is the leader, leave it alone
+      ++ii;
+    } else {
+      //This is not the leader, merge into the leader
+      SimpleCallees[Leader].insert(ii->second.begin(), ii->second.end());
+      SimpleCalleesTy::iterator tmpii = ii;
+      ++ii;
+      SimpleCallees.erase(tmpii);
+    }
+  }
+  // then the callees
+  for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(),
+       ee = SimpleCallees.end(); ii != ee; ++ii) {
+    removeECs(ii->second, SCCs);
+    //and apparent self loops inside an SCC
+    ii->second.erase(ii->first);
+  }
+  for (ActualCalleesTy::iterator ii = ActualCallees.begin(),
+       ee = ActualCallees.end(); ii != ee; ++ii)
+    removeECs(ii->second, SCCs);
+}
+
+void DSCallGraph::buildRoots() {
+  FuncSet knownCallees;
+  FuncSet knownCallers;
+  for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(),
+       ee = SimpleCallees.end(); ii != ee; ++ii) {
+    knownCallees.insert(ii->second.begin(), ii->second.end());
+    knownCallers.insert(ii->first);
+  }
+  knownRoots.clear();
+  std::set_difference(knownCallers.begin(), knownCallers.end(),
+                      knownCallees.begin(), knownCallees.end(),
+                     std::inserter(knownRoots, knownRoots.begin()));
+}
+
+template <class T>
+void printNameOrPtr(T& Out, const llvm::Function* F) {
+  if (F->hasName())
+    Out << F->getName();
+  else
+    Out << F;
+}
+
+void DSCallGraph::dump() {
+  //function map
+
+  //CallGraph map
+  for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(),
+       ee = SimpleCallees.end(); ii != ee; ++ii) {
+    llvm::errs() << "CallGraph[";
+    printNameOrPtr(llvm::errs(), ii->first);
+    llvm::errs() << "]";
+    for (FuncSet::iterator i = ii->second.begin(),
+         e = ii->second.end(); i != e; ++i) {
+      llvm::errs() << " ";
+      printNameOrPtr(llvm::errs(), *i);
+    }
+    llvm::errs() << "\n";
+  }
+
+  //Functions we know about that aren't called
+  llvm::errs() << "Roots:";
+  for (FuncSet::iterator ii = knownRoots.begin(), ee = knownRoots.end();
+       ii != ee; ++ii) {
+    llvm::errs() << " ";
+    printNameOrPtr(llvm::errs(), *ii);
+  }
+  llvm::errs() << "\n";
+}
+
+//Filter all call edges.  We only want pointer edges.
+void DSCallGraph::insert(llvm::CallSite CS, const llvm::Function* F) {
+  if (F) {
+    ActualCallees[CS].insert(F);
+    SimpleCallees[CS.getInstruction()->getParent()->getParent()].insert(F);
+    //Create an empty set for the callee, hence all called functions get to be
+    // in the call graph also.  This simplifies SCC formation
+    SimpleCallees[F];
+  }
+}





More information about the llvm-commits mailing list