[llvm-commits] CVS: llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp

Andrew Lenharth alenhar2 at cs.uiuc.edu
Mon Jun 19 11:23:11 PDT 2006



Changes in directory llvm/lib/Analysis/DataStructure:

BottomUpClosure.cpp updated: 1.118 -> 1.119
---
Log message:

Do partial inlining in BU.  This resolves more call sites.  Also add options to merge in globals during recursion and to back annotate DSNodes when function pointers are resolved.  This makes PA work for a whole lot more things (unresolved call sites being what has been killing various DSA based passes)

---
Diffs of the changes:  (+171 -61)

 BottomUpClosure.cpp |  232 ++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 171 insertions(+), 61 deletions(-)


Index: llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp
diff -u llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp:1.118 llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp:1.119
--- llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp:1.118	Wed Apr 19 10:33:35 2006
+++ llvm/lib/Analysis/DataStructure/BottomUpClosure.cpp	Mon Jun 19 13:22:59 2006
@@ -13,11 +13,13 @@
 // applications like alias analysis.
 //
 //===----------------------------------------------------------------------===//
-
+#define DEBUG_TYPE "bu_dsa"
 #include "llvm/Analysis/DataStructure/DataStructure.h"
 #include "llvm/Analysis/DataStructure/DSGraph.h"
 #include "llvm/Module.h"
+#include "llvm/DerivedTypes.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Timer.h"
 #include <iostream>
@@ -28,10 +30,20 @@
   Statistic<> NumBUInlines("budatastructures", "Number of graphs inlined");
   Statistic<> NumCallEdges("budatastructures", "Number of 'actual' call edges");
 
+  cl::opt<bool>
+  AddGlobals("budatastructures-annotate-calls",
+	     cl::desc("Annotate call sites with functions as they are resolved"));
+  cl::opt<bool>
+  UpdateGlobals("budatastructures-update-from-globals",
+		cl::desc("Update local graph from global graph when processing function"));
+
   RegisterAnalysis<BUDataStructures>
   X("budatastructure", "Bottom-up Data Structure Analysis");
 }
 
+static bool GetAllCallees(const DSCallSite &CS,
+                          std::vector<Function*> &Callees);
+
 /// BuildGlobalECs - Look at all of the nodes in the globals graph.  If any node
 /// contains multiple globals, DSA will never, ever, be able to tell the globals
 /// apart.  Instead of maintaining this information in all of the graphs
@@ -114,6 +126,26 @@
   DEBUG(if(MadeChange) G.AssertGraphOK());
 }
 
+static void AddGlobalToNode(BUDataStructures* B, DSCallSite D, Function* F) {
+  if(!AddGlobals)
+    return;
+  if(D.isIndirectCall()) {
+    DSGraph* GI = &B->getDSGraph(D.getCaller());
+    DSNodeHandle& NHF = GI->getNodeForValue(F);
+    DSCallSite DL = GI->getDSCallSiteForCallSite(D.getCallSite());
+    if (DL.getCalleeNode() != NHF.getNode() || NHF.isNull()) {
+      if (NHF.isNull()) {
+        DSNode *N = new DSNode(F->getType()->getElementType(), GI);   // Create the node
+        N->addGlobal(F);
+        NHF.setTo(N,0);
+        DEBUG(std::cerr << "Adding " << F->getName() << " to a call node in "
+             << D.getCaller().getName() << "\n");
+      }
+      DL.getCalleeNode()->mergeWith(NHF, 0);
+    }
+  }
+}
+
 // run - Calculate the bottom up data structure graphs for each function in the
 // program.
 //
@@ -132,6 +164,7 @@
   unsigned NextID = 1;
 
   Function *MainFunc = M.getMainFunction();
+
   if (MainFunc)
     calculateGraphs(MainFunc, Stack, NextID, ValMap);
 
@@ -146,8 +179,6 @@
       calculateGraphs(I, Stack, NextID, ValMap);     // Calculate all graphs.
     }
 
