[llvm-commits] [poolalloc] r111015 - in /poolalloc/trunk: include/dsa/DataStructure.h lib/DSA/BottomUpClosure.cpp

John Criswell criswell at uiuc.edu
Fri Aug 13 08:22:24 PDT 2010


Author: criswell
Date: Fri Aug 13 10:22:23 2010
New Revision: 111015

URL: http://llvm.org/viewvc/llvm-project?rev=111015&view=rev
Log:
Revert back to the original DSA algorithm described in the PLDI paper.  The
important feature of this change is that the DSCallGraph is not used to perform
bottom-up traversal of the call graph because the DSCallGraph is being computed
during the bottom-up traversal process.

Modified:
    poolalloc/trunk/include/dsa/DataStructure.h
    poolalloc/trunk/lib/DSA/BottomUpClosure.cpp

Modified: poolalloc/trunk/include/dsa/DataStructure.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DataStructure.h?rev=111015&r1=111014&r2=111015&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/DataStructure.h (original)
+++ poolalloc/trunk/include/dsa/DataStructure.h Fri Aug 13 10:22:23 2010
@@ -235,7 +235,16 @@
   bool runOnModuleInternal(Module &M);
 
 private:
+  // Private typedefs
+  typedef std::map<const Function*, unsigned> TarjanMap;
+  typedef std::vector<const Function*>        TarjanStack;
+
   void mergeSCCs();
+  void postOrderInline (Module & M);
+  unsigned calculateGraphs (const Function *F,
+                            TarjanStack & Stack,
+                            unsigned & NextID,
+                            TarjanMap & ValMap);
   DSGraph* postOrder(const Function*,
                      svset<const Function*>& marked);
   

Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=111015&r1=111014&r2=111015&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original)
+++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Fri Aug 13 10:22:23 2010
@@ -69,14 +69,27 @@
   callgraph.buildSCCs();
   callgraph.buildRoots();
 
+#if 0
   //
   // Merge the DSGraphs of functions belonging to an SCC.
   //
   mergeSCCs();
+#endif
+
+  //
+  // Make sure we have a DSGraph for all declared functions in the Module.
+  // While we may not need them in this DSA pass, a later DSA pass may ask us
+  // for their DSGraphs, and we want to have them if asked.
+  //
+  for (Module::iterator F = M.begin(); F != M.end(); ++F) {
+    if (!(F->isDeclaration()))
+      getOrCreateGraph(F);
+  }
 
   //
   // Do a post-order traversal of the SCC callgraph and do bottom-up inlining.
   //
+#if 0
   {
     //errs() << *DSG.knownRoots.begin() << " -> " << *DSG.knownRoots.rbegin() << "\n";
     svset<const Function*> marked;
@@ -97,6 +110,9 @@
       CloneAuxIntoGlobal(G);
     }
   }
+#else
+  postOrderInline (M);
+#endif
 
 
   std::vector<const Function*> EntryPoints;
@@ -139,6 +155,13 @@
 
   NumCallEdges += callgraph.size();
 
+  //
+  // Put the callgraph into canonical form by finding SCCs.  It has been
+  // updated since we did this last.
+  //
+  callgraph.buildSCCs();
+  callgraph.buildRoots();
+
   return false;
 }
 
@@ -186,6 +209,271 @@
 }
 
 //
