[llvm-commits] [poolalloc] r96631 - in /poolalloc/trunk: include/poolalloc/RunTimeAssociate.h lib/PoolAllocate/EntryPointAnalysis.cpp lib/PoolAllocate/EntryPointAnalysis.h lib/PoolAllocate/RunTimeAssociate.cpp

Andrew Lenharth alenhar2 at cs.uiuc.edu
Thu Feb 18 16:09:53 PST 2010


Author: alenhar2
Date: Thu Feb 18 18:09:52 2010
New Revision: 96631

URL: http://llvm.org/viewvc/llvm-project?rev=96631&view=rev
Log:
Simplify PA down to the bones for safecode and other dynamic points-to clients

Added:
    poolalloc/trunk/include/poolalloc/RunTimeAssociate.h
    poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.cpp
    poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.h
    poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp

Added: poolalloc/trunk/include/poolalloc/RunTimeAssociate.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/poolalloc/RunTimeAssociate.h?rev=96631&view=auto

==============================================================================
--- poolalloc/trunk/include/poolalloc/RunTimeAssociate.h (added)
+++ poolalloc/trunk/include/poolalloc/RunTimeAssociate.h Thu Feb 18 18:09:52 2010
@@ -0,0 +1,410 @@
+//===-- RunTimeAssociate.h - Runtime Ptr Association Pass -----------------===//
+//
+//                     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 transform changes programs so that pointers have an associated handle
+// corrosponding to DSA results.  This is a generalization of the Poolalloc
+// pass
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _RUNTIMEASSOCIATE_H
+#define	_RUNTIMEASSOCIATE_H
+
+#include "llvm/Argument.h"
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+#include "llvm/Pass.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/ADT/EquivalenceClasses.h"
+#include "llvm/ADT/VectorExtras.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/CommandLine.h"
+
+#include "dsa/DataStructure.h"
+
+#include <set>
+#include <map>
+#include <vector>
+#include <utility>
+
+namespace llvm {
+class DSNode;
+class DSGraph;
+class Type;
+class AllocaInst;
+class CallTargetFinder;
+
+namespace rPA {
+
+/// FuncInfo - Represent the pool allocation information for one function in
+/// the program.  Note that many functions must actually be cloned in order
+/// for pool allocation to add arguments to the function signature.  In this
+/// case, the Clone and NewToOldValueMap information identify how the clone
+/// maps to the original function...
+///
+
+class FuncInfo {
+public:
+  FuncInfo(const Function* f, DSGraph* g) : F(f), G(g), Clone(0) { }
+
+  /// F - The function this FuncInfo corresponds to.
+  ///
+  const Function *F;
+
+  DSGraph* G;
+
+  /// Clone - The cloned version of the function, if applicable.
+  ///
+  Function *Clone;
+
+  /// ArgNodes - The list of DSNodes which have pools passed in as arguments.
+  ///
+  std::vector<const DSNode*> ArgNodes;
+
+  /// PoolDescriptors - The Value* which defines the pool descriptor for this
+  /// DSNode.  Note: This does not necessarily include pool arguments that are
+  /// passed in because of indirect function calls that are not used in the
+  /// function.
+  std::map<const DSNode*, Value*> PoolDescriptors;
+
+  /// NewToOldValueMap - When and if a function needs to be cloned, this map
+  /// contains a mapping from all of the values in the new function back to
+  /// the values they correspond to in the old function.
+  ///
+  typedef std::map<const Value*, Value*> ValueMapTy;
+  ValueMapTy NewToOldValueMap;
+
+  /// MapValueToOriginal - Given a value in the cloned version of this
+  /// function, map it back to the original.  If the specified value did not
+  /// exist in the original function (e.g. because it's a pool descriptor),
+  /// return null.
+
+  Value * MapValueToOriginal(Value * V) const {
+    ValueMapTy::const_iterator I = NewToOldValueMap.find(V);
+    return I != NewToOldValueMap.end() ? const_cast<Value*> (I->second) : 0;
+  }
+
+  Value* getOldValueIfAvailable(Value* V) {
+    if (!NewToOldValueMap.empty()) {
+      // If the NewToOldValueMap is in effect, use it.
+      ValueMapTy::iterator I = NewToOldValueMap.find(V);
+      if (I != NewToOldValueMap.end())
+        V = I->second;
+    }
+    return V;
+  }
+
+  void UpdateNewToOldValueMap(Value *OldVal, Value *NewV1, Value *NewV2 = 0) {
+    ValueMapTy::iterator I = NewToOldValueMap.find(OldVal);
+    assert(I != NewToOldValueMap.end() && "OldVal not found in clone?");
+    NewToOldValueMap.insert(std::make_pair(NewV1, I->second));
+    if (NewV2)
+      NewToOldValueMap.insert(std::make_pair(NewV2, I->second));
+    NewToOldValueMap.erase(I);
+  }
+
+  DSNodeHandle& getDSNodeHFor(Value* V) {
+    return G->getScalarMap()[getOldValueIfAvailable(V)];
+  }
+
+};
+
+class PoolInfo {
+  Value* PrimDesc;
+  
+public:
+
+  void addPrimaryDescriptor(Value* P) {
+    PrimDesc = P;
+  }
+
+  void mergeNodeInfo(const DSNode* N) { }
+
+};
+
+} // end rPA namespace
+
+
+/// RTAssociate - Associate handles with pointers
+///
+
+class RTAssociate : public ModulePass {
+
+  // Type used to represent the pool, will be opaque in this pass
+  const Type *PoolDescPtrTy, *PoolDescType;
+
+  /// Special Values - Values created by this pass which should be ignored
+  std::set<const Value*> SpecialValues;
+
+  /// ValueMap - associate pools with values
+  std::map<const Value*, rPA::PoolInfo*> ValueMap;
+  
+  /// NodePoolMap - Find a pool from a DSNode
+  std::map<const DSNode*, rPA::PoolInfo*> NodePoolMap;
+  std::map<const Function*, rPA::FuncInfo> FunctionInfo;
+
+  //////////////////////////////////////////////////////////////////////////////
+
+  GlobalVariable* CreateGlobalPool(const DSNode*, Module*);
+  AllocaInst*     CreateLocalPool(const DSNode*, Function&);
+  Argument*       CreateArgPool(const DSNode*, Argument*);
+
+  /// SetupGlobalPools - Create a global for each global dsnode and associate
+  /// a pool with it
+  void SetupGlobalPools(Module*, DSGraph*);
+
+  /// setPoolForNode - associate a pool with a dsnode
+  void setupPoolForNode(const DSNode*, Value*);
+
+  /// getPoolForNode - return a poolinfo for a dsnode
+  rPA::PoolInfo* getPoolForNode(const DSNode* D) {
+    return NodePoolMap[D];
+  }
+
+  rPA::FuncInfo* getFuncInfo(const Function*);
+
+  rPA::FuncInfo& makeFuncInfo(const Function* F, DSGraph* G);
+
+  Function* MakeFunctionClone(Function& F, rPA::FuncInfo& FI, DSGraph* G);
+
+  /// ProcessCloneBody - Rewrite the body of a transformed function to use
+  /// pool allocation where appropriate.
+  ///
+  void ProcessFunctionBody(Function &Old, Function &New, DSGraph* G,
+                           DataStructures* DS);
+
+  void TransformBody(Function& F, rPA::FuncInfo& FI, DataStructures* DS);
+
+  void replaceCall(CallSite CS, rPA::FuncInfo& FI, DataStructures* DS);
+  
+  //////////////////////////////////////////////////////////////////////////////
+
+public:
+  static char ID;
+
+  RTAssociate();
+  bool runOnModule(Module &M);
+  void getAnalysisUsage(AnalysisUsage &AU) const;
+
+  
+};
+/*
+private:
+
+
+  /// GlobalNodes - For each node (with an H marker) in the globals graph, this
+  /// map contains the global variable that holds the pool descriptor for the
+  /// node.
+  std::map<const DSNode*, Value*> GlobalNodes;
+  std::map<const Function*, Function*> CloneToOrigMap;
+
+public:
+
+  /// GlobalNodes - For each node (with an H marker) in the globals graph, this
+  /// map contains the global variable that holds the pool descriptor for the
+  /// node.
+  //std::map<const DSNode*, Value*> GlobalNodes;
+
+protected:
+  std::map<const Function*, rPA::FuncInfo> FunctionInfo;
+  DataStructures* Graphs;
+  
+public:
+
+  //DataStructures &getGraphs() const {
+//    return *Graphs;
+//  }
+
+  /// getOrigFunctionFromClone - Given a pointer to a function that was cloned
+  /// from another function, return the original function.  If the argument
+  /// function is not a clone, return null.
+
+  Function *getOrigFunctionFromClone(const Function *F) const {
+    std::map<const Function*, Function*>::const_iterator I = CloneToOrigMap.find(F);
+    return I != CloneToOrigMap.end() ? I->second : 0;
+  }
+
+  /// getFuncInfo - Return the FuncInfo object for the specified function.
+  ///
+
+  rPA::FuncInfo *getFuncInfo(const Function &F) {
+    std::map<const Function*, rPA::FuncInfo>::iterator I = FunctionInfo.find(&F);
+    return I != FunctionInfo.end() ? &I->second : 0;
+  }
+
+  /// getFuncInfoOrClone - Return the function info object for for the specified
+  /// function.  If this function is a clone of another function, return the
+  /// function info object for the original function.
+
+  rPA::FuncInfo *getFuncInfoOrClone(const Function &F) {
+    // If it is cloned or not check it out.
+    if (rPA::FuncInfo * FI = getFuncInfo(F))
+      return FI;
+    // Maybe this is a function clone?
+    if (Function * FC = getOrigFunctionFromClone(&F))
+      return getFuncInfo(*FC);
+    return 0;
+  }
+
+
+  /// releaseMemory - When the pool allocator is no longer used, release
+  /// resources used by it.
+
+  virtual void releaseMemory() {
+    FunctionInfo.clear();
+    GlobalNodes.clear();
+    CloneToOrigMap.clear();
+  }
+
+  //
+  // Method: getPool()
+  //
+  // Description:
+  //  Returns the pool handle associated with the DSNode in the given function.
+  //
+  // Inputs:
+  //  N - The DSNode of the value for which the caller wants a pool handle.
+  //  F - The function in which the value for which we want a pool handle
+  //      exists.
+  //
+  // Notes:
+  //  o) The DSNode N may *not* be in the current function.  The caller may
+  //     have mapped a value in the cloned function back to the original
+  //     function.
+  //
+
+  virtual Value * getPool(const DSNode * N, Function & F) {
+    //
+    // Grab the structure containg information about the function and its
+    // clones.
+    //
+    rPA::FuncInfo * FI = getFuncInfoOrClone(F);
+    assert(FI && "Function has no FuncInfoOrClone!\n");
+
+    //
+    // Look for a mapping from the DSNode to the pool handle.
+    //
+    std::map<const DSNode*, Value*>::iterator I = FI->PoolDescriptors.find(N);
+    if (I != FI->PoolDescriptors.end()) {
+      Value * Pool = I->second;
+
+      //
+      // Now the fun part:
+      //  The specified function could either be a clone or the original
+      //  function.  This means that the pool descriptor that is matched with
+      //  the DSNode is:
+      //    o) A constant accessible from both the original function and its
+      //       clones.
+      //    o) A global variable accessible from both the original function and
+      //       its clones.
+      //    o) An allocation accessible only to the function.
+      //    o) A function parameter accessible only to the local function.
+      //
+      //  In short, we need to filter out the case where we find a pool handle,
+      //  but it's only accessible from a clone and not the original function.
+      //
+      assert((isa<GlobalVariable > (Pool) ||
+             isa<AllocationInst > (Pool) ||
+             isa<Argument > (Pool) ||
+             isa<Constant > (Pool)) &&
+             "Pool of unknown type!\n");
+      if ((isa<GlobalVariable > (Pool)) || (isa<Constant > (Pool))) {
+        return Pool;
+      } else if (AllocationInst * AI = dyn_cast<AllocationInst > (Pool)) {
+        if (AI->getParent()->getParent() == &F)
+          return Pool;
+      } else if (Argument * Arg = dyn_cast<Argument > (Pool)) {
+        if (Arg->getParent() == &F)
+          return Pool;
+      }
+    }
+
+    //
+    // We either do not have a pool, or the pool is not accessible from the
+    // specified function.  Return NULL.
+    //
+    return 0;
+  }
+
+  virtual Value * getGlobalPool(const DSNode * Node) {
+    std::map<const DSNode *, Value *>::iterator I = GlobalNodes.find(Node);
+    if (I == GlobalNodes.end())
+      return 0;
+    else
+      return I->second;
+  }
+
+protected:
+
+  /// AddPrototypes - Add prototypes for the pool functions to the
+  /// specified module and update the Pool* instance variables to point to
+  /// them.
+  ///
+  void AddPrototypes(Module*);
+
+private:
+
+  /// MicroOptimizePoolCalls - Apply any microoptimizations to calls to pool
+  /// allocation function calls that we can.
+  void MicroOptimizePoolCalls();
+
+  /// BuildIndirectFunctionSets - Iterate over the module looking for indirect
+  /// calls to functions
+  void BuildIndirectFunctionSets(Module &M);
+
+  /// 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 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 SetupGlobalPools(Module &M);
+
+  /// 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);
+
+  /// CreatePools - This inserts alloca instruction in the function for all
+  /// pools specified in the NodesToPA list.  This adds an entry to the
+  /// PoolDescriptors map for each DSNode.
+  ///
+  void CreatePools(Function &F, DSGraph* G,
+                   const std::vector<const DSNode*> &NodesToPA,
+                   std::map<const DSNode*, Value*> &PoolDescriptors);
+
+  void TransformBody(DSGraph* g, rPA::FuncInfo &fi,
+                     std::multimap<AllocaInst*, Instruction*> &poolUses,
+                     std::multimap<AllocaInst*, CallInst*> &poolFrees,
+                     Function &F);
+
+  /// InitializeAndDestroyPools - This inserts calls to poolinit and pooldestroy
+  /// into the function to initialize and destroy the pools in the NodesToPA
+  /// list.
+  void InitializeAndDestroyPools(Function &F,
+                                 const std::vector<const DSNode*> &NodesToPA,
+                                 std::map<const DSNode*, Value*> &PoolDescriptors,
+                                 std::multimap<AllocaInst*, Instruction*> &PoolUses,
+                                 std::multimap<AllocaInst*, CallInst*> &PoolFrees);
+
+  void InitializeAndDestroyPool(Function &F, const DSNode *Pool,
+                                std::map<const DSNode*, Value*> &PoolDescriptors,
+                                std::multimap<AllocaInst*, Instruction*> &PoolUses,
+                                std::multimap<AllocaInst*, CallInst*> &PoolFrees);
+
+  void CalculateLivePoolFreeBlocks(std::set<BasicBlock*> &LiveBlocks, Value *PD);
+};
+*/
+
+}
+
+#endif	/* _RUNTIMEASSOCIATE_H */
+