-  NumCallEdges += ActualCallees.size();
-
   // If we computed any temporary indcallgraphs, free them now.
   for (std::map<std::vector<Function*>,
          std::pair<DSGraph*, std::vector<DSNodeHandle> > >::iterator I =
@@ -187,9 +218,8 @@
   if (MainFunc && !MainFunc->isExternal()) {
     DSGraph &MainGraph = getOrCreateGraph(MainFunc);
     const DSGraph &GG = *MainGraph.getGlobalsGraph();
-    ReachabilityCloner RC(MainGraph, GG,
-                          DSGraph::DontCloneCallNodes |
-                          DSGraph::DontCloneAuxCallNodes);
+    ReachabilityCloner RC(MainGraph, GG, DSGraph::DontCloneCallNodes |
+			  DSGraph::DontCloneAuxCallNodes);
 
     // Clone the global nodes into this graph.
     for (DSScalarMap::global_iterator I = GG.getScalarMap().global_begin(),
@@ -200,8 +230,26 @@
     MainGraph.maskIncompleteMarkers();
     MainGraph.markIncompleteNodes(DSGraph::MarkFormalArgs |
                                   DSGraph::IgnoreGlobals);
+
+    //Debug messages if along the way we didn't resolve a call site
+    //also update the call graph and callsites we did find.
+    for(DSGraph::afc_iterator ii = MainGraph.afc_begin(),
+	  ee = MainGraph.afc_end(); ii != ee; ++ii) {
+      std::vector<Function*> Funcs;
+      GetAllCallees(*ii, Funcs);
+      std::cerr << "Lost site\n";
+      for (std::vector<Function*>::iterator iif = Funcs.begin(), eef = Funcs.end();
+	   iif != eef; ++iif) {
+	AddGlobalToNode(this, *ii, *iif);
+	std::cerr << "Adding\n";
+	ActualCallees.insert(std::make_pair(ii->getCallSite().getInstruction(), *iif));
+      }
+    }
+
   }
 
+  NumCallEdges += ActualCallees.size();
+
   return false;
 }
 
@@ -236,26 +284,33 @@
   return !callee->isExternal() || isVAHackFn(callee);
 }
 
