Move some warnings to debug mode.
[oota-llvm.git] / lib / Analysis / DataStructure / TopDownClosure.cpp
index 8c0db6dc552a07a6315c286c1c7265fcd09ab111..55a37dbcd164ea3409d42c97b675fef7b979aa52 100644 (file)
@@ -1,10 +1,10 @@
 //===- TopDownClosure.cpp - Compute the top-down interprocedure 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 TDDataStructures class, which represents the
 #include "llvm/DerivedTypes.h"
 #include "llvm/Analysis/DataStructure/DSGraph.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Timer.h"
 #include "llvm/ADT/Statistic.h"
+#include <iostream>
 using namespace llvm;
 
+#if 0
+#define TIME_REGION(VARNAME, DESC) \
+   NamedRegionTimer VARNAME(DESC)
+#else
+#define TIME_REGION(VARNAME, DESC)
+#endif
+
 namespace {
-  RegisterAnalysis<TDDataStructures>   // Register the pass
+  RegisterPass<TDDataStructures>   // Register the pass
   Y("tddatastructure", "Top-down Data Structure Analysis");
 
   Statistic<> NumTDInlines("tddatastructures", "Number of graphs inlined");
@@ -37,11 +46,9 @@ void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode *N,
   for (unsigned i = 0, e = N->getNumLinks(); i != e; ++i) {
     DSNodeHandle &NH = N->getLink(i*N->getPointerSize());
     if (DSNode *NN = NH.getNode()) {
-      const std::vector<GlobalValue*> &Globals = NN->getGlobals();
-      for (unsigned G = 0, e = Globals.size(); G != e; ++G)
-        if (Function *F = dyn_cast<Function>(Globals[G]))
-          ArgsRemainIncomplete.insert(F);
-
+      std::vector<Function*> Functions;
+      NN->addFullFunctionList(Functions);
+      ArgsRemainIncomplete.insert(Functions.begin(), Functions.end());
       markReachableFunctionsExternallyAccessible(NN, Visited);
     }
   }
@@ -52,8 +59,9 @@ void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode *N,
 // program.
 //
 bool TDDataStructures::runOnModule(Module &M) {
-  BUDataStructures &BU = getAnalysis<BUDataStructures>();
-  GlobalsGraph = new DSGraph(BU.getGlobalsGraph());
+  BUInfo = &getAnalysis<BUDataStructures>();
+  GlobalECs = BUInfo->getGlobalECs();
+  GlobalsGraph = new DSGraph(BUInfo->getGlobalsGraph(), GlobalECs);
   GlobalsGraph->setPrintAuxCalls();
 
   // Figure out which functions must not mark their arguments complete because
@@ -63,9 +71,11 @@ bool TDDataStructures::runOnModule(Module &M) {
   const DSScalarMap &GGSM = GlobalsGraph->getScalarMap();
   hash_set<DSNode*> Visited;
   for (DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end();
-       I != E; ++I)
-    markReachableFunctionsExternallyAccessible(GGSM.find(*I)->second.getNode(),
-                                               Visited);
+       I != E; ++I) {
+    DSNode *N = GGSM.find(*I)->second.getNode();
+    if (N->isIncomplete())
+      markReachableFunctionsExternallyAccessible(N, Visited);
+  }
 
   // Loop over unresolved call nodes.  Any functions passed into (but not
   // returned!) from unresolvable call nodes may be invoked outside of the
@@ -86,24 +96,47 @@ bool TDDataStructures::runOnModule(Module &M) {
   // calculate a post-order traversal, then reverse it.
   hash_set<DSGraph*> VisitedGraph;
   std::vector<DSGraph*> PostOrder;
-  const BUDataStructures::ActualCalleesTy &ActualCallees = 
-    getAnalysis<BUDataStructures>().getActualCallees();
+
+#if 0
+{TIME_REGION(XXX, "td:Copy graphs");
+
+  // Visit each of the graphs in reverse post-order now!
+  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+    if (!I->isExternal())
+      getOrCreateDSGraph(*I);
+  return false;
+}
+#endif
+
+
+{TIME_REGION(XXX, "td:Compute postorder");
 
   // Calculate top-down from main...
   if (Function *F = M.getMainFunction())
-    ComputePostOrder(*F, VisitedGraph, PostOrder, ActualCallees);
+    ComputePostOrder(*F, VisitedGraph, PostOrder);
 
   // Next calculate the graphs for each unreachable function...
   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
-    ComputePostOrder(*I, VisitedGraph, PostOrder, ActualCallees);
+    ComputePostOrder(*I, VisitedGraph, PostOrder);
 
   VisitedGraph.clear();   // Release memory!
+}
+
+{TIME_REGION(XXX, "td:Inline stuff");
 
   // Visit each of the graphs in reverse post-order now!
   while (!PostOrder.empty()) {
-    inlineGraphIntoCallees(*PostOrder.back());
+    InlineCallersIntoGraph(*PostOrder.back());
     PostOrder.pop_back();
   }
+}
+
+  // Free the IndCallMap.
+  while (!IndCallMap.empty()) {
+    delete IndCallMap.begin()->second;
+    IndCallMap.erase(IndCallMap.begin());
+  }
+
 
   ArgsRemainIncomplete.clear();
   GlobalsGraph->removeTriviallyDeadNodes();
@@ -115,33 +148,36 @@ bool TDDataStructures::runOnModule(Module &M) {
 DSGraph &TDDataStructures::getOrCreateDSGraph(Function &F) {
   DSGraph *&G = DSInfo[&F];
   if (G == 0) { // Not created yet?  Clone BU graph...
-    G = new DSGraph(getAnalysis<BUDataStructures>().getDSGraph(F));
-    G->getAuxFunctionCalls().clear();
+    G = new DSGraph(getAnalysis<BUDataStructures>().getDSGraph(F), GlobalECs,
+                    DSGraph::DontCloneAuxCallNodes);
+    assert(G->getAuxFunctionCalls().empty() && "Cloned aux calls?");
     G->setPrintAuxCalls();
     G->setGlobalsGraph(GlobalsGraph);
+
+    // Note that this graph is the graph for ALL of the function in the SCC, not
+    // just F.
+    for (DSGraph::retnodes_iterator RI = G->retnodes_begin(),
+           E = G->retnodes_end(); RI != E; ++RI)
+      if (RI->first != &F)
+        DSInfo[RI->first] = G;
   }
   return *G;
 }
 
 
 void TDDataStructures::ComputePostOrder(Function &F,hash_set<DSGraph*> &Visited,
-                                        std::vector<DSGraph*> &PostOrder,
-                      const BUDataStructures::ActualCalleesTy &ActualCallees) {
+                                        std::vector<DSGraph*> &PostOrder) {
   if (F.isExternal()) return;
   DSGraph &G = getOrCreateDSGraph(F);
   if (Visited.count(&G)) return;
   Visited.insert(&G);
-  
+
   // Recursively traverse all of the callee graphs.
-  for (DSGraph::fc_iterator CI = G.fc_begin(), E = G.fc_end(); CI != E; ++CI) {
+  for (DSGraph::fc_iterator CI = G.fc_begin(), CE = G.fc_end(); CI != CE; ++CI){
     Instruction *CallI = CI->getCallSite().getInstruction();
-    std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
-      BUDataStructures::ActualCalleesTy::const_iterator>
-         IP = ActualCallees.equal_range(CallI);
-
-    for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first;
-         I != IP.second; ++I)
-      ComputePostOrder(*I->second, Visited, PostOrder, ActualCallees);
+    for (BUDataStructures::callee_iterator I = BUInfo->callee_begin(CallI),
+           E = BUInfo->callee_end(CallI); I != E; ++I)
+      ComputePostOrder(*I->second, Visited, PostOrder);
   }
 
   PostOrder.push_back(&G);
@@ -172,121 +208,206 @@ void TDDataStructures::releaseMyMemory() {
   GlobalsGraph = 0;
 }
 
-void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) {
-  // Recompute the Incomplete markers and eliminate unreachable nodes.
-  Graph.maskIncompleteMarkers();
+/// InlineCallersIntoGraph - Inline all of the callers of the specified DS graph
+/// into it, then recompute completeness of nodes in the resultant graph.
+void TDDataStructures::InlineCallersIntoGraph(DSGraph &DSG) {
+  // Inline caller graphs into this graph.  First step, get the list of call
+  // sites that call into this graph.
+  std::vector<CallerCallEdge> EdgesFromCaller;
+  std::map<DSGraph*, std::vector<CallerCallEdge> >::iterator
+    CEI = CallerEdges.find(&DSG);
+  if (CEI != CallerEdges.end()) {
+    std::swap(CEI->second, EdgesFromCaller);
+    CallerEdges.erase(CEI);
+  }
+
+  // Sort the caller sites to provide a by-caller-graph ordering.
+  std::sort(EdgesFromCaller.begin(), EdgesFromCaller.end());
+
+
+  // Merge information from the globals graph into this graph.  FIXME: This is
+  // stupid.  Instead of us cloning information from the GG into this graph,
+  // then having RemoveDeadNodes clone it back, we should do all of this as a
+  // post-pass over all of the graphs.  We need to take cloning out of
+  // removeDeadNodes and gut removeDeadNodes at the same time first though. :(
+  {
+    DSGraph &GG = *DSG.getGlobalsGraph();
+    ReachabilityCloner RC(DSG, GG,
+                          DSGraph::DontCloneCallNodes |
+                          DSGraph::DontCloneAuxCallNodes);
+    for (DSScalarMap::global_iterator
+           GI = DSG.getScalarMap().global_begin(),
+           E = DSG.getScalarMap().global_end(); GI != E; ++GI)
+      RC.getClonedNH(GG.getNodeForValue(*GI));
+  }
+
+  DEBUG(std::cerr << "[TD] Inlining callers into '" << DSG.getFunctionNames()
+        << "'\n");
+
+  // Iteratively inline caller graphs into this graph.
+  while (!EdgesFromCaller.empty()) {
+    DSGraph &CallerGraph = *EdgesFromCaller.back().CallerGraph;
+
+    // Iterate through all of the call sites of this graph, cloning and merging
+    // any nodes required by the call.
+    ReachabilityCloner RC(DSG, CallerGraph,
+                          DSGraph::DontCloneCallNodes |
+                          DSGraph::DontCloneAuxCallNodes);
+
+    // Inline all call sites from this caller graph.
+    do {
+      const DSCallSite &CS = *EdgesFromCaller.back().CS;
+      Function &CF = *EdgesFromCaller.back().CalledFunction;
+      DEBUG(std::cerr << "   [TD] Inlining graph into Fn '"
+            << CF.getName() << "' from ");
+      if (CallerGraph.getReturnNodes().empty())
+        DEBUG(std::cerr << "SYNTHESIZED INDIRECT GRAPH");
+      else
+        DEBUG (std::cerr << "Fn '"
+               << CS.getCallSite().getInstruction()->
+               getParent()->getParent()->getName() << "'");
+      DEBUG(std::cerr << ": " << CF.getFunctionType()->getNumParams()
+            << " args\n");
+
+      // Get the formal argument and return nodes for the called function and
+      // merge them with the cloned subgraph.
+      DSCallSite T1 = DSG.getCallSiteForArguments(CF);
+      RC.mergeCallSite(T1, CS);
+      ++NumTDInlines;
+
+      EdgesFromCaller.pop_back();
+    } while (!EdgesFromCaller.empty() &&
+             EdgesFromCaller.back().CallerGraph == &CallerGraph);
+  }
+
+
+  // Next, now that this graph is finalized, we need to recompute the
+  // incompleteness markers for this graph and remove unreachable nodes.
+  DSG.maskIncompleteMarkers();
 
   // If any of the functions has incomplete incoming arguments, don't mark any
   // of them as complete.
   bool HasIncompleteArgs = false;
-  const DSGraph::ReturnNodesTy &GraphReturnNodes = Graph.getReturnNodes();
-  for (DSGraph::ReturnNodesTy::const_iterator I = GraphReturnNodes.begin(),
-         E = GraphReturnNodes.end(); I != E; ++I)
+  for (DSGraph::retnodes_iterator I = DSG.retnodes_begin(),
+         E = DSG.retnodes_end(); I != E; ++I)
     if (ArgsRemainIncomplete.count(I->first)) {
       HasIncompleteArgs = true;
       break;
     }
 
-  // Now fold in the necessary globals from the GlobalsGraph.  A global G
-  // must be folded in if it exists in the current graph (i.e., is not dead)
-  // and it was not inlined from any of my callers.  If it was inlined from
-  // a caller, it would have been fully consistent with the GlobalsGraph
-  // in the caller so folding in is not necessary.  Otherwise, this node came
-  // solely from this function's BU graph and so has to be made consistent.
-  // 
-  Graph.updateFromGlobalGraph();
-
   // Recompute the Incomplete markers.  Depends on whether args are complete
   unsigned Flags
     = HasIncompleteArgs ? DSGraph::MarkFormalArgs : DSGraph::IgnoreFormalArgs;
-  Graph.markIncompleteNodes(Flags | DSGraph::IgnoreGlobals);
+  DSG.markIncompleteNodes(Flags | DSGraph::IgnoreGlobals);
 
   // Delete dead nodes.  Treat globals that are unreachable as dead also.
-  Graph.removeDeadNodes(DSGraph::RemoveUnreachableGlobals);
-
-  // We are done with computing the current TD Graph! Now move on to
-  // inlining the current graph into the graphs for its callees, if any.
-  // 
-  if (Graph.fc_begin() == Graph.fc_end()) {
-    DEBUG(std::cerr << "  [TD] No callees for: " << Graph.getFunctionNames()
-                    << "\n");
-    return;
-  }
+  DSG.removeDeadNodes(DSGraph::RemoveUnreachableGlobals);
 
-  // Now that we have information about all of the callees, propagate the
-  // current graph into the callees.  Clone only the reachable subgraph at
-  // each call-site, not the entire graph (even though the entire graph
-  // would be cloned only once, this should still be better on average).
-  //
-  DEBUG(std::cerr << "  [TD] Inlining '" << Graph.getFunctionNames() <<"' into "
-                  << Graph.getFunctionCalls().size() << " call nodes.\n");
+  // We are done with computing the current TD Graph!  Finally, before we can
+  // finish processing this function, we figure out which functions it calls and
+  // records these call graph edges, so that we have them when we process the
+  // callee graphs.
+  if (DSG.fc_begin() == DSG.fc_end()) return;
 
-  const BUDataStructures::ActualCalleesTy &ActualCallees =
-    getAnalysis<BUDataStructures>().getActualCallees();
+  // Loop over all the call sites and all the callees at each call site, and add
+  // edges to the CallerEdges structure for each callee.
+  for (DSGraph::fc_iterator CI = DSG.fc_begin(), E = DSG.fc_end();
+       CI != E; ++CI) {
 
-  // Loop over all the call sites and all the callees at each call site.  Build
-  // a mapping from called DSGraph's to the call sites in this function that
-  // invoke them.  This is useful because we can be more efficient if there are
-  // multiple call sites to the callees in the graph from this caller.
-  std::multimap<DSGraph*, std::pair<Function*, const DSCallSite*> > CallSites;
+    // Handle direct calls efficiently.
+    if (CI->isDirectCall()) {
+      if (!CI->getCalleeFunc()->isExternal() &&
+          !DSG.getReturnNodes().count(CI->getCalleeFunc()))
+        CallerEdges[&getDSGraph(*CI->getCalleeFunc())]
+          .push_back(CallerCallEdge(&DSG, &*CI, CI->getCalleeFunc()));
+      continue;
+    }
 
-  for (DSGraph::fc_iterator CI = Graph.fc_begin(), E = Graph.fc_end();
-       CI != E; ++CI) {
     Instruction *CallI = CI->getCallSite().getInstruction();
     // For each function in the invoked function list at this call site...
-    std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
-              BUDataStructures::ActualCalleesTy::const_iterator> 
-      IP = ActualCallees.equal_range(CallI);
-    // Loop over each actual callee at this call site
-    for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first;
-         I != IP.second; ++I) {
-      DSGraph& CalleeGraph = getDSGraph(*I->second);
-      assert(&CalleeGraph != &Graph && "TD need not inline graph into self!");
-
-      CallSites.insert(std::make_pair(&CalleeGraph,
-                                      std::make_pair(I->second, &*CI)));
+    BUDataStructures::callee_iterator IPI =
+      BUInfo->callee_begin(CallI), IPE = BUInfo->callee_end(CallI);
+
+    // Skip over all calls to this graph (SCC calls).
+    while (IPI != IPE && &getDSGraph(*IPI->second) == &DSG)
+      ++IPI;
+
+    // All SCC calls?
+    if (IPI == IPE) continue;
+
+    Function *FirstCallee = IPI->second;
+    ++IPI;
+
+    // Skip over more SCC calls.
+    while (IPI != IPE && &getDSGraph(*IPI->second) == &DSG)
+      ++IPI;
+
+    // If there is exactly one callee from this call site, remember the edge in
+    // CallerEdges.
+    if (IPI == IPE) {
+      if (!FirstCallee->isExternal())
+        CallerEdges[&getDSGraph(*FirstCallee)]
+          .push_back(CallerCallEdge(&DSG, &*CI, FirstCallee));
+      continue;
     }
-  }
-
-  // Now that we built the mapping, actually perform the inlining a callee graph
-  // at a time.
-  std::multimap<DSGraph*,std::pair<Function*,const DSCallSite*> >::iterator CSI;
-  for (CSI = CallSites.begin(); CSI != CallSites.end(); ) {
-    DSGraph &CalleeGraph = *CSI->first;
-    // Iterate through all of the call sites of this graph, cloning and merging
-    // any nodes required by the call.
-    ReachabilityCloner RC(CalleeGraph, Graph, DSGraph::StripModRefBits);
 
-    // Clone over any global nodes that appear in both graphs.
-    for (DSScalarMap::global_iterator
-           SI = CalleeGraph.getScalarMap().global_begin(),
-           SE = CalleeGraph.getScalarMap().global_end(); SI != SE; ++SI) {
-      DSScalarMap::const_iterator GI = Graph.getScalarMap().find(*SI);
-      if (GI != Graph.getScalarMap().end())
-        RC.merge(CalleeGraph.getNodeForValue(*SI), GI->second);
+    // Otherwise, there are multiple callees from this call site, so it must be
+    // an indirect call.  Chances are that there will be other call sites with
+    // this set of targets.  If so, we don't want to do M*N inlining operations,
+    // so we build up a new, private, graph that represents the calls of all
+    // calls to this set of functions.
+    std::vector<Function*> Callees;
+    for (BUDataStructures::ActualCalleesTy::const_iterator I =
+           BUInfo->callee_begin(CallI), E = BUInfo->callee_end(CallI);
+         I != E; ++I)
+      if (!I->second->isExternal())
+        Callees.push_back(I->second);
+    std::sort(Callees.begin(), Callees.end());
+
+    std::map<std::vector<Function*>, DSGraph*>::iterator IndCallRecI =
+      IndCallMap.lower_bound(Callees);
+
+    DSGraph *IndCallGraph;
+
+    // If we already have this graph, recycle it.
+    if (IndCallRecI != IndCallMap.end() && IndCallRecI->first == Callees) {
+      DEBUG(std::cerr << "  [TD] *** Reuse of indcall graph for " << Callees.size()
+            << " callees!\n");
+      IndCallGraph = IndCallRecI->second;
+    } else {
+      // Otherwise, create a new DSGraph to represent this.
+      IndCallGraph = new DSGraph(DSG.getGlobalECs(), DSG.getTargetData());
+
+      // Make a nullary dummy call site, which will eventually get some content
+      // merged into it.  The actual callee function doesn't matter here, so we
+      // just pass it something to keep the ctor happy.
+      std::vector<DSNodeHandle> ArgDummyVec;
+      DSCallSite DummyCS(CI->getCallSite(), DSNodeHandle(), Callees[0]/*dummy*/,
+                         ArgDummyVec);
+      IndCallGraph->getFunctionCalls().push_back(DummyCS);
+
+      IndCallRecI = IndCallMap.insert(IndCallRecI,
+                                      std::make_pair(Callees, IndCallGraph));
+
+      // Additionally, make sure that each of the callees inlines this graph
+      // exactly once.
+      DSCallSite *NCS = &IndCallGraph->getFunctionCalls().front();
+      for (unsigned i = 0, e = Callees.size(); i != e; ++i) {
+        DSGraph& CalleeGraph = getDSGraph(*Callees[i]);
+        if (&CalleeGraph != &DSG)
+          CallerEdges[&CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS,
+                                                             Callees[i]));
+      }
     }
 
-    // Loop over all of the distinct call sites in the caller of the callee.
-    for (; CSI != CallSites.end() && CSI->first == &CalleeGraph; ++CSI) {
-      Function &CF = *CSI->second.first;
-      const DSCallSite &CS = *CSI->second.second;
-      DEBUG(std::cerr << "     [TD] Resolving arguments for callee graph '"
-            << CalleeGraph.getFunctionNames()
-            << "': " << CF.getFunctionType()->getNumParams()
-            << " args\n          at call site (DSCallSite*) 0x" << &CS << "\n");
-      
-      // Get the formal argument and return nodes for the called function and
-      // merge them with the cloned subgraph.
-      RC.mergeCallSite(CalleeGraph.getCallSiteForArguments(CF), CS);
-      ++NumTDInlines;
-    }
+    // Now that we know which graph to use for this, merge the caller
+    // information into the graph, based on information from the call site.
+    ReachabilityCloner RC(*IndCallGraph, DSG, 0);
+    RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(), *CI);
   }
-
-  DEBUG(std::cerr << "  [TD] Done inlining into callees for: "
-        << Graph.getFunctionNames() << " [" << Graph.getGraphSize() << "+"
-        << Graph.getFunctionCalls().size() << "]\n");
 }
 
+
 static const Function *getFnForValue(const Value *V) {
   if (const Instruction *I = dyn_cast<Instruction>(V))
     return I->getParent()->getParent();
@@ -304,7 +425,7 @@ void TDDataStructures::deleteValue(Value *V) {
     return;
   }
 
-  if (Function *F = dyn_cast<Function>(F)) {
+  if (Function *F = dyn_cast<Function>(V)) {
     assert(getDSGraph(*F).getReturnNodes().size() == 1 &&
            "cannot handle scc's");
     delete DSInfo[F];
@@ -326,16 +447,25 @@ void TDDataStructures::copyValue(Value *From, Value *To) {
   if (Function *FromF = dyn_cast<Function>(From)) {
     Function *ToF = cast<Function>(To);
     assert(!DSInfo.count(ToF) && "New Function already exists!");
-    DSGraph *NG = new DSGraph(getDSGraph(*FromF));
+    DSGraph *NG = new DSGraph(getDSGraph(*FromF), GlobalECs);
     DSInfo[ToF] = NG;
     assert(NG->getReturnNodes().size() == 1 && "Cannot copy SCC's yet!");
 
     // Change the Function* is the returnnodes map to the ToF.
-    DSNodeHandle Ret = NG->getReturnNodes().begin()->second;
+    DSNodeHandle Ret = NG->retnodes_begin()->second;
     NG->getReturnNodes().clear();
     NG->getReturnNodes()[ToF] = Ret;
     return;
   }
 
-  assert(!isa<GlobalVariable>(From) && "Do not know how to copy GV's yet!");
+  if (const Function *F = getFnForValue(To)) {
+    DSGraph &G = getDSGraph(*F);
+    G.getScalarMap().copyScalarIfExists(From, To);
+    return;
+  }
+
+  std::cerr << *From;
+  std::cerr << *To;
+  assert(0 && "Do not know how to copy this yet!");
+  abort();
 }