Added: poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.cpp?rev=96631&view=auto

==============================================================================
--- poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.cpp (added)
+++ poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.cpp Thu Feb 18 18:09:52 2010
@@ -0,0 +1,52 @@
+//===-- EntryPointAnalysis.cpp - Entry point Finding Pass -----------------===//
+//
+//                     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 is a general way of finding entry points in a system.  Simple programs
+// will use the main version.  Libraries and OS kernels can have more
+// specialized versions.  This is done as an analysis group to allow more
+// convinient opt invocations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+
+#include "EntryPointAnalysis.h"
+
+using namespace llvm;
+
+EntryPointAnalysis::~EntryPointAnalysis() {}
+char EntryPointAnalysis::ID;
+
+namespace {
+
+
+static RegisterAnalysisGroup<EntryPointAnalysis> A("Entry Point Analysis");
+
+class MainEntryPointAnalysis : public ImmutablePass, public EntryPointAnalysis {
+public:
+  static char ID;
+
+  MainEntryPointAnalysis() : ImmutablePass(&ID) { }
+
+  bool isEntryPoint(const llvm::Function* F) const {
+    return !F->isDeclaration()
+            && F->hasExternalLinkage()
+            && F->hasName() && F->getName() == "main";
+  }
+};
+
+char MainEntryPointAnalysis::ID;
+RegisterPass<MainEntryPointAnalysis> B("epa_main", "Identify Main");
+RegisterAnalysisGroup<EntryPointAnalysis, true> C(B);
+
+
+
+}
\ No newline at end of file

