Fix for PR341
[oota-llvm.git] / lib / Analysis / DataStructure / BottomUpClosure.cpp
index 2d2a182a4f55959a288a035a32aba06d6ce7452d..9f2124a1bb57178a78f6459545a3f6fa4b46cf17 100644 (file)
-//===- BottomUpClosure.cpp - Compute the bottom up interprocedure closure -===//
+//===- BottomUpClosure.cpp - Compute bottom-up interprocedural closure ----===//
+// 
+//                     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 BUDataStructures class, which represents the
 // Bottom-Up Interprocedural closure of the data structure graph over the
 // program.  This is useful for applications like pool allocation, but **not**
-// applications like pointer analysis.
+// applications like alias analysis.
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Analysis/DataStructure.h"
+#include "llvm/Analysis/DataStructure/DataStructure.h"
 #include "llvm/Module.h"
-#include "llvm/DerivedTypes.h"
-#include "Support/StatisticReporter.h"
-#include <set>
-using std::map;
-
-static RegisterAnalysis<BUDataStructures>
-X("budatastructure", "Bottom-up Data Structure Analysis Closure");
-AnalysisID BUDataStructures::ID = X;
-
-// releaseMemory - If the pass pipeline is done with this pass, we can release
-// our memory... here...
-//
-void BUDataStructures::releaseMemory() {
-  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();
+#include "Support/Statistic.h"
+#include "Support/Debug.h"
+#include "DSCallSiteIterator.h"
+using namespace llvm;
+
+namespace {
+  Statistic<> MaxSCC("budatastructure", "Maximum SCC Size in Call Graph");
+  Statistic<> NumBUInlines("budatastructures", "Number of graphs inlined");
+  Statistic<> NumCallEdges("budatastructures", "Number of 'actual' call edges");
+  
+  RegisterAnalysis<BUDataStructures>
+  X("budatastructure", "Bottom-up Data Structure Analysis");
 }
 
+using namespace DS;
+
 // 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...
+  LocalDataStructures &LocalDSA = getAnalysis<LocalDataStructures>();
+  GlobalsGraph = new DSGraph(LocalDSA.getGlobalsGraph());
+  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.count(I)) {
+#ifndef NDEBUG
+      if (MainFunc)
+        std::cerr << "*** Function unreachable from main: "
+                  << I->getName() << "\n";
+#endif
+      calculateReachableGraphs(I);    // Calculate all graphs...
+    }
+
+  NumCallEdges += ActualCallees.size();
+
+  // At the end of the bottom-up pass, the globals graph becomes complete.
+  // FIXME: This is not the right way to do this, but it is sorta better than
+  // nothing!  In particular, externally visible globals and unresolvable call
+  // nodes at the end of the BU phase should make things that they point to
+  // incomplete in the globals graph.
+  // 
+  GlobalsGraph->removeTriviallyDeadNodes();
+  GlobalsGraph->maskIncompleteMarkers();
   return false;
 }
 
