Make error messages more useful than jsut an abort
[oota-llvm.git] / lib / Analysis / DataStructure / BottomUpClosure.cpp
index 52b473883ccd7f6ceb6b7284ed8a33ad7c9f075a..0833a029129095c78b86978ee2150c5325635ef5 100644 (file)
 #include "llvm/Analysis/DSGraph.h"
 #include "llvm/Module.h"
 #include "Support/Statistic.h"
-using std::map;
+#include "Support/hash_map"
 
-static RegisterAnalysis<BUDataStructures>
-X("budatastructure", "Bottom-up Data Structure Analysis Closure");
-
-// TODO: FIXME
-namespace DataStructureAnalysis {
-  // isPointerType - Return true if this first class type is big enough to hold
-  // a pointer.
-  //
-  bool isPointerType(const Type *Ty);
+namespace {
+  Statistic<> MaxSCC("budatastructure", "Maximum SCC Size in Call Graph");
+  
+  RegisterAnalysis<BUDataStructures>
+  X("budatastructure", "Bottom-up Data Structure Analysis Closure");
 }
-using namespace DataStructureAnalysis;
 
+using namespace DS;
 
-// releaseMemory - If the pass pipeline is done with this pass, we can release
-// our memory... here...
+static bool isVAHackFn(const Function *F) {
+  return F->getName() == "printf"  || F->getName() == "sscanf" ||
+         F->getName() == "fprintf" || F->getName() == "open" ||
+         F->getName() == "sprintf" || F->getName() == "fputs" ||
+         F->getName() == "fscanf";
+}
+
+// isCompleteNode - Return true if we know all of the targets of this node, and
+// if the call sites are not external.
 //
-void BUDataStructures::releaseMemory() {
-  // Delete all call site information
-  CallSites.clear();
+static inline bool isCompleteNode(DSNode *N) {
+  if (N->NodeType & DSNode::Incomplete) return false;
+  const std::vector<GlobalValue*> &Callees = N->getGlobals();
+  for (unsigned i = 0, e = Callees.size(); i != e; ++i)
+    if (Callees[i]->isExternal())
+      if (!isVAHackFn(cast<Function>(Callees[i])))
+        return false;  // External function found...
+  return true;  // otherwise ok
+}
+
+struct CallSiteIterator {
+  // FCs are the edges out of the current node are the call site targets...
+  std::vector<DSCallSite> *FCs;
+  unsigned CallSite;
+  unsigned CallSiteEntry;
+
+  CallSiteIterator(std::vector<DSCallSite> &CS) : FCs(&CS) {
+    CallSite = 0; CallSiteEntry = 0;
+    advanceToValidCallee();
+  }
+
+  // End iterator ctor...
+  CallSiteIterator(std::vector<DSCallSite> &CS, bool) : FCs(&CS) {
+    CallSite = FCs->size(); CallSiteEntry = 0;
+  }
+
+  void advanceToValidCallee() {
+    while (CallSite < FCs->size()) {
+      if ((*FCs)[CallSite].isDirectCall()) {
+        if (CallSiteEntry == 0 &&        // direct call only has one target...
+            (!(*FCs)[CallSite].getCalleeFunc()->isExternal() ||
+             isVAHackFn((*FCs)[CallSite].getCalleeFunc()))) // If not external
+          return;
+      } else {
+        DSNode *CalleeNode = (*FCs)[CallSite].getCalleeNode();
+        if (CallSiteEntry || isCompleteNode(CalleeNode)) {
+          const std::vector<GlobalValue*> &Callees = CalleeNode->getGlobals();
+          
+          if (CallSiteEntry < Callees.size())
+            return;
+        }
+      }
+      CallSiteEntry = 0;
+      ++CallSite;
+    }
+  }
+public:
+  static CallSiteIterator begin(DSGraph &G) { return G.getAuxFunctionCalls(); }
+  static CallSiteIterator end(DSGraph &G) {
+    return CallSiteIterator(G.getAuxFunctionCalls(), true);
+  }
+  static CallSiteIterator begin(std::vector<DSCallSite> &CSs) { return CSs; }
+  static CallSiteIterator end(std::vector<DSCallSite> &CSs) {
+    return CallSiteIterator(CSs, true);
+  }
+  bool operator==(const CallSiteIterator &CSI) const {
+    return CallSite == CSI.CallSite && CallSiteEntry == CSI.CallSiteEntry;
+  }
+  bool operator!=(const CallSiteIterator &CSI) const { return !operator==(CSI);}
+
+  unsigned getCallSiteIdx() const { return CallSite; }
+  DSCallSite &getCallSite() const { return (*FCs)[CallSite]; }
+
+  Function *operator*() const {
+    if ((*FCs)[CallSite].isDirectCall()) {
+      return (*FCs)[CallSite].getCalleeFunc();
+    } else {
+      DSNode *Node = (*FCs)[CallSite].getCalleeNode();
+      return cast<Function>(Node->getGlobals()[CallSiteEntry]);
+    }
+  }
+
+  CallSiteIterator& operator++() {                // Preincrement
+    ++CallSiteEntry;
+    advanceToValidCallee();
+    return *this;
+  }
+  CallSiteIterator operator++(int) { // Postincrement
+    CallSiteIterator tmp = *this; ++*this; return tmp; 
+  }
+};
 
-  for (map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
-         E = DSInfo.end(); I != E; ++I)
-    delete I->second;
 
-  // Empty map so next time memory is released, data structures are not
-  // re-deleted.
-  DSInfo.clear();
-}
 
 // run - Calculate the bottom up data structure graphs for each function in the
 // program.
 //
 bool BUDataStructures::run(Module &M) {
-  // Simply calculate the graphs for each function...
+  GlobalsGraph = new DSGraph();
+  GlobalsGraph->setPrintAuxCalls();
+
+  Function *MainFunc = M.getMainFunction();
+  if (MainFunc)
+    calculateReachableGraphs(MainFunc);
+
+  // Calculate the graphs for any functions that are unreachable from main...
   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
-    if (!I->isExternal())
-      calculateGraph(*I);
+    if (!I->isExternal() && DSInfo.find(I) == DSInfo.end()) {
+#ifndef NDEBUG
+      if (MainFunc)
+        std::cerr << "*** Function unreachable from main: "
+                  << I->getName() << "\n";
+#endif
+      calculateReachableGraphs(I);    // Calculate all graphs...
+    }
   return false;
 }
 
-// ResolveArguments - Resolve the formal and actual arguments for a function
-// call.
-//
-static void ResolveArguments(DSCallSite &Call, Function &F,
-                             map<Value*, DSNodeHandle> &ValueMap) {
-  // Resolve all of the function arguments...
-  Function::aiterator AI = F.abegin();
-  for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i) {
-    // Advance the argument iterator to the first pointer argument...
-    while (!isPointerType(AI->getType())) ++AI;
-    
-    // Add the link from the argument scalar to the provided value
-    DSNodeHandle &NN = ValueMap[AI];
-    NN.addEdgeTo(Call.getPtrArgNode(i));
-    ++AI;
-  }
+void BUDataStructures::calculateReachableGraphs(Function *F) {
+  std::vector<Function*> Stack;
+  hash_map<Function*, unsigned> ValMap;
+  unsigned NextID = 1;
+  calculateGraphs(F, Stack, NextID, ValMap);
 }
 
-DSGraph &BUDataStructures::calculateGraph(Function &F) {
-  // Make sure this graph has not already been calculated, or that we don't get
-  // into an infinite loop with mutually recursive functions.
-  //
-  DSGraph *&Graph = DSInfo[&F];
+DSGraph &BUDataStructures::getOrCreateGraph(Function *F) {
+  // Has the graph already been created?
+  DSGraph *&Graph = DSInfo[F];
   if (Graph) return *Graph;
 
   // Copy the local version into DSInfo...
-  Graph = new DSGraph(getAnalysis<LocalDataStructures>().getDSGraph(F));
+  Graph = new DSGraph(getAnalysis<LocalDataStructures>().getDSGraph(*F));
+
+  Graph->setGlobalsGraph(GlobalsGraph);
+  Graph->setPrintAuxCalls();
+
+  // Start with a copy of the original call sites...
+  Graph->getAuxFunctionCalls() = Graph->getFunctionCalls();
+  return *Graph;
+}
+
+unsigned BUDataStructures::calculateGraphs(Function *F,
+                                           std::vector<Function*> &Stack,
+                                           unsigned &NextID, 
+                                     hash_map<Function*, unsigned> &ValMap) {
+  assert(ValMap.find(F) == ValMap.end() && "Shouldn't revisit functions!");
+  unsigned Min = NextID++, MyID = Min;
+  ValMap[F] = Min;
+  Stack.push_back(F);
+
+  if (F->isExternal()) {   // sprintf, fprintf, sscanf, etc...
+    // No callees!
+    Stack.pop_back();
+    ValMap[F] = ~0;
+    return Min;
+  }
+
+  DSGraph &Graph = getOrCreateGraph(F);
+
+  // The edges out of the current node are the call site targets...
+  for (CallSiteIterator I = CallSiteIterator::begin(Graph),
+         E = CallSiteIterator::end(Graph); I != E; ++I) {
+    Function *Callee = *I;
+    unsigned M;
+    // Have we visited the destination function yet?
+    hash_map<Function*, unsigned>::iterator It = ValMap.find(Callee);
+    if (It == ValMap.end())  // No, visit it now.
+      M = calculateGraphs(Callee, Stack, NextID, ValMap);
+    else                    // Yes, get it's number.
+      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 (Stack.back() == F) {           // Special case the single "SCC" case here.
+    DEBUG(std::cerr << "Visiting single node SCC #: " << MyID << " fn: "
+                    << F->getName() << "\n");
+    Stack.pop_back();
+    DSGraph &G = calculateGraph(*F);
+
+    if (MaxSCC < 1) MaxSCC = 1;
+
+    // Should we revisit the graph?
+    if (CallSiteIterator::begin(G) != CallSiteIterator::end(G)) {
+      ValMap.erase(F);
+      return calculateGraphs(F, Stack, NextID, ValMap);
+    } else {
+      ValMap[F] = ~0U;
+    }
+    return MyID;
+
+  } else {
+    // SCCFunctions - Keep track of the functions in the current SCC
+    //
+    hash_set<Function*> SCCFunctions;
+
+    Function *NF;
+    std::vector<Function*>::iterator FirstInSCC = Stack.end();
+    do {
+      NF = *--FirstInSCC;
+      ValMap[NF] = ~0U;
+      SCCFunctions.insert(NF);
+    } while (NF != F);
+
+    std::cerr << "Identified SCC #: " << MyID << " of size: "
+              << (Stack.end()-FirstInSCC) << "\n";
+
+    // Compute the Max SCC Size...
+    if (MaxSCC < unsigned(Stack.end()-FirstInSCC))
+      MaxSCC = Stack.end()-FirstInSCC;
+
+    std::vector<Function*>::iterator I = Stack.end();
+    do {
+      --I;
+#ifndef NDEBUG
+      /*DEBUG*/(std::cerr << "  Fn #" << (Stack.end()-I) << "/"
+            << (Stack.end()-FirstInSCC) << " in SCC: "
+            << (*I)->getName());
+      DSGraph &G = getDSGraph(**I);
+      std::cerr << " [" << G.getGraphSize() << "+"
+                << G.getAuxFunctionCalls().size() << "] ";
+#endif
+
+      // Eliminate all call sites in the SCC that are not to functions that are
+      // in the SCC.
+      inlineNonSCCGraphs(**I, SCCFunctions);
+
+#ifndef NDEBUG
+      std::cerr << "after Non-SCC's [" << G.getGraphSize() << "+"
+                << G.getAuxFunctionCalls().size() << "]\n";
+#endif
+    } while (I != FirstInSCC);
+
+    I = Stack.end();
+    do {
+      --I;
+#ifndef NDEBUG
+      /*DEBUG*/(std::cerr << "  Fn #" << (Stack.end()-I) << "/"
+            << (Stack.end()-FirstInSCC) << " in SCC: "
+            << (*I)->getName());
+      DSGraph &G = getDSGraph(**I);
+      std::cerr << " [" << G.getGraphSize() << "+"
+                << G.getAuxFunctionCalls().size() << "] ";
+#endif
+      // Inline all graphs into the SCC nodes...
+      calculateSCCGraph(**I, SCCFunctions);
+
+#ifndef NDEBUG
+      std::cerr << "after [" << G.getGraphSize() << "+"
+                << G.getAuxFunctionCalls().size() << "]\n";
+#endif
+    } while (I != FirstInSCC);
+
 
+    std::cerr << "DONE with SCC #: " << MyID << "\n";
+
+    // We never have to revisit "SCC" processed functions...
+    
+    // Drop the stuff we don't need from the end of the stack
+    Stack.erase(FirstInSCC, Stack.end());
+    return MyID;
+  }
+
+  return MyID;  // == Min
+}
+
+
+// releaseMemory - If the pass pipeline is done with this pass, we can release
+// our memory... here...
+//
+void BUDataStructures::releaseMemory() {
+  for (hash_map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
+         E = DSInfo.end(); I != E; ++I)
+    delete I->second;
+
+  // Empty map so next time memory is released, data structures are not
+  // re-deleted.
+  DSInfo.clear();
+  delete GlobalsGraph;
+  GlobalsGraph = 0;
+}
+
+DSGraph &BUDataStructures::calculateGraph(Function &F) {
+  DSGraph &Graph = getDSGraph(F);
+  DEBUG(std::cerr << "  [BU] Calculating graph for: " << F.getName() << "\n");
+
+  // Move our call site list into TempFCs so that inline call sites go into the
+  // new call site list and doesn't invalidate our iterators!
+  std::vector<DSCallSite> TempFCs;
+  std::vector<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
+  TempFCs.swap(AuxCallsList);
+
+  // Loop over all of the resolvable call sites
+  unsigned LastCallSiteIdx = ~0U;
+  for (CallSiteIterator I = CallSiteIterator::begin(TempFCs),
+         E = CallSiteIterator::end(TempFCs); I != E; ++I) {
+    // If we skipped over any call sites, they must be unresolvable, copy them
+    // to the real call site list.
+    LastCallSiteIdx++;
+    for (; LastCallSiteIdx < I.getCallSiteIdx(); ++LastCallSiteIdx)
+      AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
+    LastCallSiteIdx = I.getCallSiteIdx();
+    
+    // Resolve the current call...
+    Function *Callee = *I;
+    DSCallSite &CS = I.getCallSite();
+
+    if (Callee->isExternal()) {
+      // Ignore this case, simple varargs functions we cannot stub out!
+    } else if (Callee == &F) {
+      // Self recursion... simply link up the formal arguments with the
+      // actual arguments...
+      DEBUG(std::cerr << "    Self Inlining: " << F.getName() << "\n");
+
+      // Handle self recursion by resolving the arguments and return value
+      Graph.mergeInGraph(CS, Graph, 0);
+
+    } else {
+      // Get the data structure graph for the called function.
+      //
+      DSGraph &GI = getDSGraph(*Callee);  // Graph to inline
+      
+      DEBUG(std::cerr << "    Inlining graph for " << Callee->getName()
+            << "[" << GI.getGraphSize() << "+"
+            << GI.getAuxFunctionCalls().size() << "] into: " << F.getName()
+            << "[" << Graph.getGraphSize() << "+"
+            << Graph.getAuxFunctionCalls().size() << "]\n");
 #if 0
-  // Populate the GlobalsGraph with globals from this one.
-  Graph->GlobalsGraph->cloneGlobals(*Graph, /*cloneCalls*/ false);
+      Graph.writeGraphToFile(std::cerr, "bu_" + F.getName() + "_before_" +
+                             Callee->getName());
 #endif
+      
+      // Handle self recursion by resolving the arguments and return value
+      Graph.mergeInGraph(CS, GI,
+                         DSGraph::KeepModRefBits | 
+                         DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes);
 
-  // Start resolving calls...
-  std::vector<DSCallSite> &FCs = Graph->getFunctionCalls();
+#if 0
+      Graph.writeGraphToFile(std::cerr, "bu_" + F.getName() + "_after_" +
+                             Callee->getName());
+#endif
+    }
+  }
 
-  DEBUG(std::cerr << "  [BU] Inlining: " << F.getName() << "\n");
+  // Make sure to catch any leftover unresolvable calls...
+  for (++LastCallSiteIdx; LastCallSiteIdx < TempFCs.size(); ++LastCallSiteIdx)
+    AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
 
-  bool Inlined;
-  do {
-    Inlined = false;
+  TempFCs.clear();
 
-    for (unsigned i = 0; i != FCs.size(); ++i) {
-      // Copy the call, because inlining graphs may invalidate the FCs vector.
-      DSCallSite Call = FCs[i];
+  // Recompute the Incomplete markers.  If there are any function calls left
+  // now that are complete, we must loop!
+  Graph.maskIncompleteMarkers();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
+  // FIXME: materialize nodes from the globals graph as neccesary...
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
 
-      // If the function list is complete...
-      if ((Call.getCalleeNode().getNode()->NodeType & DSNode::Incomplete)==0) {
-        // Start inlining all of the functions we can... some may not be
-        // inlinable if they are external...
-        //
-        std::vector<GlobalValue*> Callees(Call.getCalleeNode().getNode()->getGlobals());
-
-        // Loop over the functions, inlining whatever we can...
-        for (unsigned c = 0; c != Callees.size(); ++c) {
-          // Must be a function type, so this cast MUST succeed.
-          Function &FI = cast<Function>(*Callees[c]);
-
-          if (&FI == &F) {
-            // Self recursion... simply link up the formal arguments with the
-            // actual arguments...
-
-            DEBUG(std::cerr << "\t[BU] Self Inlining: " << F.getName() << "\n");
-
-            if (Call.getReturnValueNode().getNode()) // Handle the return value if present...
-              Graph->getRetNode().mergeWith(Call.getReturnValueNode());
-
-            // Resolve the arguments in the call to the actual values...
-            ResolveArguments(Call, F, Graph->getValueMap());
-
-            // Erase the entry in the callees vector
-            Callees.erase(Callees.begin()+c--);
-
-          } else if (!FI.isExternal()) {
-            DEBUG(std::cerr << "\t[BU] In " << F.getName() << " inlining: "
-                  << FI.getName() << "\n");
-            
-            // Get the data structure graph for the called function, closing it
-            // if possible (which is only impossible in the case of mutual
-            // recursion...
-            //
-            DSGraph &GI = calculateGraph(FI);  // Graph to inline
-
-            DEBUG(std::cerr << "\t\t[BU] Got graph for " << FI.getName()
-                  << " in: " << F.getName() << "\n");
-
-            // Record that the original DSCallSite was a call site of FI.
-            // This may or may not have been known when the DSCallSite was
-            // originally created.
-            CallSites[&FI].push_back(Call);
-
-            // Clone the callee's graph into the current graph, keeping
-            // track of where scalars in the old graph _used_ to point,
-            // and of the new nodes matching nodes of the old graph.
-            map<Value*, DSNodeHandle> OldValMap;
-            map<const DSNode*, DSNode*> OldNodeMap;
-
-            // The clone call may invalidate any of the vectors in the data
-            // structure graph.  Strip locals and don't copy the list of callers
-            DSNodeHandle RetVal = Graph->cloneInto(GI, OldValMap, OldNodeMap,
-                                                   /*StripScalars*/   true,
-                                                   /*StripAllocas*/   true,
-                                                   /*CopyCallers*/    false,
-                                                   /*CopyOrigCalls*/  false);
-
-            // Resolve the arguments in the call to the actual values...
-            ResolveArguments(Call, FI, OldValMap);
-
-            if (Call.getReturnValueNode().getNode())  // Handle the return value if present
-              RetVal.mergeWith(Call.getReturnValueNode());
-
-            // Erase the entry in the Callees vector
-            Callees.erase(Callees.begin()+c--);
-
-          } else if (FI.getName() == "printf" || FI.getName() == "sscanf" ||
-                     FI.getName() == "fprintf" || FI.getName() == "open" ||
-                     FI.getName() == "sprintf") {
-
-            // Erase the entry in the globals vector
-            Callees.erase(Callees.begin()+c--);
-          }
-        }
+  DEBUG(std::cerr << "  [BU] Done inlining: " << F.getName() << " ["
+        << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
+        << "]\n");
 
-        if (Callees.empty()) {         // Inlined all of the function calls?
-          // Erase the call if it is resolvable...
-          FCs.erase(FCs.begin()+i--);  // Don't skip a the next call...
-          Inlined = true;
-        } else if (Callees.size() != Call.getCalleeNode().getNode()->getGlobals().size()) {
-          // Was able to inline SOME, but not all of the functions.  Construct a
-          // new global node here.
-          //
-          assert(0 && "Unimpl!");
-          Inlined = true;
-        }
-      }
+  //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
+
+  return Graph;
+}
+
+
+// inlineNonSCCGraphs - This method is almost like the other two calculate graph
+// methods.  This one is used to inline function graphs (from functions outside
+// of the SCC) into functions in the SCC.  It is not supposed to touch functions
+// IN the SCC at all.
+//
+DSGraph &BUDataStructures::inlineNonSCCGraphs(Function &F,
+                                             hash_set<Function*> &SCCFunctions){
+  DSGraph &Graph = getDSGraph(F);
+  DEBUG(std::cerr << "  [BU] Inlining Non-SCC graphs for: "
+                  << F.getName() << "\n");
+
+  // Move our call site list into TempFCs so that inline call sites go into the
+  // new call site list and doesn't invalidate our iterators!
+  std::vector<DSCallSite> TempFCs;
+  std::vector<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
+  TempFCs.swap(AuxCallsList);
+
+  // Loop over all of the resolvable call sites
+  unsigned LastCallSiteIdx = ~0U;
+  for (CallSiteIterator I = CallSiteIterator::begin(TempFCs),
+         E = CallSiteIterator::end(TempFCs); I != E; ++I) {
+    // If we skipped over any call sites, they must be unresolvable, copy them
+    // to the real call site list.
+    LastCallSiteIdx++;
+    for (; LastCallSiteIdx < I.getCallSiteIdx(); ++LastCallSiteIdx)
+      AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
+    LastCallSiteIdx = I.getCallSiteIdx();
+    
+    // Resolve the current call...
+    Function *Callee = *I;
+    DSCallSite &CS = I.getCallSite();
+
+    if (Callee->isExternal()) {
+      // Ignore this case, simple varargs functions we cannot stub out!
+    } else if (SCCFunctions.count(Callee)) {
+      // Calling a function in the SCC, ignore it for now!
+      DEBUG(std::cerr << "    SCC CallSite for: " << Callee->getName() << "\n");
+      AuxCallsList.push_back(CS);
+    } else {
+      // Get the data structure graph for the called function.
+      //
+      DSGraph &GI = getDSGraph(*Callee);  // Graph to inline
+
+      DEBUG(std::cerr << "    Inlining graph for " << Callee->getName()
+            << "[" << GI.getGraphSize() << "+"
+            << GI.getAuxFunctionCalls().size() << "] into: " << F.getName()
+            << "[" << Graph.getGraphSize() << "+"
+            << Graph.getAuxFunctionCalls().size() << "]\n");
+
+      // Handle self recursion by resolving the arguments and return value
+      Graph.mergeInGraph(CS, GI,
+                         DSGraph::KeepModRefBits | DSGraph::StripAllocaBit |
+                         DSGraph::DontCloneCallNodes);
     }
+  }
+
+  // Make sure to catch any leftover unresolvable calls...
+  for (++LastCallSiteIdx; LastCallSiteIdx < TempFCs.size(); ++LastCallSiteIdx)
+    AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
+
+  TempFCs.clear();
+
+  // Recompute the Incomplete markers.  If there are any function calls left
+  // now that are complete, we must loop!
+  Graph.maskIncompleteMarkers();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
+
+  DEBUG(std::cerr << "  [BU] Done Non-SCC inlining: " << F.getName() << " ["
+        << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
+        << "]\n");
+  //Graph.writeGraphToFile(std::cerr, "nscc_" + F.getName());
+  return Graph;
+}
 
-    // Recompute the Incomplete markers.  If there are any function calls left
-    // now that are complete, we must loop!
-    if (Inlined) {
-      Graph->maskIncompleteMarkers();
-      Graph->markIncompleteNodes();
-      Graph->removeDeadNodes(/*KeepAllGlobals*/ true, /*KeepCalls*/ true);
+
+DSGraph &BUDataStructures::calculateSCCGraph(Function &F,
+                                             hash_set<Function*> &SCCFunctions){
+  DSGraph &Graph = getDSGraph(F);
+  DEBUG(std::cerr << "  [BU] Calculating SCC graph for: " << F.getName()<<"\n");
+
+  std::vector<DSCallSite> UnresolvableCalls;
+  hash_map<Function*, DSCallSite> SCCCallSiteMap;
+  std::vector<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
+
+  while (1) {  // Loop until we run out of resolvable call sites!
+    // Move our call site list into TempFCs so that inline call sites go into
+    // the new call site list and doesn't invalidate our iterators!
+    std::vector<DSCallSite> TempFCs;
+    TempFCs.swap(AuxCallsList);
+
+    // Loop over all of the resolvable call sites
+    unsigned LastCallSiteIdx = ~0U;
+    CallSiteIterator I = CallSiteIterator::begin(TempFCs),
+      E = CallSiteIterator::end(TempFCs);
+    if (I == E) {
+      TempFCs.swap(AuxCallsList);
+      break;  // Done when no resolvable call sites exist
     }
-  } while (Inlined && !FCs.empty());
 
-  Graph->maskIncompleteMarkers();
-  Graph->markIncompleteNodes();
-  Graph->removeTriviallyDeadNodes(false);
-  Graph->removeDeadNodes(/*KeepAllGlobals*/ true, /*KeepCalls*/ true);
+    for (; I != E; ++I) {
+      // If we skipped over any call sites, they must be unresolvable, copy them
+      // to the unresolvable site list.
+      LastCallSiteIdx++;
+      for (; LastCallSiteIdx < I.getCallSiteIdx(); ++LastCallSiteIdx)
+        UnresolvableCalls.push_back(TempFCs[LastCallSiteIdx]);
+      LastCallSiteIdx = I.getCallSiteIdx();
+      
+      // Resolve the current call...
+      Function *Callee = *I;
+      DSCallSite &CS = I.getCallSite();
+      
+      if (Callee->isExternal()) {
+        // Ignore this case, simple varargs functions we cannot stub out!
+      } else if (Callee == &F) {
+        // Self recursion... simply link up the formal arguments with the
+        // actual arguments...
+        DEBUG(std::cerr << "    Self Inlining: " << F.getName() << "\n");
+        
+        // Handle self recursion by resolving the arguments and return value
+        Graph.mergeInGraph(CS, Graph, 0);
+      } else if (SCCCallSiteMap.count(Callee)) {
+        // We have already seen a call site in the SCC for this function, just
+        // merge the two call sites together and we are done.
+        SCCCallSiteMap.find(Callee)->second.mergeWith(CS);
+      } else {
+        // Get the data structure graph for the called function.
+        //
+        DSGraph &GI = getDSGraph(*Callee);  // Graph to inline
+        DEBUG(std::cerr << "    Inlining graph for " << Callee->getName()
+              << "[" << GI.getGraphSize() << "+"
+              << GI.getAuxFunctionCalls().size() << "] into: " << F.getName()
+              << "[" << Graph.getGraphSize() << "+"
+              << Graph.getAuxFunctionCalls().size() << "]\n");
+        
+        // Handle self recursion by resolving the arguments and return value
+        Graph.mergeInGraph(CS, GI,
+                           DSGraph::KeepModRefBits | DSGraph::StripAllocaBit |
+                           DSGraph::DontCloneCallNodes);
+
+        if (SCCFunctions.count(Callee))
+          SCCCallSiteMap.insert(std::make_pair(Callee, CS));
+      }
+    }
+    
+    // Make sure to catch any leftover unresolvable calls...
+    for (++LastCallSiteIdx; LastCallSiteIdx < TempFCs.size(); ++LastCallSiteIdx)
+      UnresolvableCalls.push_back(TempFCs[LastCallSiteIdx]);
+  }
+
+  // Reset the SCCCallSiteMap...
+  SCCCallSiteMap.clear();
+
+  AuxCallsList.insert(AuxCallsList.end(), UnresolvableCalls.begin(),
+                      UnresolvableCalls.end());
+  UnresolvableCalls.clear();
+
+
+  // Recompute the Incomplete markers.  If there are any function calls left
+  // now that are complete, we must loop!
+  Graph.maskIncompleteMarkers();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
+
+  // FIXME: materialize nodes from the globals graph as neccesary...
+
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
 
   DEBUG(std::cerr << "  [BU] Done inlining: " << F.getName() << " ["
-        << Graph->getGraphSize() << "+" << Graph->getFunctionCalls().size()
+        << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
         << "]\n");
-
-  return *Graph;
+  //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
+  return Graph;
 }