[llvm-commits] [poolalloc] r113351 - in /poolalloc/trunk: include/poolalloc/PoolAllocate.h lib/PoolAllocate/PoolAllocate.cpp lib/PoolAllocate/TransformFunctionBody.cpp

John Criswell criswell at uiuc.edu
Tue Sep 7 22:50:10 PDT 2010


Author: criswell
Date: Wed Sep  8 00:50:10 2010
New Revision: 113351

URL: http://llvm.org/viewvc/llvm-project?rev=113351&view=rev
Log:
This commit fixes 254.gap on Mac OS X and should fix PR#8103.

First, when finding which arguments need pools, process an entire equivalence
class at a time.  This ensures that every function in an equivalence class has
the same DSNodes listed in MarkedNodes and ArgNodes in its FuncInfo, which
helps to transform the functions in the equivalence class uniformly.

Second, when transforming a call site, examine the target with the maximum
number of arguments.  This originaly helped prevent eliding a pool argument
because a particular target didn't need it.  I'm not convinced that this change
in TransformFunctionBody.cpp is needed (or correct), but it's not breaking
anything at the moment, so it goes in.


Modified:
    poolalloc/trunk/include/poolalloc/PoolAllocate.h
    poolalloc/trunk/lib/PoolAllocate/PoolAllocate.cpp
    poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp

Modified: poolalloc/trunk/include/poolalloc/PoolAllocate.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/poolalloc/PoolAllocate.h?rev=113351&r1=113350&r2=113351&view=diff
==============================================================================
--- poolalloc/trunk/include/poolalloc/PoolAllocate.h (original)
+++ poolalloc/trunk/include/poolalloc/PoolAllocate.h Wed Sep  8 00:50:10 2010
@@ -451,7 +451,7 @@
   /// FindFunctionPoolArgs - In the first pass over the program, we decide which
   /// arguments will have to be added for each function, build the FunctionInfo
   /// map and recording this info in the ArgNodes set.
-  void FindFunctionPoolArgs (Function &F);   
+  void FindFunctionPoolArgs (const std::vector<const Function *> & Funcs);   
   
   /// MakeFunctionClone - If the specified function needs to be modified for
   /// pool allocation support, make a clone of it, adding additional arguments

Modified: poolalloc/trunk/lib/PoolAllocate/PoolAllocate.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/PoolAllocate.cpp?rev=113351&r1=113350&r2=113351&view=diff
==============================================================================
--- poolalloc/trunk/lib/PoolAllocate/PoolAllocate.cpp (original)
+++ poolalloc/trunk/lib/PoolAllocate/PoolAllocate.cpp Wed Sep  8 00:50:10 2010
@@ -620,7 +620,7 @@
 }
 
 //
-// Function: MarkNodesWhichMustBePassedIn()
+// Function: RemoveGlobalNodes()
 //
 // Description:
 //  Given a function and its DSGraph, determine which values will need to have