Added: poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.h?rev=96631&view=auto

==============================================================================
--- poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.h (added)
+++ poolalloc/trunk/lib/PoolAllocate/EntryPointAnalysis.h Thu Feb 18 18:09:52 2010
@@ -0,0 +1,35 @@
+//===-- EntryPointAnalysis.h - Entry point Finding Pass -------------------===//
+//
+//                     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 is a general way of finding entry points in a system.  Simple programs
+// will use the main version.  Libraries and OS kernels can have more
+// specialized versions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _ENTRYPOINTANALYSIS_H
+#define	_ENTRYPOINTANALYSIS_H
+
+namespace llvm {
+class Function;
+}
+
+class EntryPointAnalysis {
+public:
+  static char ID;
+  EntryPointAnalysis() {}
+  virtual ~EntryPointAnalysis();
+
+  virtual bool isEntryPoint(const llvm::Function* F) const = 0;
+};
+
+
+
+#endif	/* _ENTRYPOINTANALYSIS_H */
+

Added: poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp?rev=96631&view=auto

==============================================================================
--- poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp (added)
+++ poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp Thu Feb 18 18:09:52 2010
@@ -0,0 +1,612 @@
+//===-- RunTimeAssociate.cpp - MemHandle Association Pass -----------------===//
+//
+//                     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 transform changes programs so that pointers have an associated handle
+// corrosponding to DSA results.  This is a generalization of the Poolalloc
+// pass
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "pa_assoc"
+
+#include "dsa/DataStructure.h"
+#include "dsa/DSGraph.h"
+#include "poolalloc/RunTimeAssociate.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/Constants.h"
+#include "llvm/Attributes.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+
+#include "EntryPointAnalysis.h"
+
+#include <iostream>
+
+using namespace llvm;
+using namespace rPA;
+
+char RTAssociate::ID = 0;
+
+namespace {
+RegisterPass<RTAssociate>
+X("rtassoc", "Memory handle association");
+
+STATISTIC(NumArgsAdded, "Number of function arguments added");
+STATISTIC(MaxArgsAdded, "Maximum function arguments added to one function");
+STATISTIC(NumCloned, "Number of functions cloned");
+STATISTIC(NumPools, "Number of pools allocated");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Helpers
+////////////////////////////////////////////////////////////////////////////////
+
+static void GetNodesReachableFromGlobals(DSGraph* G,
+                                         hash_set<const DSNode*> &NodesFromGlobals) {
+  for (DSScalarMap::global_iterator I = G->getScalarMap().global_begin(),
+          E = G->getScalarMap().global_end(); I != E; ++I)
+    G->getNodeForValue(*I).getNode()->markReachableNodes(NodesFromGlobals);
+}
+
+static void MarkNodesWhichMustBePassedIn(hash_set<const DSNode*> &MarkedNodes,
+                                         Function &F, DSGraph* G,
+                                         EntryPointAnalysis* EPA) {
+  // All DSNodes reachable from arguments must be passed in...
+  // Unless this is an entry point to the program
+  if (!EPA->isEntryPoint(&F)) {
+    for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
+            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 needing to be passed in.
+  if (DSNode * RetNode = G->getReturnNodeFor(F).getNode())
+    RetNode->markReachableNodes(MarkedNodes);
+
+  // 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<const 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.
+
+  for (hash_set<const DSNode*>::iterator I = NodesFromGlobals.begin(),
+          E = NodesFromGlobals.end(); I != E; ++I)
+    MarkedNodes.erase(*I);
+}
+
+
+/// 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.
+static void FindFunctionPoolArgs(Function &F, FuncInfo& FI,
+                                 EntryPointAnalysis* EPA) {
+  hash_set<const DSNode*> MarkedNodes;
+
+  if (FI.G->node_begin() == FI.G->node_end())
+    return; // No memory activity, nothing is required
+
+  // 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, F, FI.G,EPA);
+
+  FI.ArgNodes.insert(FI.ArgNodes.end(), MarkedNodes.begin(), MarkedNodes.end());
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// RTAssociate
+////////////////////////////////////////////////////////////////////////////////
+
+// MakeFunctionClone - If the specified function needs to be modified for pool
+// allocation support, make a clone of it, adding additional arguments as
+// necessary, and return it.  If not, just return null.
+//
+Function* RTAssociate::MakeFunctionClone(Function &F, FuncInfo& FI, DSGraph* G) {
+  if (G->node_begin() == G->node_end()) return 0;
+
+  if (FI.ArgNodes.empty())
+    return 0; // No need to clone if no pools need to be passed in!
+
+  // Update statistics..
+  NumArgsAdded += FI.ArgNodes.size();
+  if (MaxArgsAdded < FI.ArgNodes.size()) MaxArgsAdded = FI.ArgNodes.size();
+  ++NumCloned;
+
+  // Figure out what the arguments are to be for the new version of the
+  // function
+  const FunctionType *OldFuncTy = F.getFunctionType();
+  std::vector<const Type*> ArgTys(FI.ArgNodes.size(), PoolDescPtrTy);
+  ArgTys.reserve(OldFuncTy->getNumParams() + FI.ArgNodes.size());
+
+  ArgTys.insert(ArgTys.end(), OldFuncTy->param_begin(), OldFuncTy->param_end());
+
+  // Create the new function prototype
+  FunctionType *FuncTy = FunctionType::get(OldFuncTy->getReturnType(), ArgTys,
+                                           OldFuncTy->isVarArg());
+  // Create the new function...
+  Function *New = Function::Create(FuncTy, Function::InternalLinkage, F.getName());
+  New->copyAttributesFrom(&F);
+  F.getParent()->getFunctionList().insert(&F, New);
+
+  // Set the rest of the new arguments names to be PDa<n> and add entries to the
+  // pool descriptors map
+  Function::arg_iterator NI = New->arg_begin();
+  for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI) {
+    FI.PoolDescriptors[FI.ArgNodes[i]] = CreateArgPool(FI.ArgNodes[i], NI);
+    NI->setName("PDa");
+  }
+
+  // Map the existing arguments of the old function to the corresponding
+  // arguments of the new function, and copy over the names.
+  DenseMap<const Value*, Value*> ValueMap;
+  for (Function::arg_iterator I = F.arg_begin();
+          NI != New->arg_end(); ++I, ++NI) {
+    ValueMap[I] = NI;
+    NI->setName(I->getName());
+  }
+
+  // Perform the cloning.
+  std::vector<ReturnInst*> Returns;
+  CloneFunctionInto(New, &F, ValueMap, Returns);
+
+  //
+  // The CloneFunctionInto() function will copy the parameter attributes
+  // verbatim.  This is incorrect; each attribute should be shifted one so
+  // that the pool descriptor has no attributes.
+  //
+  const AttrListPtr OldAttrs = New->getAttributes();
+  if (!OldAttrs.isEmpty()) {
+    AttrListPtr NewAttrsVector;
+    for (unsigned index = 0; index < OldAttrs.getNumSlots(); ++index) {
+      const AttributeWithIndex & PAWI = OldAttrs.getSlot(index);
+      unsigned argIndex = PAWI.Index;
+
+      // If it's not the return value, move the attribute to the next
+      // parameter.
+      if (argIndex) ++argIndex;
+
+      // Add the parameter to the new list.
+      NewAttrsVector.addAttr(argIndex, PAWI.Attrs);
+    }
+
+    // Assign the new attributes to the function clone
+    New->setAttributes(NewAttrsVector);
+  }
+
+  for (DenseMap<const Value*, Value*>::iterator I = ValueMap.begin(),
+          E = ValueMap.end(); I != E; ++I)
+    FI.NewToOldValueMap.insert(std::make_pair(I->second, (Value*)I->first));
+
+  return FI.Clone = New;
+}
+
+RTAssociate::RTAssociate()
+: ModulePass((intptr_t) & ID) { }
+
+void RTAssociate::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<EquivBUDataStructures > ();
+  AU.addRequired<EntryPointAnalysis> ();
+}
+
+bool RTAssociate::runOnModule(Module &M) {
+  if (M.begin() == M.end()) return false;
+
+  //
+  // Get references to the DSA information.  For SAFECode, we need Top-Down
+  // DSA.  For Automatic Pool Allocation only, we need Bottom-Up DSA.  In all
+  // cases, we need to use the Equivalence-Class version of DSA.
+  //
+  DataStructures* Graphs = &getAnalysis<EquivBUDataStructures > ();
+  EntryPointAnalysis* EPA = &getAnalysis<EntryPointAnalysis > ();
+
+  //  PoolDescType = OpaqueType::get(M.getContext());
+  PoolDescType = Type::getInt32Ty(M.getContext());
+  PoolDescPtrTy = PointerType::getUnqual(PoolDescType);
+  M.addTypeName("PoolDescriptor", PoolDescType);
+
+  // Create the pools for memory objects reachable by global variables.
+  SetupGlobalPools(&M, Graphs-> getGlobalsGraph());
+
+  // Loop over the functions in the original program finding the pool desc.
+  // arguments necessary for each function that is indirectly callable.
+  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+    if (!I->isDeclaration() && Graphs->hasDSGraph(*I)) {
+      FuncInfo & FI = makeFuncInfo(I, Graphs->getDSGraph(*I));
+      FindFunctionPoolArgs(*I, FI, EPA);
+    }
+
+  // Map that maps an original function to its clone
+  std::map<Function*, Function*> FuncToCloneMap;
+  
+  // 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.
+  std::set<Function*> ClonedFunctions;
+  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+    if (!I->isDeclaration() && !ClonedFunctions.count(I) &&
+            Graphs->hasDSGraph(*I)) {
+      FuncInfo & FI = FunctionInfo.find(I)->second;
+      if (Function* Clone = MakeFunctionClone(*I, FI, Graphs->getDSGraph(*I))) {
+        assert(!EPA->isEntryPoint(I) && "Entry Point Cloned");
+        FuncToCloneMap[I] = Clone;
+        ClonedFunctions.insert(Clone);
+      }
+    }
+
+  // Now that all call targets are available, rewrite the function bodies of the
+  // clones.
+  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+    if (!I->isDeclaration() && !ClonedFunctions.count(I) &&
+            Graphs->hasDSGraph(*I)) {
+      if (FuncToCloneMap.find(I) == FuncToCloneMap.end()) {
+        // Function was changed inplace
+        ProcessFunctionBody(*I, *I, Graphs->getDSGraph(*I),Graphs);
+      } else {
+        // Function was cloned
+        ProcessFunctionBody(*I, *FuncToCloneMap[I], Graphs->getDSGraph(*I),
+                            Graphs);
+      }
+    }
+
+  return true;
+}
+
+// SetupGlobalPools - Create global pools for all DSNodes in the globals graph.
+// This is implemented by making the pool descriptor be a global variable of
+// it's own.
+
+void RTAssociate::SetupGlobalPools(Module* M, DSGraph* GG) {
+  // Get the globals graph for the program.
+  // DSGraph* GG = Graphs->getGlobalsGraph();
+
+  // Get all of the nodes reachable from globals.
+  hash_set<const DSNode*> GlobalHeapNodes;
+  GetNodesReachableFromGlobals(GG, GlobalHeapNodes);
+
+  std::cerr << "Pool allocating " << GlobalHeapNodes.size()
+          << " global nodes!\n";
+
+  FuncInfo& FI = makeFuncInfo(0, GG);
+
+  while (GlobalHeapNodes.size()) {
+    const DSNode* D = *GlobalHeapNodes.begin();
+    GlobalHeapNodes.erase(D);
+    FI.PoolDescriptors[D] = CreateGlobalPool(D, M);
+  }
+}
+
+/// CreateGlobalPool - Create a global pool descriptor object
+
+GlobalVariable* RTAssociate::CreateGlobalPool(const DSNode* D, Module* M) {
+  //Must use external linkage unless we have an inializer
+  GlobalVariable *GV = new GlobalVariable(*M, PoolDescType, false,
+                                          GlobalValue::ExternalLinkage, 0,
+                                          "GlobalPool");
+  ++NumPools;
+  SpecialValues.insert(GV);
+  return GV;
+}
+
+/// CreatePool - This creates the pool for local DSNodes
+///
+
+AllocaInst* RTAssociate::CreateLocalPool(const DSNode* D, Function &F) {
+  AllocaInst* AI = new AllocaInst(PoolDescType, 0, "LocalPool",
+                                  F.getEntryBlock().begin());
+  ++NumPools;
+  SpecialValues.insert(AI);
+  return AI;
+}
+
+Argument* RTAssociate::CreateArgPool(const DSNode*D, Argument* Arg) {
+  SpecialValues.insert(Arg);
+  return Arg;
+}
+
+/// setupPoolForNode - Update or merge the pool with the DSNode's info and update
+/// node mappings.
+
+void RTAssociate::setupPoolForNode(const DSNode* D, Value* V) {
+  SpecialValues.insert(V);
+  PoolInfo*& PI = NodePoolMap[D];
+  assert(!PI && "Pool already exists");
+  PI = new PoolInfo();
+  PI->addPrimaryDescriptor(V);
+  PI->mergeNodeInfo(D);
+  NodePoolMap[D] = PI;
+}
+
+/// ProcessFunctionBody - Pool allocate any data structures which are contained
+/// in the specified function.
+//
+
+void RTAssociate::ProcessFunctionBody(Function &F, Function &NewF, DSGraph* G,
+                                      DataStructures* DS) {
+  if (G->node_begin() == G->node_end()) return; // Quick exit if nothing to do.
+
+  FuncInfo &FI = *getFuncInfo(&F);
+
+  // 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.
+  G->getGlobalsGraph();
+
+  // Map all node reachable from this global to the corresponding nodes in
+  // the globals graph.
+  DSGraph::NodeMapTy GlobalsGraphNodeMapping;
+  G->computeGToGGMapping(GlobalsGraphNodeMapping);
+
+  // Loop over all of the nodes which are non-escaping, adding pool-allocatable
+  // ones to the NodesToPA vector.
+  for (DSGraph::node_iterator I = G->node_begin(), E = G->node_end(); I != E; ++I) {
+    DSNode *N = I;
+    if (GlobalsGraphNodeMapping.count(N)) {
+      // If it is a global pool, set up the pool descriptor appropriately.
+      DSNode *GGN = GlobalsGraphNodeMapping[N].getNode();
+      assert(getFuncInfo(0)->PoolDescriptors[GGN] && "Should be in global mapping!");
+      FI.PoolDescriptors[N] = getFuncInfo(0)->PoolDescriptors[GGN];
+    } else if (!FI.PoolDescriptors[N]) {
+      // Otherwise, if it was not passed in from outside the function, it must
+      // be a local pool!
+      assert(!N->isGlobalNode() && "Should be in global mapping!");
+      FI.PoolDescriptors[N] = CreateLocalPool(N, NewF);
+    }
+  }
+  TransformBody(NewF, FI, DS);
+}
+
+FuncInfo* RTAssociate::getFuncInfo(const Function* F) {
+  std::map<const Function*, FuncInfo>::iterator I = FunctionInfo.find(F);
+  return I != FunctionInfo.end() ? &I->second : 0;
+}
+
+FuncInfo& RTAssociate::makeFuncInfo(const Function* F, DSGraph* G) {
+  return FunctionInfo.insert(std::make_pair(F, FuncInfo(F, G))).first->second;
+}
+
+void RTAssociate::TransformBody(Function& F, FuncInfo& FI,
+                                DataStructures* DS) {
+  for (Function::iterator ii = F.begin(), ee = F.end(); ii != ee; ++ii)
+    for (BasicBlock::iterator bi = ii->begin(); bi != ii->end();)
+      if (CallInst* CI = dyn_cast<CallInst>(bi)) {
+        ++bi;
+        replaceCall(CallSite(CI), FI, DS);
+      } else
+        ++bi;
+ }
+
+void RTAssociate::replaceCall(CallSite CS, FuncInfo& FI, DataStructures* DS) {
+  const Function *CF = CS.getCalledFunction();
+  Instruction *TheCall = CS.getInstruction();
+
+  // If the called function is casted from one function type to another, peer
+  // into the cast instruction and pull out the actual function being called.
+  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(CS.getCalledValue()))
+    if (CE->getOpcode() == Instruction::BitCast &&
+        isa<Function>(CE->getOperand(0)))
+      CF = cast<Function>(CE->getOperand(0));
+
+  if (isa<InlineAsm>(TheCall->getOperand(0))) {
+    std::cerr << "INLINE ASM: ignoring.  Hoping that's safe.\n";
+    return;
+  }
+
+  // Ignore calls to NULL pointers.
+  if (isa<ConstantPointerNull>(CS.getCalledValue())) {
+    std::cerr << "WARNING: Ignoring call using NULL function pointer.\n";
+    return;
+  }
+  // We need to figure out which local pool descriptors correspond to the pool
+  // descriptor arguments passed into the function call.  Calculate a mapping
+  // from callee DSNodes to caller DSNodes.  We construct a partial isomophism
+  // between the graphs to figure out which pool descriptors need to be passed
+  // in.  The roots of this mapping is found from arguments and return values.
+  //
+  DSGraph::NodeMapTy NodeMapping;
+  Instruction *NewCall;
+  Value *NewCallee;
+  std::vector<const DSNode*> ArgNodes;
+  DSGraph *CalleeGraph;  // The callee graph
+
+  // For indirect callees, find any callee since all DS graphs have been
+  // merged.
+  if (CF) { // Direct calls are nice and simple.
+    DEBUG(std::cerr << "  Handling direct call: " << *TheCall);
+    FuncInfo *CFI = getFuncInfo(CF);
+    if (CFI == 0 || CFI->Clone == 0) // Nothing to transform...
+      return;
+
+    NewCallee = CFI->Clone;
+    ArgNodes = CFI->ArgNodes;
+
+    assert ((DS->hasDSGraph (*CF)) && "Function has no ECGraph!\n");
+    CalleeGraph = DS->getDSGraph(*CF);
+  } else {
+    DEBUG(std::cerr << "  Handling indirect call: " << *TheCall);
+
+    // Here we fill in CF with one of the possible called functions.  Because we
+    // merged together all of the arguments to all of the functions in the
+    // equivalence set, it doesn't really matter which one we pick.
+    // (If the function was cloned, we have to map the cloned call instruction
+    // in CS back to the original call instruction.)
+    Instruction *OrigInst =
+      cast<Instruction>(FI.getOldValueIfAvailable(CS.getInstruction()));
+
+    DataStructures::callee_iterator I = DS->callee_begin(OrigInst);
+    if (I != DS->callee_end(OrigInst))
+      CF = *I;
+
+    // If we didn't find the callee in the constructed call graph, try
+    // checking in the DSNode itself.
+    // This isn't ideal as it means that this call site didn't have inlining
+    // happen.
+    if (!CF) {
+      DSGraph* dg = DS->getDSGraph(*OrigInst->getParent()->getParent());
+      DSNode* d = dg->getNodeForValue(OrigInst->getOperand(0)).getNode();
+      assert (d && "No DSNode!\n");
+      std::vector<const Function*> g;
+      d->addFullFunctionList(g);
+      if (g.size()) {
+        EquivalenceClasses< const GlobalValue *> & EC = dg->getGlobalECs();
+        for(std::vector<const Function*>::const_iterator ii = g.begin(), ee = g.end();
+            !CF && ii != ee; ++ii) {
+          for (EquivalenceClasses<const GlobalValue *>::member_iterator MI = EC.findLeader(*ii);
+               MI != EC.member_end(); ++MI)   // Loop over members in this set.
+            if ((CF = dyn_cast<Function>(*MI))) {
+              break;
+            }
+        }
+      }
+    }
+
+    //
+    // Do an assert unless we're bugpointing something.
+    //
+//    if ((UsingBugpoint) && (!CF)) return;
+    assert (CF && "No call graph info");
+
+    // Get the common graph for the set of functions this call may invoke.
+//    if (UsingBugpoint && (!(Graphs.hasDSGraph(*CF)))) return;
+    assert ((DS->hasDSGraph(*CF)) && "Function has no DSGraph!\n");
+    CalleeGraph = DS->getDSGraph(*CF);
+
+#ifndef NDEBUG
+    // Verify that all potential callees at call site have the same DS graph.
+    DataStructures::callee_iterator E = DS->callee_end(OrigInst);
+    for (; I != E; ++I)
+      if (!(*I)->isDeclaration())
+        assert(CalleeGraph == DS->getDSGraph(**I) &&
+               "Callees at call site do not have a common graph!");
+#endif
+
+    // Find the DS nodes for the arguments that need to be added, if any.
+    FuncInfo *CFI = getFuncInfo(CF);
+    assert(CFI && "No function info for callee at indirect call?");
+    ArgNodes = CFI->ArgNodes;
+
+    if (ArgNodes.empty())
+      return;           // No arguments to add?  Transformation is a noop!
+
+    // Cast the function pointer to an appropriate type!
+    std::vector<const Type*> ArgTys(ArgNodes.size(), PoolDescPtrTy);
+    for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
+         I != E; ++I)
+      ArgTys.push_back((*I)->getType());
+
+    FunctionType *FTy = FunctionType::get(TheCall->getType(), ArgTys, false);
+    PointerType *PFTy = PointerType::getUnqual(FTy);
+
+    // If there are any pool arguments cast the func ptr to the right type.
+    NewCallee = CastInst::CreatePointerCast(CS.getCalledValue(), PFTy, "tmp", TheCall);
+  }
+
+  Function::const_arg_iterator FAI = CF->arg_begin(), E = CF->arg_end();
+  CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
+  for ( ; FAI != E && AI != AE; ++FAI, ++AI)
+    if (!isa<Constant>(*AI))
+      DSGraph::computeNodeMapping(CalleeGraph->getNodeForValue(FAI),
+                                  FI.getDSNodeHFor(*AI), NodeMapping, false);
+
+  assert(AI == AE && "Varargs calls not handled yet!");
+
+  // Map the return value as well...
+  if (isa<PointerType>(TheCall->getType()))
+    DSGraph::computeNodeMapping(CalleeGraph->getReturnNodeFor(*CF),
+                                FI.getDSNodeHFor(TheCall), NodeMapping, false);
+
+  // Okay, now that we have established our mapping, we can figure out which
+  // pool descriptors to pass in...
+  std::vector<Value*> Args;
+  for (unsigned i = 0, e = ArgNodes.size(); i != e; ++i) {
+    Value *ArgVal = Constant::getNullValue(PoolDescPtrTy);
+    if (NodeMapping.count(ArgNodes[i]))
+      if (DSNode *LocalNode = NodeMapping[ArgNodes[i]].getNode())
+        if (FI.PoolDescriptors.count(LocalNode))
+          ArgVal = FI.PoolDescriptors.find(LocalNode)->second;
+    if (isa<Constant > (ArgVal) && cast<Constant > (ArgVal)->isNullValue())
+      std::cerr << "WARNING: NULL POOL ARGUMENTS ARE PASSED IN!\n";
+    Args.push_back(ArgVal);
+  }
+
+  // Add the rest of the arguments...
+  Args.insert(Args.end(), CS.arg_begin(), CS.arg_end());
+
+  //
+  // There are circumstances where a function is casted to another type and
+  // then called (que horible).  We need to perform a similar cast if the
+  // type doesn't match the number of arguments.
+  //
+  if (Function * NewFunction = dyn_cast<Function>(NewCallee)) {
+    const FunctionType * NewCalleeType = NewFunction->getFunctionType();
+    if (NewCalleeType->getNumParams() != Args.size()) {
+      std::vector<const Type *> Types;
+      Type * FuncTy = FunctionType::get (NewCalleeType->getReturnType(),
+                                         Types,
+                                         true);
+      FuncTy = PointerType::getUnqual (FuncTy);
+      NewCallee = new BitCastInst (NewCallee, FuncTy, "", TheCall);
+    }
+  }
+
+  std::string Name = TheCall->getName();    TheCall->setName("");
+
+  if (InvokeInst *II = dyn_cast<InvokeInst>(TheCall)) {
+    NewCall = InvokeInst::Create (NewCallee, II->getNormalDest(),
+                                  II->getUnwindDest(),
+                                  Args.begin(), Args.end(), Name, TheCall);
+  } else {
+    NewCall = CallInst::Create (NewCallee, Args.begin(), Args.end(), Name,
+                                TheCall);
+  }
+
+  TheCall->replaceAllUsesWith(NewCall);
+  DEBUG(std::cerr << "  Result Call: " << *NewCall);
+
+  if (TheCall->getType()->getTypeID() != Type::VoidTyID) {
+    // If we are modifying the original function, update the DSGraph...
+    DSGraph::ScalarMapTy &SM = FI.G->getScalarMap();
+    DSGraph::ScalarMapTy::iterator CII = SM.find(TheCall);
+    if (CII != SM.end()) {
+      SM[NewCall] = CII->second;
+      SM.erase(CII);                     // Destroy the CallInst
+    } else if (!FI.NewToOldValueMap.empty()) {
+      // Otherwise, if this is a clone, update the NewToOldValueMap with the new
+      // CI return value.
+      FI.UpdateNewToOldValueMap(TheCall, NewCall);
+    }
+  } else if (!FI.NewToOldValueMap.empty()) {
+    FI.UpdateNewToOldValueMap(TheCall, NewCall);
+  }
+
+  //FIXME: attributes on call?
+  CallSite(NewCall).setCallingConv(CallSite(TheCall).getCallingConv());
+
+  TheCall->eraseFromParent();
+}
\ No newline at end of file





More information about the llvm-commits mailing list