[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