@@ -695,50 +695,164 @@
 //
 void
 PoolAllocate::FindPoolArgs (Module & M) {
-  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
-    if (!I->isDeclaration() && Graphs->hasDSGraph(*I))
-      FindFunctionPoolArgs(*I);
+  //
+  // Scan through each equivalence class.  The Equivalence Class Bottom-Up
+  // pass guarantees that each function that is the target of an indirect
+  // function call will have the same DSGraph and will have identical DSNodes
+  // for corresponding arguments.  Therefore, we want to process all the
+  // functions in the same equivalence class once to avoid doing extra work.
+  //
+  EquivalenceClasses<const GlobalValue*> & GlobalECs = Graphs->getGlobalECs();
+  EquivalenceClasses<const GlobalValue*>::iterator EQSI = GlobalECs.begin();
+  EquivalenceClasses<const GlobalValue*>::iterator EQSE = GlobalECs.end();
+  for (;EQSI != EQSE; ++EQSI) {
+    //
+    // If this element is not a leader, then skip it.
+    //
+    if (!EQSI->isLeader()) continue;
+
+    //
+    // Iterate through all members of this equivalence class, looking for
+    // functions.  Record all of those functions which need to be processed.
+    //
+    std::vector<const Function *> Functions;
+    EquivalenceClasses<const GlobalValue*>::member_iterator MI;
+    for (MI=GlobalECs.member_begin(EQSI); MI != GlobalECs.member_end(); ++MI) {
+      if (const Function* F = dyn_cast<Function>(*MI)) {
+        //
+        // If the function has no body, then it has no DSGraph.
+        //
+        // FIXME: I don't believe this is correct; the stdlib pass can assign
+        //        DSGraphs to C standard library functions.
+        //
+        if (!(F->isDeclaration()))
+          Functions.push_back (F);
+      }
+    }
+
+    //
+    // Find the pool arguments for all of the functions in the equivalence
+    // class and construct the FuncInfo structure for each one.
+    //
+    FindFunctionPoolArgs (Functions);
+  }
+
+  //
+  // Make sure every function has a FuncInfo structure.
+  //
+  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+    if (!I->isDeclaration() && Graphs->hasDSGraph(*I)) {
+      if (FunctionInfo.find (I) == FunctionInfo.end()) {
+        FunctionInfo.insert(std::make_pair(I, FuncInfo(*I)));
+      }
+    }
+  }
+
+  return;
 }
 
 /// FindFunctionPoolArgs - In the first pass over the program, we decide which
 /// arguments will have to be added for each function, build the FunctionInfo
 /// map and recording this info in the ArgNodes set.
 void