-
-// ResolveArguments - Resolve the formal and actual arguments for a function
-// call.
-//
-static void ResolveArguments(std::vector<DSNodeHandle> &Call, Function &F,
-                             map<Value*, DSNodeHandle> &ValueMap) {
-  // Resolve all of the function arguments...
-  Function::aiterator AI = F.abegin();
-  for (unsigned i = 2, e = Call.size(); i != e; ++i) {
-    // Advance the argument iterator to the first pointer argument...
-    while (!isa<PointerType>(AI->getType())) ++AI;
-    
-    // Add the link from the argument scalar to the provided value
-    DSNode *NN = ValueMap[AI];
-    NN->addEdgeTo(Call[i]);
-    ++AI;
-  }
+void BUDataStructures::calculateReachableGraphs(Function *F) {
+  std::vector<Function*> Stack;
+  hash_map<Function*, unsigned> ValMap;
+  unsigned NextID = 1;
+  calculateGraphs(F, Stack, NextID, ValMap);
 }
 
-// MergeGlobalNodes - Merge all existing global nodes with globals
-// inlined from the callee or with globals from the GlobalsGraph.
-//
-static void MergeGlobalNodes(DSGraph& Graph,
-                             map<Value*, DSNodeHandle> &OldValMap) {
-  map<Value*, DSNodeHandle> &ValMap = Graph.getValueMap();
-  for (map<Value*, DSNodeHandle>::iterator I = ValMap.begin(), E = ValMap.end();
-       I != E; ++I)
-    if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) {
-      map<Value*, DSNodeHandle>:: iterator NHI = OldValMap.find(GV);
-      if (NHI != OldValMap.end())       // was it inlined from the callee?
-        I->second->mergeWith(NHI->second);
-      else                              // get it from the GlobalsGraph
-        I->second->mergeWith(Graph.cloneGlobalInto(GV));
-    }
+DSGraph &BUDataStructures::getOrCreateGraph(Function *F) {
+  // Has the graph already been created?
+  DSGraph *&Graph = DSInfo[F];
+  if (Graph) return *Graph;
 
-  // Add unused inlined global nodes into the value map
-  for (map<Value*, DSNodeHandle>::iterator I = OldValMap.begin(),
-         E = OldValMap.end(); I != E; ++I)
-    if (isa<GlobalValue>(I->first)) {
-      DSNodeHandle &NH = ValMap[I->first];  // If global is not in ValMap...
-      if (NH == 0)
-        NH = I->second;                     // Add the one just inlined.
-    }
+  // Copy the local version into DSInfo...
+  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;
 }
 
-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];
-  if (Graph) return *Graph;
+unsigned BUDataStructures::calculateGraphs(Function *F,
+                                           std::vector<Function*> &Stack,
+                                           unsigned &NextID, 
+                                     hash_map<Function*, unsigned> &ValMap) {
+  assert(!ValMap.count(F) && "Shouldn't revisit functions!");
+  unsigned Min = NextID++, MyID = Min;
+  ValMap[F] = Min;
+  Stack.push_back(F);
+
+  // FIXME!  This test should be generalized to be any function that we have
+  // already processed, in the case when there isn't a main or there are
+  // unreachable functions!
+  if (F->isExternal()) {   // sprintf, fprintf, sscanf, etc...
+    // No callees!
+    Stack.pop_back();
+    ValMap[F] = ~0;
+    return Min;
+  }
 
-  // Copy the local version into DSInfo...
-  Graph = new DSGraph(getAnalysis<LocalDataStructures>().getDSGraph(F));
-
-  // Populate the GlobalsGraph with globals from this one.
-  Graph->GlobalsGraph->cloneGlobals(*Graph, /*cloneCalls*/ false);
-
-  // Save a copy of the original call nodes for the top-down pass
-  Graph->saveOrigFunctionCalls();
-
-  // Start resolving calls...
-  std::vector<std::vector<DSNodeHandle> > &FCs = Graph->getFunctionCalls();
-
-  DEBUG(std::cerr << "  [BU] Inlining: " << F.getName() << "\n");
-
-  // Add F to the PendingCallers list of each direct callee for use in the
-  // top-down pass so we don't have to compute this again.  We don't want
-  // to do it for indirect callees inlined later, so remember which calls
-  // are in the original FCs set.
-  std::set<const DSNode*> directCallees;
-  for (unsigned i = 0; i < FCs.size(); ++i)
-    directCallees.insert(FCs[i][1]); // ptr to function node
-
-  bool Inlined;
-  do {
-    Inlined = false;
-
-    for (unsigned i = 0; i != FCs.size(); ++i) {
-      // Copy the call, because inlining graphs may invalidate the FCs vector.
-      std::vector<DSNodeHandle> Call = FCs[i];
-
-      // If the function list is not incomplete...
-      if ((Call[1]->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[1]->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[0]) // Handle the return value if present...
-              Graph->RetNode->mergeWith(Call[0]);
-
-            // 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");
-
-            // 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.
-            std::map<Value*, DSNodeHandle> OldValMap;
-            std::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
-            DSNode *RetVal = Graph->cloneInto(GI, OldValMap, OldNodeMap,
-                                              /*StripScalars*/   true,
-                                              /*StripAllocas*/   true,
-                                              /*CopyCallers*/    false,
-                                              /*CopyOrigCalls*/  false);
-
-            ResolveArguments(Call, FI, OldValMap);
-
-            if (Call[0])  // Handle the return value if present
-              RetVal->mergeWith(Call[0]);
-
-            // Merge global value nodes in the inlined graph with the global
-            // value nodes in the current graph if there are duplicates.
-            //
-            MergeGlobalNodes(*Graph, OldValMap);
-
-            // If this was an original call, add F to the PendingCallers list
-            if (directCallees.find(Call[1]) != directCallees.end())
-              GI.addCaller(F);
-
-            // 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--);
-          }
-        }
+  DSGraph &Graph = getOrCreateGraph(F);
+
+  // The edges out of the current node are the call site targets...
+  for (DSCallSiteIterator I = DSCallSiteIterator::begin_aux(Graph),
+         E = DSCallSiteIterator::end_aux(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;
+  }
 
-        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[1]->getGlobals().size()) {
-          // Was able to inline SOME, but not all of the functions.  Construct a
-          // new global node here.
-          //
-          assert(0 && "Unimpl!");
-          Inlined = true;
+  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 = getDSGraph(*F);
+    DEBUG(std::cerr << "  [BU] Calculating graph for: " << F->getName()<< "\n");
+    calculateGraph(G);
+    DEBUG(std::cerr << "  [BU] Done inlining: " << F->getName() << " ["
+                    << G.getGraphSize() << "+" << G.getAuxFunctionCalls().size()
+                    << "]\n");
+
+    if (MaxSCC < 1) MaxSCC = 1;
+
+    // Should we revisit the graph?
+    if (DSCallSiteIterator::begin_aux(G) != DSCallSiteIterator::end_aux(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<DSGraph*> SCCGraphs;
+
+    Function *NF;
+    std::vector<Function*>::iterator FirstInSCC = Stack.end();
+    DSGraph *SCCGraph = 0;
+    do {
+      NF = *--FirstInSCC;
+      ValMap[NF] = ~0U;
+
+      // Figure out which graph is the largest one, in order to speed things up
+      // a bit in situations where functions in the SCC have widely different
+      // graph sizes.
+      DSGraph &NFGraph = getDSGraph(*NF);
+      SCCGraphs.insert(&NFGraph);
+      // FIXME: If we used a better way of cloning graphs (ie, just splice all
+      // of the nodes into the new graph), this would be completely unneeded!
+      if (!SCCGraph || SCCGraph->getGraphSize() < NFGraph.getGraphSize())
+        SCCGraph = &NFGraph;
+    } while (NF != F);
+
+    std::cerr << "Calculating graph for SCC #: " << MyID << " of size: "
+              << SCCGraphs.size() << "\n";
+
+    // Compute the Max SCC Size...
+    if (MaxSCC < SCCGraphs.size())
+      MaxSCC = SCCGraphs.size();
+
+    // First thing first, collapse all of the DSGraphs into a single graph for
+    // the entire SCC.  We computed the largest graph, so clone all of the other
+    // (smaller) graphs into it.  Discard all of the old graphs.
+    //
+    for (hash_set<DSGraph*>::iterator I = SCCGraphs.begin(),
+           E = SCCGraphs.end(); I != E; ++I) {
+      DSGraph &G = **I;
+      if (&G != SCCGraph) {
+        {
+          DSGraph::NodeMapTy NodeMap;
+          SCCGraph->cloneInto(G, SCCGraph->getScalarMap(),
+                              SCCGraph->getReturnNodes(), NodeMap);
         }
+        // Update the DSInfo map and delete the old graph...
+        for (DSGraph::ReturnNodesTy::iterator I = G.getReturnNodes().begin(),
+               E = G.getReturnNodes().end(); I != E; ++I)
+          DSInfo[I->first] = SCCGraph;
+        delete &G;
       }
     }
 
-    // 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*/ false, /*KeepCalls*/ true);
+    // Clean up the graph before we start inlining a bunch again...
+    SCCGraph->removeDeadNodes(DSGraph::RemoveUnreachableGlobals);
+
+    // Now that we have one big happy family, resolve all of the call sites in
+    // the graph...
+    calculateGraph(*SCCGraph);
+    DEBUG(std::cerr << "  [BU] Done inlining SCC  [" << SCCGraph->getGraphSize()
+                    << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n");
+
+    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<Function*, DSGraph*>::iterator I = DSInfo.begin(),
+         E = DSInfo.end(); I != E; ++I) {
+    I->second->getReturnNodes().erase(I->first);
+    if (I->second->getReturnNodes().empty())
+      delete I->second;
+  }
+
+  // Empty map so next time memory is released, data structures are not
+  // re-deleted.
+  DSInfo.clear();
+  delete GlobalsGraph;
+  GlobalsGraph = 0;
+}
+
+void BUDataStructures::calculateGraph(DSGraph &Graph) {
+  // 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);
+
+  DSGraph::ReturnNodesTy &ReturnNodes = Graph.getReturnNodes();
+
+  // Loop over all of the resolvable call sites
+  unsigned LastCallSiteIdx = ~0U;
+  for (DSCallSiteIterator I = DSCallSiteIterator::begin(TempFCs),
+         E = DSCallSiteIterator::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 (ReturnNodes.count(Callee)) {
+      // Self recursion... simply link up the formal arguments with the
+      // actual arguments...
+      DEBUG(std::cerr << "    Self Inlining: " << Callee->getName() << "\n");
+
+      // Handle self recursion by resolving the arguments and return value
+      Graph.mergeInGraph(CS, *Callee, Graph, 0);
+
+    } else {
+      ActualCallees.insert(std::make_pair(CS.getCallSite().getInstruction(),
+                                          Callee));
+
+      // 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 '"
+            << Graph.getFunctionNames() << "' [" << Graph.getGraphSize() << "+"
+            << Graph.getAuxFunctionCalls().size() << "]\n");
+      Graph.mergeInGraph(CS, *Callee, GI,
+                         DSGraph::KeepModRefBits | 
+                         DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes);
+      ++NumBUInlines;
+
+#if 0
+      Graph.writeGraphToFile(std::cerr, "bu_" + F.getName() + "_after_" +
+                             Callee->getName());
+#endif
     }
-  } while (Inlined && !FCs.empty());
+  }
 
-  // Copy any unresolved call nodes into the Globals graph and
-  // filter out unresolved call nodes inlined from the callee.
-  if (!FCs.empty())
-    Graph->GlobalsGraph->cloneCalls(*Graph);
+  // Make sure to catch any leftover unresolvable calls...
+  for (++LastCallSiteIdx; LastCallSiteIdx < TempFCs.size(); ++LastCallSiteIdx)
+    AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
 
-  Graph->maskIncompleteMarkers();
-  Graph->markIncompleteNodes();
-  Graph->removeDeadNodes(/*KeepAllGlobals*/ false, /*KeepCalls*/ false);
+  TempFCs.clear();
 
-  DEBUG(std::cerr << "  [BU] Done inlining: " << F.getName() << " ["
-        << Graph->getGraphSize() << "+" << Graph->getFunctionCalls().size()
-        << "]\n");
+  // Recompute the Incomplete markers
+  assert(Graph.getInlinedGlobals().empty());
+  Graph.maskIncompleteMarkers();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
 
-  return *Graph;
+  // Delete dead nodes.  Treat globals that are unreachable but that can
+  // reach live nodes as live.
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
+
+  // When this graph is finalized, clone the globals in the graph into the
+  // globals graph to make sure it has everything, from all graphs.
+  DSScalarMap &MainSM = Graph.getScalarMap();
+  ReachabilityCloner RC(*GlobalsGraph, Graph, DSGraph::StripAllocaBit);
+
+  // Clone everything reachable from globals in the "main" graph into the
+  // globals graph.
+  for (DSScalarMap::global_iterator I = MainSM.global_begin(),
+         E = MainSM.global_end(); I != E; ++I) 
+    RC.getClonedNH(MainSM[*I]);
+
+  //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
 }