[llvm-commits] CVS: poolalloc/lib/PoolAllocate/PoolAllocate.cpp

Chris Lattner lattner at cs.uiuc.edu
Mon Nov 10 23:11:01 PST 2003


Changes in directory poolalloc/lib/PoolAllocate:

PoolAllocate.cpp updated: 1.44 -> 1.45

---
Log message:

Implement global pools more efficiently by making the pool descriptors global 
variables, which do not need to be passed around as arguments!

Also, add a PASS_ALL_ARGUMENTS macro that safecode can use to get arguments
passed into functions which do not call malloc and free, but use the memory
objects in some way.



---
Diffs of the changes:  (+212 -122)

Index: poolalloc/lib/PoolAllocate/PoolAllocate.cpp
diff -u poolalloc/lib/PoolAllocate/PoolAllocate.cpp:1.44 poolalloc/lib/PoolAllocate/PoolAllocate.cpp:1.45
--- poolalloc/lib/PoolAllocate/PoolAllocate.cpp:1.44	Mon Nov 10 18:47:53 2003
+++ poolalloc/lib/PoolAllocate/PoolAllocate.cpp	Mon Nov 10 23:10:27 2003
@@ -24,6 +24,12 @@
 #include "Support/Statistic.h"
 using namespace PA;
 
+// PASS_ALL_ARGUMENTS - If this is set to true, pass in pool descriptors for all
+// DSNodes in a function, even if there are no allocations or frees in it.  This
+// is useful for SafeCode.
+#define PASS_ALL_ARGUMENTS 0
+
+
 const Type *PoolAllocate::PoolDescPtrTy = 0;
 
 namespace {
@@ -54,6 +60,93 @@
   AU.addRequired<TargetData>();
 }
 
+bool PoolAllocate::run(Module &M) {
+  if (M.begin() == M.end()) return false;
+  CurModule = &M;
+  BU = &getAnalysis<BUDataStructures>();
+
+  AddPoolPrototypes();
+  BuildIndirectFunctionSets(M);
+
+  if (SetupGlobalPools(M))
+    return true;
+
+  // Loop over the functions in the original program finding the pool desc.
+  // arguments necessary for each function that is indirectly callable.
+  // For each equivalence class, make a list of pool arguments and update
+  // the PoolArgFirst and PoolArgLast values for each function.
+  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+    if (!I->isExternal())
+      FindFunctionPoolArgs(*I);
+
+  std::map<Function*, Function*> FuncMap;
+
+  // Now clone a function using the pool arg list obtained in the previous pass
+  // over the modules.  Loop over only the function initially in the program,
+  // don't traverse newly added ones.  If the function needs new arguments, make
+  // its clone.
+  Module::iterator LastOrigFunction = --M.end();
+  for (Module::iterator I = M.begin(); ; ++I) {
+    if (!I->isExternal())
+      if (Function *R = MakeFunctionClone(*I))
+        FuncMap[I] = R;
+    if (I == LastOrigFunction) break;
+  }
+  
+  ++LastOrigFunction;
+
+  // Now that all call targets are available, rewrite the function bodies of the
+  // clones.
+  for (Module::iterator I = M.begin(); I != LastOrigFunction; ++I)
+    if (!I->isExternal()) {
+      std::map<Function*, Function*>::iterator FI = FuncMap.find(I);
+      ProcessFunctionBody(*I, FI != FuncMap.end() ? *FI->second : *I);
+    }
+
+  return true;
+}
+
+static void GetNodesReachableFromGlobals(DSGraph &G,
+                                         hash_set<DSNode*> &NodesFromGlobals) {
+  for (DSGraph::ScalarMapTy::iterator I = G.getScalarMap().begin(), 
+         E = G.getScalarMap().end(); I != E; ++I)
+    if (isa<GlobalValue>(I->first))              // Found a global
+      I->second.getNode()->markReachableNodes(NodesFromGlobals);
+}
+
+// AddPoolPrototypes - Add prototypes for the pool functions to the specified
+// module and update the Pool* instance variables to point to them.
+//
+void PoolAllocate::AddPoolPrototypes() {
+  if (VoidPtrTy == 0) {
+    VoidPtrTy = PointerType::get(Type::SByteTy);
+    PoolDescType =
+      StructType::get(make_vector<const Type*>(VoidPtrTy, VoidPtrTy,
+                                               Type::UIntTy, Type::UIntTy, 0));
+    PoolDescPtrTy = PointerType::get(PoolDescType);
+  }
+
+  CurModule->addTypeName("PoolDescriptor", PoolDescType);
+  
+  // Get poolinit function...
+  PoolInit = CurModule->getOrInsertFunction("poolinit", Type::VoidTy,
+                                            PoolDescPtrTy, Type::UIntTy, 0);
+
+  // Get pooldestroy function...
+  PoolDestroy = CurModule->getOrInsertFunction("pooldestroy", Type::VoidTy,
+                                               PoolDescPtrTy, 0);
+  
+  // The poolalloc function
+  PoolAlloc = CurModule->getOrInsertFunction("poolalloc", 
+                                             VoidPtrTy, PoolDescPtrTy,
+                                             Type::UIntTy, 0);
+  
+  // Get the poolfree function...
+  PoolFree = CurModule->getOrInsertFunction("poolfree", Type::VoidTy,
+                                            PoolDescPtrTy, VoidPtrTy, 0);  
+}
+
+
 // Prints out the functions mapped to the leader of the equivalence class they
 // belong to.
 void PoolAllocate::printFuncECs() {
@@ -75,14 +168,13 @@
   }
 }
 