+// Function: GetAllCallees()
+//
+// Description:
+//  Given a DSCallSite, add to the list the functions that can be called by
+//  the call site *if* it is resolvable.
+//
+static void
+GetAllCallees(const DSCallSite &CS, std::vector<const Function*> &Callees) {
+  //
+  // FIXME: Should we check for the Unknown flag on indirect call sites?
+  //
+  // Direct calls to functions that have bodies are always resolvable.
+  // Indirect function calls that are for a complete call site (the analysis
+  // knows everything about the call site) and do not target external functions
+  // are also resolvable.
+  //
+  if (CS.isDirectCall()) {
+    if (!CS.getCalleeFunc()->isDeclaration())
+      Callees.push_back(CS.getCalleeFunc());
+  } else if (!CS.getCalleeNode()->isIncompleteNode()) {
+    // Get all callees.
+    if (!CS.getCalleeNode()->isExternFuncNode())
+      CS.getCalleeNode()->addFullFunctionList(Callees);
+  }
+}
+
+//
+// Function: GetAllAuxCallees()
+//
+// Description:
+//  Return a list containing all of the resolvable callees in the auxiliary
+//  list for the specified graph in the Callees vector.
+//
+// Inputs:
+//  G - The DSGraph for which the callers wants a list of resolvable call
+//      sites.
+//
+// Outputs:
+//  Callees - A list of all functions that can be called from resolvable call
+//            sites.  This list is always cleared by this function before any
+//            functions are added to it.
+//
+static void
+GetAllAuxCallees (DSGraph* G, std::vector<const Function*> & Callees) {
+  //
+  // Clear out the list of callees.
+  //
+  Callees.clear();
+  for (DSGraph::afc_iterator I = G->afc_begin(), E = G->afc_end(); I != E; ++I)
+    GetAllCallees(*I, Callees);
+}
+
+//
+// Method: postOrderInline()
+//
+// Description:
+//  This methods does a post order traversal of the call graph and performs
+//  bottom-up inlining of the DSGraphs.
+//
+void
+BUDataStructures::postOrderInline (Module & M) {
+  // Variables used for Tarjan SCC-finding algorithm.  These are passed into
+  // the recursive function used to find SCCs.
+  std::vector<const Function*> Stack;
+  std::map<const Function*, unsigned> ValMap;
+  unsigned NextID = 1;
+
+  //
+  // Start the post order traversal with the main() function.  If there is no
+  // main() function, don't worry; we'll have a separate traversal for inlining
+  // graphs for functions not reachable from main().
+  //
+  Function *MainFunc = M.getFunction ("main");
+  if (MainFunc && !MainFunc->isDeclaration()) {
+    calculateGraphs(MainFunc, Stack, NextID, ValMap);
+    CloneAuxIntoGlobal(getDSGraph(*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->isDeclaration() && !hasDSGraph(*I)) {
+      if (MainFunc)
+        DEBUG(errs() << debugname << ": Function unreachable from main: "
+        << I->getName() << "\n");
+      calculateGraphs(I, Stack, NextID, ValMap);     // Calculate all graphs.
+      CloneAuxIntoGlobal(getDSGraph(*I));
+    }
+
+  return;
+}
+
+//
+// Method: calculateGraphs()
+//
+// Description:
+//  Perform recursive bottom-up inlining of DSGraphs from callee to caller.
+//
+// Inputs:
+//  F - The function which should have its callees' DSGraphs merged into its
+//      own DSGraph.
+//  Stack - The stack used for Tarjan's SCC-finding algorithm.
+//  NextID - The nextID value used for Tarjan's SCC-finding algorithm.
+//  ValMap - The map used for Tarjan's SCC-finding algorithm.
+//
+// Return value:
+//
+unsigned
+BUDataStructures::calculateGraphs (const Function *F,
+                                   TarjanStack & Stack,
+                                   unsigned & NextID,
+                                   TarjanMap & 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->isDeclaration()) {   // sprintf, fprintf, sscanf, etc...
+    // No callees!
+    Stack.pop_back();
+    ValMap[F] = ~0;
+    return Min;
+  }
+
+  //
+  // Get the DSGraph of the current function.  Make one if one doesn't exist.
+  //
+  DSGraph* Graph = getOrCreateGraph(F);
+
+  //
+  // Find all callee functions.  Use the DSGraph for this (do not use the call
+  // graph (DSCallgraph) as we're still in the process of constructing it).
+  //
+  std::vector<const Function*> CalleeFunctions;
+  GetAllAuxCallees(Graph, CalleeFunctions);
+
+  //
+  // Iterate through each call target (these are the edges out of the current
+  // node (i.e., the current function) in Tarjan graph parlance).  Find the
+  // minimum assigned ID.
+  //
+  for (unsigned i = 0, e = CalleeFunctions.size(); i != e; ++i) {
+    const Function *Callee = CalleeFunctions[i];
+    unsigned M;
+    //
+    // If we have not visited this callee before, visit it now (this is the
+    // post-order component of the Bottom-Up algorithm).  Otherwise, look up
+    // the assigned ID value from the Tarjan Value Map.
+    //
+    TarjanMap::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 we've found a function with a smaller ID than this funtion, record
+    // that ID as the minimum ID.
+    //
+    if (M < Min) Min = M;
+  }
+
+  assert(ValMap[F] == MyID && "SCC construction assumption wrong!");
+
+  //
+  // If the minimum ID found is not this function's ID, then this function is
+  // part of a larger SCC.
+  //
+  if (Min != MyID)
+    return Min;
+
+  //
+  // If this is a new SCC, process it now.
+  //
+  if (Stack.back() == F) {           // Special case the single "SCC" case here.
+    DEBUG(errs() << "Visiting single node SCC #: " << MyID << " fn: "
+	  << F->getName() << "\n");
+    Stack.pop_back();
+    DEBUG(errs() << "  [BU] Calculating graph for: " << F->getName()<< "\n");
+    calculateGraph (Graph);
+    DEBUG(errs() << "  [BU] Done inlining: " << F->getName() << " ["
+	  << Graph->getGraphSize() << "+" << Graph->getAuxFunctionCalls().size()
+	  << "]\n");
+
+    if (MaxSCC < 1) MaxSCC = 1;
+
+    //
+    // Should we revisit the graph?  Only do it if there are now new resolvable
+    // callees.
+    GetAllAuxCallees (Graph, CalleeFunctions);
+    if (!CalleeFunctions.empty()) {
+      DEBUG(errs() << "Recalculating " << F->getName() << " due to new knowledge\n");
+      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
+    //
+    std::vector<DSGraph*> SCCGraphs;
+
+    unsigned SCCSize = 1;
+    const Function *NF = Stack.back();
+    ValMap[NF] = ~0U;
+    DSGraph* SCCGraph = getDSGraph(*NF);
+
+    //
+    // First thing first: collapse all of the DSGraphs into a single graph for
+    // the entire SCC.  Splice all of the graphs into one and discard all of
+    // the old graphs.
+    //
+    while (NF != F) {
+      Stack.pop_back();
+      NF = Stack.back();
+      ValMap[NF] = ~0U;
+
+      DSGraph* NFG = getDSGraph(*NF);
+
+      if (NFG != SCCGraph) {
+        // Update the Function -> DSG map.
+        for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(),
+               E = NFG->retnodes_end(); I != E; ++I)
+          setDSGraph(*I->first, SCCGraph);
+        
+        SCCGraph->spliceFrom(NFG);
+        delete NFG;
+        ++SCCSize;
+      }
+    }
+    Stack.pop_back();
+
+    DEBUG(errs() << "Calculating graph for SCC #: " << MyID << " of size: "
+	  << SCCSize << "\n");
+
+    // Compute the Max SCC Size.
+    if (MaxSCC < SCCSize)
+      MaxSCC = SCCSize;
+
+    // Clean up the graph before we start inlining a bunch again...
+    SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
+
+    // Now that we have one big happy family, resolve all of the call sites in
+    // the graph...
+    calculateGraph(SCCGraph);
+    DEBUG(errs() << "  [BU] Done inlining SCC  [" << SCCGraph->getGraphSize()
+	  << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n"
+	  << "DONE with SCC #: " << MyID << "\n");
+
+    // We never have to revisit "SCC" processed functions...
+    return MyID;
+  }
+
+  return MyID;  // == Min
+}
+
+//
 // Method: postOrder()
 //
 // Description:
@@ -461,6 +749,11 @@
 
   cloneIntoGlobals(Graph);
   //Graph.writeGraphToFile(cerr, "bu_" + F.getName());
+
+  //
+  // Update the callgraph with the new information that we have gleaned.
+  //
+  Graph->buildCallGraph(callgraph);
 }
 
 //For Entry Points





More information about the llvm-commits mailing list