-static void GetAllCallees(const DSCallSite &CS,
+//returns true if all callees were resolved
+static bool GetAllCallees(const DSCallSite &CS,
                           std::vector<Function*> &Callees) {
   if (CS.isDirectCall()) {
-    if (isResolvableFunc(CS.getCalleeFunc()))
+    if (isResolvableFunc(CS.getCalleeFunc())) {
       Callees.push_back(CS.getCalleeFunc());
-  } else if (!CS.getCalleeNode()->isIncomplete()) {
+      return true;
+    } else
+      return false;
+  } else {
     // Get all callees.
+    bool retval = CS.getCalleeNode()->isComplete();
     unsigned OldSize = Callees.size();
     CS.getCalleeNode()->addFullFunctionList(Callees);
 
-    // If any of the callees are unresolvable, remove the whole batch!
-    for (unsigned i = OldSize, e = Callees.size(); i != e; ++i)
+    // If any of the callees are unresolvable, remove that one
+    for (unsigned i = OldSize; i != Callees.size(); ++i)
       if (!isResolvableFunc(Callees[i])) {
-        Callees.erase(Callees.begin()+OldSize, Callees.end());
-        return;
+        Callees.erase(Callees.begin()+i);
+        --i;
+       retval = false;
       }
+    return retval;
+    //return false;
   }
 }
 
-
 /// GetAllAuxCallees - Return a list containing all of the resolvable callees in
 /// the aux list for the specified graph in the Callees vector.
 static void GetAllAuxCallees(DSGraph &G, std::vector<Function*> &Callees) {
@@ -267,7 +322,7 @@
 unsigned BUDataStructures::calculateGraphs(Function *F,
                                            std::vector<Function*> &Stack,
                                            unsigned &NextID,
-                                     hash_map<Function*, unsigned> &ValMap) {
+					   hash_map<Function*, unsigned> &ValMap) {
   assert(!ValMap.count(F) && "Shouldn't revisit functions!");
   unsigned Min = NextID++, MyID = Min;
   ValMap[F] = Min;
@@ -284,6 +339,8 @@
   }
 
   DSGraph &Graph = getOrCreateGraph(F);
+  if (UpdateGlobals)
+    Graph.updateFromGlobalGraph();
 
   // Find all callee functions.
   std::vector<Function*> CalleeFunctions;
@@ -313,7 +370,7 @@
     Stack.pop_back();
     DSGraph &G = getDSGraph(*F);
     DEBUG(std::cerr << "  [BU] Calculating graph for: " << F->getName()<< "\n");
-    calculateGraph(G);
+    bool redo = calculateGraph(G);
     DEBUG(std::cerr << "  [BU] Done inlining: " << F->getName() << " ["
                     << G.getGraphSize() << "+" << G.getAuxFunctionCalls().size()
                     << "]\n");
@@ -322,8 +379,8 @@
 
     // Should we revisit the graph?  Only do it if there are now new resolvable
     // callees.
-    GetAllAuxCallees(Graph, CalleeFunctions);
-    if (!CalleeFunctions.empty()) {
+    if (redo) {
+      DEBUG(std::cerr << "Recalculating " << F->getName() << " due to new knowledge\n");
       ValMap.erase(F);
       return calculateGraphs(F, Stack, NextID, ValMap);
     } else {
@@ -376,10 +433,14 @@
 
     // Now that we have one big happy family, resolve all of the call sites in
     // the graph...
-    calculateGraph(SCCGraph);
+    bool redo = calculateGraph(SCCGraph);
     DEBUG(std::cerr << "  [BU] Done inlining SCC  [" << SCCGraph.getGraphSize()
                     << "+" << SCCGraph.getAuxFunctionCalls().size() << "]\n");
 
+    if (redo) {
+      DEBUG(std::cerr << "MISSING REDO\n");
+    }
+
     std::cerr << "DONE with SCC #: " << MyID << "\n";
 
     // We never have to revisit "SCC" processed functions...
@@ -434,7 +495,7 @@
 }
 
 
-void BUDataStructures::calculateGraph(DSGraph &Graph) {
+bool BUDataStructures::calculateGraph(DSGraph &Graph) {
   // If this graph contains the main function, clone the globals graph into this
   // graph before we inline callees and other fun stuff.
   bool ContainsMain = false;
@@ -470,42 +531,27 @@
   std::list<DSCallSite> TempFCs;
   std::list<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
   TempFCs.swap(AuxCallsList);
+  //remember what we've seen (or will see)
+  unsigned oldSize = TempFCs.size();
 
   bool Printed = false;
-  std::vector<Function*> CalledFuncs;
+  bool missingNode = false;
+
   while (!TempFCs.empty()) {
     DSCallSite &CS = *TempFCs.begin();
-
-    CalledFuncs.clear();
+    Instruction *TheCall = CS.getCallSite().getInstruction();
+    DSGraph *GI;
 
     // Fast path for noop calls.  Note that we don't care about merging globals
     // in the callee with nodes in the caller here.
-    if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0) {
-      TempFCs.erase(TempFCs.begin());
-      continue;
-    } else if (CS.isDirectCall() && isVAHackFn(CS.getCalleeFunc())) {
-      TempFCs.erase(TempFCs.begin());
-      continue;
-    }
-
-    GetAllCallees(CS, CalledFuncs);
-
-    if (CalledFuncs.empty()) {
-      // Remember that we could not resolve this yet!
-      AuxCallsList.splice(AuxCallsList.end(), TempFCs, TempFCs.begin());
-      continue;
-    } else {
-      DSGraph *GI;
-      Instruction *TheCall = CS.getCallSite().getInstruction();
-
-      if (CalledFuncs.size() == 1) {
-        Function *Callee = CalledFuncs[0];
+    if (CS.isDirectCall()) {
+      if (!isVAHackFn(CS.getCalleeFunc()) && isResolvableFunc(CS.getCalleeFunc())) {
+        Function* Callee = CS.getCalleeFunc();
         ActualCallees.insert(std::make_pair(TheCall, Callee));
-
-        // Get the data structure graph for the called function.
+	
+        assert(doneDSGraph(Callee) && "Direct calls should always be precomputed");
         GI = &getDSGraph(*Callee);  // Graph to inline
         DEBUG(std::cerr << "    Inlining graph for " << Callee->getName());
-
         DEBUG(std::cerr << "[" << GI->getGraphSize() << "+"
               << GI->getAuxFunctionCalls().size() << "] into '"
               << Graph.getFunctionNames() << "' [" << Graph.getGraphSize() <<"+"
@@ -514,22 +560,38 @@
                            DSGraph::StripAllocaBit|DSGraph::DontCloneCallNodes);
         ++NumBUInlines;
       } else {
+        DEBUG(std::cerr << "Graph " << Graph.getFunctionNames() << " Call Site " <<
+              CS.getCallSite().getInstruction() << " never resolvable\n");
+      }
+      --oldSize;
+      TempFCs.pop_front();
+      continue;
+    } else {
+      std::vector<Function*> CalledFuncs;
+      bool resolved = GetAllCallees(CS, CalledFuncs);
+
+      if (CalledFuncs.empty()) {
+        DEBUG(std::cerr << "Graph " << Graph.getFunctionNames() << " Call Site " <<
+              CS.getCallSite().getInstruction() << " delayed\n");
+      } else {
+        DEBUG(
         if (!Printed)
           std::cerr << "In Fns: " << Graph.getFunctionNames() << "\n";
         std::cerr << "  calls " << CalledFuncs.size()
                   << " fns from site: " << CS.getCallSite().getInstruction()
                   << "  " << *CS.getCallSite().getInstruction();
         std::cerr << "   Fns =";
+        );
         unsigned NumPrinted = 0;
 
         for (std::vector<Function*>::iterator I = CalledFuncs.begin(),
                E = CalledFuncs.end(); I != E; ++I) {
-          if (NumPrinted++ < 8) std::cerr << " " << (*I)->getName();
+          DEBUG(if (NumPrinted++ < 8) std::cerr << " " << (*I)->getName(););
 
           // Add the call edges to the call graph.
           ActualCallees.insert(std::make_pair(TheCall, *I));
         }
-        std::cerr << "\n";
+        DEBUG(std::cerr << "\n");
 
         // See if we already computed a graph for this set of callees.
         std::sort(CalledFuncs.begin(), CalledFuncs.end());
@@ -541,6 +603,14 @@
             E = CalledFuncs.end();
 
           // Start with a copy of the first graph.
+          if (!doneDSGraph(*I)) {
+            AuxCallsList.splice(AuxCallsList.end(), TempFCs, TempFCs.begin());
+            missingNode = true;
+            continue;
+          }
+
+          AddGlobalToNode(this, CS, *I);
+
           GI = IndCallGraph.first = new DSGraph(getDSGraph(**I), GlobalECs);
           GI->setGlobalsGraph(Graph.getGlobalsGraph());
           std::vector<DSNodeHandle> &Args = IndCallGraph.second;
@@ -550,10 +620,17 @@
           GI->getFunctionArgumentsForCall(*I, Args);
 
           // Merge all of the other callees into this graph.
-          for (++I; I != E; ++I) {
+          bool locMissing = false;
+          for (++I; I != E && !locMissing; ++I) {
+            AddGlobalToNode(this, CS, *I);
             // If the graph already contains the nodes for the function, don't
             // bother merging it in again.
             if (!GI->containsFunction(*I)) {
+              if (!doneDSGraph(*I)) {
+                locMissing = true;
+                break;
+              }
+
               GI->cloneInto(getDSGraph(**I));
               ++NumBUInlines;
             }
@@ -568,29 +645,44 @@
             for (e = NextArgs.size(); i != e; ++i)
               Args.push_back(NextArgs[i]);
           }
+          if (locMissing) {
+            AuxCallsList.splice(AuxCallsList.end(), TempFCs, TempFCs.begin());
+            missingNode = true;
+            continue;
+          }
 
           // Clean up the final graph!
           GI->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
         } else {
-          std::cerr << "***\n*** RECYCLED GRAPH ***\n***\n";
+          DEBUG(std::cerr << "***\n*** RECYCLED GRAPH ***\n***\n");
+          for (std::vector<Function*>::iterator I = CalledFuncs.begin(), E = CalledFuncs.end(); I != E; ++I) {
+            AddGlobalToNode(this, CS, *I);
+          }
         }
 
         GI = IndCallGraph.first;
 
-        // Merge the unified graph into this graph now.
-        DEBUG(std::cerr << "    Inlining multi callee graph "
-              << "[" << GI->getGraphSize() << "+"
-              << GI->getAuxFunctionCalls().size() << "] into '"
-              << Graph.getFunctionNames() << "' [" << Graph.getGraphSize() <<"+"
-              << Graph.getAuxFunctionCalls().size() << "]\n");
+        if (AlreadyInlined[CS.getCallSite()] != CalledFuncs) {
+         AlreadyInlined[CS.getCallSite()].swap(CalledFuncs);
 
-        Graph.mergeInGraph(CS, IndCallGraph.second, *GI,
-                           DSGraph::StripAllocaBit |
-                           DSGraph::DontCloneCallNodes);
-        ++NumBUInlines;
+          // Merge the unified graph into this graph now.
+          DEBUG(std::cerr << "    Inlining multi callee graph "
+                << "[" << GI->getGraphSize() << "+"
+                << GI->getAuxFunctionCalls().size() << "] into '"
+                << Graph.getFunctionNames() << "' [" << Graph.getGraphSize() <<"+"
+                << Graph.getAuxFunctionCalls().size() << "]\n");
+
+          Graph.mergeInGraph(CS, IndCallGraph.second, *GI,
+                             DSGraph::StripAllocaBit |
+                             DSGraph::DontCloneCallNodes);
+
+          ++NumBUInlines;
+        } else {
+          DEBUG(std::cerr << "   Skipping already inlined graph\n");
+        }
       }
+      AuxCallsList.splice(AuxCallsList.end(), TempFCs, TempFCs.begin());
     }
-    TempFCs.erase(TempFCs.begin());
   }
 
   // Recompute the Incomplete markers
@@ -613,6 +705,24 @@
     RC.getClonedNH(MainSM[*I]);
 
   //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
+  AuxCallsList.sort();
+  AuxCallsList.unique();
+  //conditionally prune the call list keeping only one copy of each actual
+  //CallSite
+  if (AuxCallsList.size() > 100) {
+    DEBUG(std::cerr << "Reducing Aux from " << AuxCallsList.size());
+    std::map<CallSite, std::list<DSCallSite>::iterator> keepers;
+    TempFCs.swap(AuxCallsList);
+    for( std::list<DSCallSite>::iterator ii = TempFCs.begin(), ee = TempFCs.end();
+         ii != ee; ++ii)
+      keepers[ii->getCallSite()] = ii;
+    for (std::map<CallSite, std::list<DSCallSite>::iterator>::iterator
+           ii = keepers.begin(), ee = keepers.end();
+         ii != ee; ++ii)
+      AuxCallsList.splice(AuxCallsList.end(), TempFCs, ii->second);
+    DEBUG(std::cerr << " to " << AuxCallsList.size() << "\n");
+  }
+  return missingNode || oldSize != AuxCallsList.size();
 }
 
 static const Function *getFnForValue(const Value *V) {






More information about the llvm-commits mailing list