-void PoolAllocate::buildIndirectFunctionSets(Module &M) {
-  // Iterate over the module looking for indirect calls to functions
-
+// BuildIndirectFunctionSets - Iterate over the module looking for indirect
+// calls to functions
+void PoolAllocate::BuildIndirectFunctionSets(Module &M) {
   // Get top down DSGraph for the functions
   TDDS = &getAnalysis<TDDataStructures>();
   
   for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
-
     DEBUG(std::cerr << "Processing indirect calls function:" <<  MI->getName()
                     << "\n");
 
@@ -128,83 +220,70 @@
   DEBUG(printFuncECs());
 }
 
-bool PoolAllocate::run(Module &M) {
-  if (M.begin() == M.end()) return false;
-  CurModule = &M;
-  BU = &getAnalysis<BUDataStructures>();
-
-  if (VoidPtrTy == 0) {
-    VoidPtrTy = PointerType::get(Type::SByteTy);
-    PoolDescType =
-      StructType::get(make_vector<const Type*>(VoidPtrTy, VoidPtrTy,
-                                               Type::UIntTy, Type::UIntTy, 0));
-    PoolDescPtrTy = PointerType::get(PoolDescType);
+// SetupGlobalPools - Create global pools for all DSNodes in the globals graph
+// which contain heap objects.  If a global variable points to a piece of memory
+// allocated from the heap, this pool gets a global lifetime.  This is
+// implemented by making the pool descriptor be a global variable of it's own,
+// and initializing the pool on entrance to main.  Note that we never destroy
+// the pool, because it has global lifetime.
+//
+// This method returns true if correct pool allocation of the module cannot be
+// performed because there is no main function for the module and there are
+// global pools.
+//
+bool PoolAllocate::SetupGlobalPools(Module &M) {
+  // Get the globals graph for the program.
+  DSGraph &GG = BU->getGlobalsGraph();
+
+  // Get all of the nodes reachable from globals.
+  hash_set<DSNode*> GlobalHeapNodes;
+  GetNodesReachableFromGlobals(GG, GlobalHeapNodes);
+
+  // Filter out all nodes which have no heap allocations merged into them.
+  for (hash_set<DSNode*>::iterator I = GlobalHeapNodes.begin(),
+         E = GlobalHeapNodes.end(); I != E; ) {
+    hash_set<DSNode*>::iterator Last = I++;
+    if (!(*Last)->isHeapNode())
+      GlobalHeapNodes.erase(Last);
+  }
+  
+  // If we don't need to create any global pools, exit now.
+  if (GlobalHeapNodes.empty()) return false;
+
+  // Otherwise get the main function to insert the poolinit calls.
+  Function *MainFunc = M.getMainFunction();
+  if (MainFunc == 0 || MainFunc->isExternal()) {
+    std::cerr << "Cannot pool allocate this program: it has global "
+              << "pools but no 'main' function yet!\n";
+    return true;
   }
-  
-  AddPoolPrototypes();
-  buildIndirectFunctionSets(M);
 
-  std::map<Function*, Function*> FuncMap;
+  BasicBlock::iterator InsertPt = MainFunc->getEntryBlock().begin();
+  while (isa<AllocaInst>(InsertPt)) ++InsertPt;
+  
+  TargetData &TD = getAnalysis<TargetData>();
 
-  // Loop over the functions in the original program finding the pool desc.
-  // arguments necessary for each function that is indirectly callable.
-  // For each equivalence class, make a list of pool arguments and update
-  // the PoolArgFirst and PoolArgLast values for each function.
-  Module::iterator LastOrigFunction = --M.end();
-  for (Module::iterator I = M.begin(); ; ++I) {
-    if (!I->isExternal())
-      FindFunctionPoolArgs(*I);
-    if (I == LastOrigFunction) break;
-  }
+  // Loop over all of the pools, creating a new global pool descriptor,
+  // inserting a new entry in GlobalNodes, and inserting a call to poolinit in
+  // main.
+  for (hash_set<DSNode*>::iterator I = GlobalHeapNodes.begin(),
+         E = GlobalHeapNodes.end(); I != E; ++I) {
+    GlobalVariable *GV =
+      new GlobalVariable(PoolDescType, false, GlobalValue::InternalLinkage, 
+                         Constant::getNullValue(PoolDescType), "GlobalPool",&M);
+    GlobalNodes[*I] = GV;
 
-  // Now clone a function using the pool arg list obtained in the previous
-  // pass over the modules.
-  // Loop over only the function initially in the program, don't traverse newly
-  // added ones.  If the function uses memory, make its clone.
-  for (Module::iterator I = M.begin(); ; ++I) {
-    if (!I->isExternal())
-      if (Function *R = MakeFunctionClone(*I))
-        FuncMap[I] = R;
-    if (I == LastOrigFunction) break;
+    Value *ElSize =
+      ConstantUInt::get(Type::UIntTy, (*I)->getType()->isSized() ? 
+                        TD.getTypeSize((*I)->getType()) : 4);
+    new CallInst(PoolInit, make_vector((Value*)GV, ElSize, 0), "", InsertPt);
   }
-  
-  ++LastOrigFunction;
 
-  // Now that all call targets are available, rewrite the function bodies of the
-  // clones.
-  for (Module::iterator I = M.begin(); I != LastOrigFunction; ++I)
-    if (!I->isExternal()) {
-      std::map<Function*, Function*>::iterator FI = FuncMap.find(I);
-      ProcessFunctionBody(*I, FI != FuncMap.end() ? *FI->second : *I);
-    }
-
-  return true;
+  return false;
 }
 
 
-// AddPoolPrototypes - Add prototypes for the pool functions to the specified
-// module and update the Pool* instance variables to point to them.
-//
-void PoolAllocate::AddPoolPrototypes() {
-  CurModule->addTypeName("PoolDescriptor", PoolDescType);
-  
-  // Get poolinit function...
-  PoolInit = CurModule->getOrInsertFunction("poolinit", Type::VoidTy,
-                                            PoolDescPtrTy, Type::UIntTy, 0);
 
-  // Get pooldestroy function...
-  PoolDestroy = CurModule->getOrInsertFunction("pooldestroy", Type::VoidTy,
-                                               PoolDescPtrTy, 0);
-  
-  // The poolalloc function
-  PoolAlloc = CurModule->getOrInsertFunction("poolalloc", 
-                                             VoidPtrTy, PoolDescPtrTy,
-                                             Type::UIntTy, 0);
-  
-  // Get the poolfree function...
-  PoolFree = CurModule->getOrInsertFunction("poolfree", Type::VoidTy,
-                                            PoolDescPtrTy, VoidPtrTy, 0);  
-}
 
 // Inline the DSGraphs of functions corresponding to the potential targets at
 // indirect call sites into the DS Graph of the callee.
@@ -252,41 +331,24 @@
 }
 
 void PoolAllocate::FindFunctionPoolArgs(Function &F) {
-
   DSGraph &G = BU->getDSGraph(F);
  
   // Inline the potential targets of indirect calls
   hash_set<Function*> visitedFuncs;
   InlineIndirectCalls(F, G, visitedFuncs);
 
-  // The DSGraph is merged with the globals graph. 
-  G.mergeInGlobalsGraph();
-
-  // The nodes reachable from globals need to be recognized as potential 
-  // arguments. This is required because, upon merging in the globals graph,
-  // the nodes pointed to by globals that are not live are not marked 
-  // incomplete.
-  hash_set<DSNode*> NodesFromGlobals;
-  for (DSGraph::ScalarMapTy::iterator I = G.getScalarMap().begin(), 
-	 E = G.getScalarMap().end(); I != E; ++I)
-    if (isa<GlobalValue>(I->first)) {             // Found a global
-      DSNodeHandle &GH = I->second;
-      GH.getNode()->markReachableNodes(NodesFromGlobals);
-    }
-
   // At this point the DS Graphs have been modified in place including
-  // information about globals as well as indirect calls, making it useful
-  // for pool allocation
+  // information about indirect calls, making it useful for pool allocation.
   std::vector<DSNode*> &Nodes = G.getNodes();
-  if (Nodes.empty()) return ;  // No memory activity, nothing is required
+  if (Nodes.empty()) return;  // No memory activity, nothing is required
 
   FuncInfo &FI = FunctionInfo[&F];   // Create a new entry for F
   
   FI.Clone = 0;
   
-  // Initialize the PoolArgFirst and PoolArgLast for the function depending
-  // on whether there have been other functions in the equivalence class
-  // that have pool arguments so far in the analysis.
+  // Initialize the PoolArgFirst and PoolArgLast for the function depending on
+  // whether there have been other functions in the equivalence class that have
+  // pool arguments so far in the analysis.
   if (!FuncECs.findClass(&F)) {
     FI.PoolArgFirst = FI.PoolArgLast = 0;
   } else {
@@ -304,35 +366,40 @@
   hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
   
   // Mark globals and incomplete nodes as live... (this handles arguments)
-  if (F.getName() != "main")
-    for (unsigned i = 0, e = Nodes.size(); i != e; ++i) {
-      if (Nodes[i]->isGlobalNode() && !Nodes[i]->isIncomplete())
-        DEBUG(std::cerr << "Global node is not Incomplete\n");
-      if ((Nodes[i]->isIncomplete() || Nodes[i]->isGlobalNode() || 
-	   NodesFromGlobals.count(Nodes[i])) && Nodes[i]->isHeapNode())
-        Nodes[i]->markReachableNodes(MarkedNodes);
+  if (F.getName() != "main") {
+    // All DSNodes reachable from arguments must be passed in.
+    for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I) {
+      DSGraph::ScalarMapTy::iterator AI = G.getScalarMap().find(I);
+      if (AI != G.getScalarMap().end())
+        if (DSNode *N = AI->second.getNode())
+          N->markReachableNodes(MarkedNodes);
     }
+  }
 
   // Marked the returned node as alive...
   if (DSNode *RetNode = G.getReturnNodeFor(F).getNode())
-    if (RetNode->isHeapNode())
-      RetNode->markReachableNodes(MarkedNodes);
+    RetNode->markReachableNodes(MarkedNodes);
 
-  if (MarkedNodes.empty())   // We don't need to clone the function if there
-    return;                  // are no incoming arguments to be added.
-
-  // Erase any marked node that is not a heap node
+  // Calculate 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.
+  hash_set<DSNode*> NodesFromGlobals;
+  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.
   for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
-	 E = MarkedNodes.end(); I != E; ) {
-    // erase invalidates hash_set iterators if the iterator points to the
-    // element being erased
-    if (!(*I)->isHeapNode())
-      MarkedNodes.erase(I++);
-    else
-      ++I;
+         E = MarkedNodes.end(); I != E; ) {
+    DSNode *N = *I++;
+    if ((!N->isHeapNode() && !PASS_ALL_ARGUMENTS) || NodesFromGlobals.count(N))
+      MarkedNodes.erase(N);
   }
 
+  if (MarkedNodes.empty())   // We don't need to clone the function if there
+    return;                  // are no incoming arguments to be added.
+
   FI.PoolArgLast += MarkedNodes.size();
 
   // Update the equivalence class last pool argument information
@@ -380,8 +447,7 @@
     }
     if (FI.ArgNodes.empty()) return 0;      // No nodes to be pool allocated!
 
-  }
-  else {
+  } else {
     // This function is a member of an equivalence class and needs to be cloned 
     ArgTys.reserve(OldFuncTy->getParamTypes().size() + 
 		   EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1);
@@ -423,8 +489,7 @@
   
   if (FuncECs.findClass(&F)) {
     // If the function belongs to an equivalence class
-    for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i, 
-	   ++NI)
+    for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i, ++NI)
       NI->setName("PDa");
     
     NI = New->abegin();
@@ -525,14 +590,37 @@
   hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
   
   DEBUG(std::cerr << "[" << F.getName() << "] Pool Allocate: ");
+
+  // Calculate 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.
+  DSGraph &GG = BU->getGlobalsGraph();
+  DSGraph::NodeMapTy GlobalsGraphNodeMapping;
+  for (DSGraph::ScalarMapTy::iterator I = G.getScalarMap().begin(), 
+         E = G.getScalarMap().end(); I != E; ++I)
+    if (GlobalValue *GV = dyn_cast<GlobalValue>(I->first)) {
+      // Map all node reachable from this global to the corresponding nodes in
+      // the globals graph.
+      DSGraph::computeNodeMapping(I->second.getNode(), GG.getNodeForValue(GV),
+                                  GlobalsGraphNodeMapping);
+    }
   
   // Loop over all of the nodes which are non-escaping, adding pool-allocatable
   // ones to the NodesToPA vector.
   std::vector<DSNode*> NodesToPA;
   for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
-    if (Nodes[i]->isHeapNode() &&   // Pick nodes with heap elems
-        !MarkedNodes.count(Nodes[i]))              // Can't be marked
-      NodesToPA.push_back(Nodes[i]);
+    // We only need to make a pool if there is a heap object in it...
+    if (Nodes[i]->isHeapNode())
+      if (GlobalsGraphNodeMapping.count(Nodes[i])) {
+        // If it is a global pool, set up the pool descriptor appropriately.
+        DSNode *GGN = GlobalsGraphNodeMapping[Nodes[i]].getNode();
+        assert(GGN && GlobalNodes[GGN] && "No global node found??");
+        FI.PoolDescriptors[Nodes[i]] = GlobalNodes[GGN];
+      } else if (!MarkedNodes.count(Nodes[i])) {
+        // Otherwise, if it was not passed in from outside the function, it must
+        // be a local pool!
+        NodesToPA.push_back(Nodes[i]);
+      }
   
   DEBUG(std::cerr << NodesToPA.size() << " nodes to pool allocate\n");
   if (!NodesToPA.empty())    // Insert pool alloca's
@@ -759,7 +847,10 @@
     // to poolalloc, and the call to pooldestroy.  Figure out which basic blocks
     // have this property for this pool.
     std::set<BasicBlock*> PoolFreeLiveBlocks;
-    CalculateLivePoolFreeBlocks(PoolFreeLiveBlocks, PD);
+    if (!DisableInitDestroyOpt)
+      CalculateLivePoolFreeBlocks(PoolFreeLiveBlocks, PD);
+    else
+      PoolFreeLiveBlocks = LiveBlocks;
     PoolDestroyPoints.clear();
 
     // Delete any pool frees which are not in live blocks, for correctness.
@@ -772,6 +863,5 @@
           !PoolFreeLiveBlocks.count(PoolFree->getParent()))
         DeleteIfIsPoolFree(PoolFree, PD, PoolFrees);
     }
-
   }
 }





More information about the llvm-commits mailing list