-PoolAllocate::FindFunctionPoolArgs (Function & F) {
-  DSGraph* G = Graphs->getDSGraph(F);
+PoolAllocate::FindFunctionPoolArgs (const std::vector<const Function *> & Functions) {
+  //
+  // If there are no functions to process, then do nothing.
+  //
+  if (Functions.size() == 0)
+    return;
 
-  // Create a new entry for F.
-  FuncInfo &FI =
-    FunctionInfo.insert(std::make_pair(&F, FuncInfo(F))).first->second;
-  DenseSet<const DSNode*> &MarkedNodes = FI.MarkedNodes;
+  //
+  // Find all of the DSNodes which could possibly require a pool to be passed
+  // in.  Collect these DSNodes into one big container.
+  //
+  std::vector<DSNodeHandle> RootNodes;
+  for (unsigned index = 0; index < Functions.size(); ++index) {
+    //
+    // Get the DSGraph of the function.
+    //
+    const Function * F = Functions[index];
+    DSGraph* G = Graphs->getDSGraph (*F);
+
+    //
+    // Get all of the DSNodes which could possibly require a pool to be
+    // passed into the function.
+    //
+    G->getFunctionArgumentsForCall (F, RootNodes);
+  }
 
   //
-  // If there is no memory activity in this function, then nothing is required.
+  // If there is no memory activity in any of these functions, then nothing is
+  // required.
   //
-  if (G->node_begin() == G->node_end())
+  if (RootNodes.size() == 0)
     return;
 
   //
-  // Find all of the DSNodes which could require a pool to be passed into the
-  // function.
+  // Now find all nodes which are reachable from these DSNodes.
   //
-  std::vector<DSNodeHandle> Args;
-  G->getFunctionArgumentsForCall (&F, Args);
+  DenseSet<const DSNode*> MarkedNodes;
+  for (unsigned index = 0; index < RootNodes.size(); ++index) {
+    if (DSNode * N = RootNodes[index].getNode()) {
+      MarkedNodes.insert (N);
+      N->markReachableNodes(MarkedNodes);
+    }
+  }
 
-  // Find DataStructure nodes which are allocated in pools non-local to the
-  // current function.  This set will contain all of the DSNodes which require
-  // pools to be passed in from outside of the function.
-  MarkNodesWhichMustBePassedIn(MarkedNodes, Args, G, PassAllArguments);
+  //
+  // Determine which DSNodes are reachable from globals.  If a node is
+  // reachable from a global, we will create a global pool for it, so no
+  // argument passage is required.
+  //
+  DenseSet<const DSNode*> NodesFromGlobals;
+  for (unsigned index = 0; index < Functions.size(); ++index) {
+    //
+    // Get the DSGraph of the function.
+    //
+    const Function * F = Functions[index];
+    DSGraph* G = Graphs->getDSGraph(*F);
+    GetNodesReachableFromGlobals (G, NodesFromGlobals);
+  }
 
+  //
+  // Remove any nodes reachable from a global.  These nodes will be put into
+  // global pools, which do not require arguments to be passed in.  Also, erase
+  // any marked node that is not a heap node.  Since no allocations or frees
+  // will be done with it, it needs no argument.
+  //
+  // FIXME:
+  //  1) PassAllArguments seems to be ignored here.  Why is that?
+  //  2) Should the heap node check be part of the PassAllArguments check?
+  //  3) SAFECode probably needs to pass the pool even if it's not a heap node.
+  //     We should probably just do what the heuristic tells us to do.
+  //
+  for (DenseSet<const DSNode*>::iterator I = MarkedNodes.begin(),
+         E = MarkedNodes.end(); I != E; ) {
+    const DSNode *N = *I; ++I;
+    if ((!(1 || N->isHeapNode()) && !PassAllArguments) ||
+        NodesFromGlobals.count(N))
+      MarkedNodes.erase(N);
+  }
 
   //
-  // DenseSet does not have iterator traits, so we cannot use an insert()
-  // method that takes iterators.  Instead, we must use a loop to insert each
-  // element into ArgNodes one at a time.
+  // Create new FuncInfo entries for all of the functions.  Each one will have
+  // the same set of DSNodes passed in.
   //
-  for (DenseSet<const DSNode*>::iterator ii = MarkedNodes.begin(),
-       ee = MarkedNodes.end(); ii != ee; ++ii)
-    FI.ArgNodes.insert(FI.ArgNodes.end(), *ii);
+  for (unsigned index = 0; index < Functions.size(); ++index) {
+    Function * F = (Function *) Functions[index];
+    FuncInfo & FI =
+            FunctionInfo.insert(std::make_pair(F, FuncInfo(*F))).first->second;
+    //
+    // DenseSet does not have iterator traits, so we cannot use an insert()
+    // method that takes iterators.  Instead, we must use a loop to insert each
+    // element into MarkedNodes and ArgNodes one at a time.
+    //
+    for (DenseSet<const DSNode*>::iterator ii = MarkedNodes.begin(),
+         ee = MarkedNodes.end(); ii != ee; ++ii) {
+      FI.MarkedNodes.insert(*ii);
+      FI.ArgNodes.insert(FI.ArgNodes.end(), *ii);
+    }
+  }
 }
 
 //

Modified: poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp?rev=113351&r1=113350&r2=113351&view=diff
==============================================================================
--- poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp (original)
+++ poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp Wed Sep  8 00:50:10 2010
@@ -855,10 +855,30 @@
     // sure to use the original call site from the original function; the
     // points-to analysis has no information on the clones we've created.
     //
+    // Also, look for the target that has the greatest number of arguments that
+    // have associated DSNodes.  This ensures that we pass the maximum number
+    // of pools possible and prevents us from eliding a pool because we're
+    // examining a target that doesn't need it.
+    //
     const DSCallGraph & callGraph = Graphs.getCallGraph();
+    unsigned maxArgsWithNodes = 0;
     DSCallGraph::callee_iterator I = callGraph.callee_begin(OrigInst);
-    if (I != callGraph.callee_end(OrigInst))
-      CF = *I;
+    for (; I != callGraph.callee_end(OrigInst); ++I) {
+      //
+      // Get the information for this function.  Since this is coming from DSA,
+      // it should be an original function.
+      //
+      FuncInfo *CFI = PAInfo.getFuncInfo(**I);
+
+      //
+      // If this target takes more DSNodes than the last one we found, then
+      // make *this* target our canonical target.
+      //
+      if (CFI->ArgNodes.size() > maxArgsWithNodes) {
+        maxArgsWithNodes = CFI->ArgNodes.size();
+        CF = *I;
+      }
+    }
 
     //
     // If we didn't find the callee in the constructed call graph, try





More information about the llvm-commits mailing list