aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/PoolAllocate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/IPO/PoolAllocate.cpp')
-rw-r--r--lib/Transforms/IPO/PoolAllocate.cpp1204
1 files changed, 0 insertions, 1204 deletions
diff --git a/lib/Transforms/IPO/PoolAllocate.cpp b/lib/Transforms/IPO/PoolAllocate.cpp
deleted file mode 100644
index 337c4adee3..0000000000
--- a/lib/Transforms/IPO/PoolAllocate.cpp
+++ /dev/null
@@ -1,1204 +0,0 @@
-//===-- PoolAllocate.cpp - Pool Allocation Pass ---------------------------===//
-//
-// This transform changes programs so that disjoint data structures are
-// allocated out of different pools of memory, increasing locality.
-//
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "PoolAllocation"
-#include "llvm/Transforms/PoolAllocate.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Module.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Constants.h"
-#include "llvm/Instructions.h"
-#include "llvm/Target/TargetData.h"
-#include "llvm/Support/InstVisitor.h"
-#include "Support/Debug.h"
-#include "Support/VectorExtras.h"
-using namespace PA;
-
-namespace {
- const Type *VoidPtrTy = PointerType::get(Type::SByteTy);
-
- // The type to allocate for a pool descriptor: { sbyte*, uint, uint }
- // void *Data (the data)
- // unsigned NodeSize (size of an allocated node)
- // unsigned FreeablePool (are slabs in the pool freeable upon calls to
- // poolfree?)
- const Type *PoolDescType =
- StructType::get(make_vector<const Type*>(VoidPtrTy, Type::UIntTy,
- Type::UIntTy, 0));
-
- const PointerType *PoolDescPtr = PointerType::get(PoolDescType);
-
- RegisterOpt<PoolAllocate>
- X("poolalloc", "Pool allocate disjoint data structures");
-}
-
-void PoolAllocate::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<BUDataStructures>();
- AU.addRequired<TDDataStructures>();
- AU.addRequired<TargetData>();
-}
-
-// Prints out the functions mapped to the leader of the equivalence class they
-// belong to.
-void PoolAllocate::printFuncECs() {
- std::map<Function*, Function*> &leaderMap = FuncECs.getLeaderMap();
- std::cerr << "Indirect Function Map \n";
- for (std::map<Function*, Function*>::iterator LI = leaderMap.begin(),
- LE = leaderMap.end(); LI != LE; ++LI) {
- std::cerr << LI->first->getName() << ": leader is "
- << LI->second->getName() << "\n";
- }
-}
-
-static void printNTOMap(std::map<Value*, const Value*> &NTOM) {
- std::cerr << "NTOM MAP\n";
- for (std::map<Value*, const Value *>::iterator I = NTOM.begin(),
- E = NTOM.end(); I != E; ++I) {
- if (!isa<Function>(I->first) && !isa<BasicBlock>(I->first))
- std::cerr << *I->first << " to " << *I->second << "\n";
- }
-}
-
-void PoolAllocate::buildIndirectFunctionSets(Module &M) {
- // Iterate over the module looking for indirect calls to functions
-
- // 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");
-
- if (MI->isExternal())
- continue;
-
- DSGraph &TDG = TDDS->getDSGraph(*MI);
-
- std::vector<DSCallSite> callSites = TDG.getFunctionCalls();
-
- // For each call site in the function
- // All the functions that can be called at the call site are put in the
- // same equivalence class.
- for (std::vector<DSCallSite>::iterator CSI = callSites.begin(),
- CSE = callSites.end(); CSI != CSE ; ++CSI) {
- if (CSI->isIndirectCall()) {
- DSNode *DSN = CSI->getCalleeNode();
- if (DSN->isIncomplete())
- std::cerr << "Incomplete node " << CSI->getCallInst();
- // assert(DSN->isGlobalNode());
- const std::vector<GlobalValue*> &Callees = DSN->getGlobals();
- if (Callees.size() > 0) {
- Function *firstCalledF = dyn_cast<Function>(*Callees.begin());
- FuncECs.addElement(firstCalledF);
- CallInstTargets.insert(std::pair<CallInst*,Function*>
- (&CSI->getCallInst(),
- firstCalledF));
- if (Callees.size() > 1) {
- for (std::vector<GlobalValue*>::const_iterator CalleesI =
- Callees.begin()+1, CalleesE = Callees.end();
- CalleesI != CalleesE; ++CalleesI) {
- Function *calledF = dyn_cast<Function>(*CalleesI);
- FuncECs.unionSetsWith(firstCalledF, calledF);
- CallInstTargets.insert(std::pair<CallInst*,Function*>
- (&CSI->getCallInst(), calledF));
- }
- }
- } else {
- std::cerr << "No targets " << CSI->getCallInst();
- }
- }
- }
- }
-
- // Print the equivalence classes
- DEBUG(printFuncECs());
-}
-
-bool PoolAllocate::run(Module &M) {
- if (M.begin() == M.end()) return false;
- CurModule = &M;
-
- AddPoolPrototypes();
- BU = &getAnalysis<BUDataStructures>();
-
- buildIndirectFunctionSets(M);
-
- std::map<Function*, Function*> FuncMap;
-
- // 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;
- }
-
- // 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;
- }
-
- ++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);
- }
-
- if (CollapseFlag)
- std::cerr << "Pool Allocation successful! However all data structures may not be pool allocated\n";
-
- return true;
-}
-
-
-// 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...
- FunctionType *PoolInitTy =
- FunctionType::get(Type::VoidTy,
- make_vector<const Type*>(PoolDescPtr, Type::UIntTy, 0),
- false);
- PoolInit = CurModule->getOrInsertFunction("poolinit", PoolInitTy);
-
- // Get pooldestroy function...
- std::vector<const Type*> PDArgs(1, PoolDescPtr);
- FunctionType *PoolDestroyTy =
- FunctionType::get(Type::VoidTy, PDArgs, false);
- PoolDestroy = CurModule->getOrInsertFunction("pooldestroy", PoolDestroyTy);
-
- // Get the poolalloc function...
- FunctionType *PoolAllocTy = FunctionType::get(VoidPtrTy, PDArgs, false);
- PoolAlloc = CurModule->getOrInsertFunction("poolalloc", PoolAllocTy);
-
- // Get the poolfree function...
- PDArgs.push_back(VoidPtrTy); // Pointer to free
- FunctionType *PoolFreeTy = FunctionType::get(Type::VoidTy, PDArgs, false);
- PoolFree = CurModule->getOrInsertFunction("poolfree", PoolFreeTy);
-
- // The poolallocarray function
- FunctionType *PoolAllocArrayTy =
- FunctionType::get(VoidPtrTy,
- make_vector<const Type*>(PoolDescPtr, Type::UIntTy, 0),
- false);
- PoolAllocArray = CurModule->getOrInsertFunction("poolallocarray",
- PoolAllocArrayTy);
-
-}
-
-// Inline the DSGraphs of functions corresponding to the potential targets at
-// indirect call sites into the DS Graph of the callee.
-// This is required to know what pools to create/pass at the call site in the
-// caller
-//
-void PoolAllocate::InlineIndirectCalls(Function &F, DSGraph &G,
- hash_set<Function*> &visited) {
- std::vector<DSCallSite> callSites = G.getFunctionCalls();
-
- visited.insert(&F);
-
- // For each indirect call site in the function, inline all the potential
- // targets
- for (std::vector<DSCallSite>::iterator CSI = callSites.begin(),
- CSE = callSites.end(); CSI != CSE; ++CSI) {
- if (CSI->isIndirectCall()) {
- CallInst &CI = CSI->getCallInst();
- std::pair<std::multimap<CallInst*, Function*>::iterator,
- std::multimap<CallInst*, Function*>::iterator> Targets =
- CallInstTargets.equal_range(&CI);
- for (std::multimap<CallInst*, Function*>::iterator TFI = Targets.first,
- TFE = Targets.second; TFI != TFE; ++TFI) {
- DSGraph &TargetG = BU->getDSGraph(*TFI->second);
- // Call the function recursively if the callee is not yet inlined
- // and if it hasn't been visited in this sequence of calls
- // The latter is dependent on the fact that the graphs of all functions
- // in an SCC are actually the same
- if (InlinedFuncs.find(TFI->second) == InlinedFuncs.end() &&
- visited.find(TFI->second) == visited.end()) {
- InlineIndirectCalls(*TFI->second, TargetG, visited);
- }
- G.mergeInGraph(*CSI, *TFI->second, TargetG, DSGraph::KeepModRefBits |
- DSGraph::KeepAllocaBit | DSGraph::DontCloneCallNodes |
- DSGraph::DontCloneAuxCallNodes);
- }
- }
- }
-
- // Mark this function as one whose graph is inlined with its indirect
- // function targets' DS Graphs. This ensures that every function is inlined
- // exactly once
- InlinedFuncs.insert(&F);
-}
-
-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
- std::vector<DSNode*> &Nodes = G.getNodes();
- 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.
- if (!FuncECs.findClass(&F)) {
- FI.PoolArgFirst = FI.PoolArgLast = 0;
- } else {
- if (EqClass2LastPoolArg.find(FuncECs.findClass(&F)) !=
- EqClass2LastPoolArg.end())
- FI.PoolArgFirst = FI.PoolArgLast =
- EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1;
- else
- FI.PoolArgFirst = FI.PoolArgLast = 0;
- }
-
- // 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.
- 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);
- }
-
- // Marked the returned node as alive...
- if (DSNode *RetNode = G.getReturnNodeFor(F).getNode())
- if (RetNode->isHeapNode())
- 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
-
- 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;
- }
-
- FI.PoolArgLast += MarkedNodes.size();
-
-
- if (FuncECs.findClass(&F)) {
- // Update the equivalence class last pool argument information
- // only if there actually were pool arguments to the function.
- // Also, there is no entry for the Eq. class in EqClass2LastPoolArg
- // if there are no functions in the equivalence class with pool arguments.
- if (FI.PoolArgLast != FI.PoolArgFirst)
- EqClass2LastPoolArg[FuncECs.findClass(&F)] = FI.PoolArgLast - 1;
- }
-
-}
-
-// MakeFunctionClone - If the specified function needs to be modified for pool
-// allocation support, make a clone of it, adding additional arguments as
-// neccesary, and return it. If not, just return null.
-//
-Function *PoolAllocate::MakeFunctionClone(Function &F) {
-
- DSGraph &G = BU->getDSGraph(F);
-
- std::vector<DSNode*> &Nodes = G.getNodes();
- if (Nodes.empty())
- return 0;
-
- FuncInfo &FI = FunctionInfo[&F];
-
- hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
-
- if (!FuncECs.findClass(&F)) {
- // Not in any equivalence class
- if (MarkedNodes.empty())
- return 0;
- } else {
- // No need to clone if there are no pool arguments in any function in the
- // equivalence class
- if (!EqClass2LastPoolArg.count(FuncECs.findClass(&F)))
- return 0;
- }
-
- // 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;
- if (!FuncECs.findClass(&F)) {
- ArgTys.reserve(OldFuncTy->getParamTypes().size() + MarkedNodes.size());
- FI.ArgNodes.reserve(MarkedNodes.size());
- for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
- E = MarkedNodes.end(); I != E; ++I) {
- ArgTys.push_back(PoolDescPtr); // Add the appropriate # of pool descs
- FI.ArgNodes.push_back(*I);
- }
- if (FI.ArgNodes.empty()) return 0; // No nodes to be pool allocated!
-
- }
- 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);
- FI.ArgNodes.reserve(EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1);
-
- for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i) {
- ArgTys.push_back(PoolDescPtr); // Add the appropriate # of pool
- // descs
- }
-
- for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
- E = MarkedNodes.end(); I != E; ++I) {
- FI.ArgNodes.push_back(*I);
- }
-
- assert ((FI.ArgNodes.size() == (unsigned) (FI.PoolArgLast -
- FI.PoolArgFirst)) &&
- "Number of ArgNodes equal to the number of pool arguments used by this function");
-
- if (FI.ArgNodes.empty()) return 0;
- }
-
-
- ArgTys.insert(ArgTys.end(), OldFuncTy->getParamTypes().begin(),
- OldFuncTy->getParamTypes().end());
-
-
- // Create the new function prototype
- FunctionType *FuncTy = FunctionType::get(OldFuncTy->getReturnType(), ArgTys,
- OldFuncTy->isVarArg());
- // Create the new function...
- Function *New = new Function(FuncTy, GlobalValue::InternalLinkage,
- F.getName(), F.getParent());
-
- // Set the rest of the new arguments names to be PDa<n> and add entries to the
- // pool descriptors map
- std::map<DSNode*, Value*> &PoolDescriptors = FI.PoolDescriptors;
- Function::aiterator NI = New->abegin();
-
- if (FuncECs.findClass(&F)) {
- // If the function belongs to an equivalence class
- for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i,
- ++NI)
- NI->setName("PDa");
-
- NI = New->abegin();
- if (FI.PoolArgFirst > 0)
- for (int i = 0; i < FI.PoolArgFirst; ++NI, ++i)
- ;
-
- for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI)
- PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
-
- NI = New->abegin();
- if (EqClass2LastPoolArg.count(FuncECs.findClass(&F)))
- for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i, ++NI)
- ;
- } else {
- // If the function does not belong to an equivalence class
- if (FI.ArgNodes.size())
- for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI) {
- NI->setName("PDa"); // Add pd entry
- PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
- }
- NI = New->abegin();
- if (FI.ArgNodes.size())
- for (unsigned i = 0; i < FI.ArgNodes.size(); ++NI, ++i)
- ;
- }
-
- // Map the existing arguments of the old function to the corresponding
- // arguments of the new function.
- std::map<const Value*, Value*> ValueMap;
- if (NI != New->aend())
- for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I, ++NI) {
- ValueMap[I] = NI;
- NI->setName(I->getName());
- }
-
- // Populate the value map with all of the globals in the program.
- // FIXME: This should be unneccesary!
- Module &M = *F.getParent();
- for (Module::iterator I = M.begin(), E=M.end(); I!=E; ++I) ValueMap[I] = I;
- for (Module::giterator I = M.gbegin(), E=M.gend(); I!=E; ++I) ValueMap[I] = I;
-
- // Perform the cloning.
- std::vector<ReturnInst*> Returns;
- CloneFunctionInto(New, &F, ValueMap, Returns);
-
- // Invert the ValueMap into the NewToOldValueMap
- std::map<Value*, const Value*> &NewToOldValueMap = FI.NewToOldValueMap;
- for (std::map<const Value*, Value*>::iterator I = ValueMap.begin(),
- E = ValueMap.end(); I != E; ++I)
- NewToOldValueMap.insert(std::make_pair(I->second, I->first));
-
- return FI.Clone = New;
-}
-
-
-// processFunction - Pool allocate any data structures which are contained in
-// the specified function...
-//
-void PoolAllocate::ProcessFunctionBody(Function &F, Function &NewF) {
- DSGraph &G = BU->getDSGraph(F);
-
- std::vector<DSNode*> &Nodes = G.getNodes();
- if (Nodes.empty()) return; // Quick exit if nothing to do...
-
- FuncInfo &FI = FunctionInfo[&F]; // Get FuncInfo for F
- hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
-
- DEBUG(std::cerr << "[" << F.getName() << "] Pool Allocate: ");
-
- // 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]);
-
- DEBUG(std::cerr << NodesToPA.size() << " nodes to pool allocate\n");
- if (!NodesToPA.empty()) {
- // Create pool construction/destruction code
- std::map<DSNode*, Value*> &PoolDescriptors = FI.PoolDescriptors;
- CreatePools(NewF, NodesToPA, PoolDescriptors);
- }
-
- // Transform the body of the function now...
- TransformFunctionBody(NewF, F, G, FI);
-}
-
-
-// CreatePools - This creates the pool initialization and destruction code for
-// the DSNodes specified by the NodesToPA list. This adds an entry to the
-// PoolDescriptors map for each DSNode.
-//
-void PoolAllocate::CreatePools(Function &F,
- const std::vector<DSNode*> &NodesToPA,
- std::map<DSNode*, Value*> &PoolDescriptors) {
- // Find all of the return nodes in the CFG...
- std::vector<BasicBlock*> ReturnNodes;
- for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
- if (isa<ReturnInst>(I->getTerminator()))
- ReturnNodes.push_back(I);
-
- TargetData &TD = getAnalysis<TargetData>();
-
- // Loop over all of the pools, inserting code into the entry block of the
- // function for the initialization and code in the exit blocks for
- // destruction.
- //
- Instruction *InsertPoint = F.front().begin();
- for (unsigned i = 0, e = NodesToPA.size(); i != e; ++i) {
- DSNode *Node = NodesToPA[i];
-
- // Create a new alloca instruction for the pool...
- Value *AI = new AllocaInst(PoolDescType, 0, "PD", InsertPoint);
-
- Value *ElSize;
-
- // Void types in DS graph are never used
- if (Node->getType() != Type::VoidTy)
- ElSize = ConstantUInt::get(Type::UIntTy, TD.getTypeSize(Node->getType()));
- else {
- DEBUG(std::cerr << "Potential node collapsing in " << F.getName()
- << ". All Data Structures may not be pool allocated\n");
- ElSize = ConstantUInt::get(Type::UIntTy, 0);
- }
-
- // Insert the call to initialize the pool...
- new CallInst(PoolInit, make_vector(AI, ElSize, 0), "", InsertPoint);
-
- // Update the PoolDescriptors map
- PoolDescriptors.insert(std::make_pair(Node, AI));
-
- // Insert a call to pool destroy before each return inst in the function
- for (unsigned r = 0, e = ReturnNodes.size(); r != e; ++r)
- new CallInst(PoolDestroy, make_vector(AI, 0), "",
- ReturnNodes[r]->getTerminator());
- }
-}
-
-
-namespace {
- /// FuncTransform - This class implements transformation required of pool
- /// allocated functions.
- struct FuncTransform : public InstVisitor<FuncTransform> {
- PoolAllocate &PAInfo;
- DSGraph &G; // The Bottom-up DS Graph
- DSGraph &TDG; // The Top-down DS Graph
- FuncInfo &FI;
-
- FuncTransform(PoolAllocate &P, DSGraph &g, DSGraph &tdg, FuncInfo &fi)
- : PAInfo(P), G(g), TDG(tdg), FI(fi) {
- }
-
- void visitMallocInst(MallocInst &MI);
- void visitFreeInst(FreeInst &FI);
- void visitCallInst(CallInst &CI);
-
- // The following instructions are never modified by pool allocation
- void visitBranchInst(BranchInst &I) { }
- void visitBinaryOperator(Instruction &I) { }
- void visitShiftInst (ShiftInst &I) { }
- void visitSwitchInst (SwitchInst &I) { }
- void visitCastInst (CastInst &I) { }
- void visitAllocaInst(AllocaInst &I) { }
- void visitLoadInst(LoadInst &I) { }
- void visitGetElementPtrInst (GetElementPtrInst &I) { }
-
- void visitReturnInst(ReturnInst &I);
- void visitStoreInst (StoreInst &I);
- void visitPHINode(PHINode &I);
-
- void visitInstruction(Instruction &I) {
- std::cerr << "PoolAllocate does not recognize this instruction\n";
- abort();
- }
-
- private:
- DSNodeHandle& getDSNodeHFor(Value *V) {
- // if (isa<Constant>(V))
- // return DSNodeHandle();
-
- if (!FI.NewToOldValueMap.empty()) {
- // If the NewToOldValueMap is in effect, use it.
- std::map<Value*,const Value*>::iterator I = FI.NewToOldValueMap.find(V);
- if (I != FI.NewToOldValueMap.end())
- V = (Value*)I->second;
- }
-
- return G.getScalarMap()[V];
- }
-
- DSNodeHandle& getTDDSNodeHFor(Value *V) {
- if (!FI.NewToOldValueMap.empty()) {
- // If the NewToOldValueMap is in effect, use it.
- std::map<Value*,const Value*>::iterator I = FI.NewToOldValueMap.find(V);
- if (I != FI.NewToOldValueMap.end())
- V = (Value*)I->second;
- }
-
- return TDG.getScalarMap()[V];
- }
-
- Value *getPoolHandle(Value *V) {
- DSNode *Node = getDSNodeHFor(V).getNode();
- // Get the pool handle for this DSNode...
- std::map<DSNode*, Value*>::iterator I = FI.PoolDescriptors.find(Node);
-
- if (I != FI.PoolDescriptors.end()) {
- // Check that the node pointed to by V in the TD DS graph is not
- // collapsed
- DSNode *TDNode = getTDDSNodeHFor(V).getNode();
- if (TDNode->getType() != Type::VoidTy)
- return I->second;
- else {
- PAInfo.CollapseFlag = 1;
- return 0;
- }
- }
- else
- return 0;
-
- }
-
- bool isFuncPtr(Value *V);
-
- Function* getFuncClass(Value *V);
-
- Value* retCloneIfFunc(Value *V);
- };
-}
-
-void PoolAllocate::TransformFunctionBody(Function &F, Function &OldF,
- DSGraph &G, FuncInfo &FI) {
- FuncTransform(*this, G, TDDS->getDSGraph(OldF), FI).visit(F);
-}
-
-// Returns true if V is a function pointer
-bool FuncTransform::isFuncPtr(Value *V) {
- if (const PointerType *PTy = dyn_cast<PointerType>(V->getType()))
- return isa<FunctionType>(PTy->getElementType());
- return false;
-}
-
-// Given a function pointer, return the function eq. class if one exists
-Function* FuncTransform::getFuncClass(Value *V) {
- // Look at DSGraph and see if the set of of functions it could point to
- // are pool allocated.
-
- if (!isFuncPtr(V))
- return 0;
-
- // Two cases:
- // if V is a constant
- if (Function *theFunc = dyn_cast<Function>(V)) {
- if (!PAInfo.FuncECs.findClass(theFunc))
- // If this function does not belong to any equivalence class
- return 0;
- if (PAInfo.EqClass2LastPoolArg.count(PAInfo.FuncECs.findClass(theFunc)))
- return PAInfo.FuncECs.findClass(theFunc);
- else
- return 0;
- }
-
- // if V is not a constant
- DSNode *DSN = TDG.getNodeForValue(V).getNode();
- if (!DSN) {
- return 0;
- }
- const std::vector<GlobalValue*> &Callees = DSN->getGlobals();
- if (Callees.size() > 0) {
- Function *calledF = dyn_cast<Function>(*Callees.begin());
- assert(PAInfo.FuncECs.findClass(calledF) && "should exist in some eq. class");
- if (PAInfo.EqClass2LastPoolArg.count(PAInfo.FuncECs.findClass(calledF)))
- return PAInfo.FuncECs.findClass(calledF);
- }
-
- return 0;
-}
-
-// Returns the clone if V is a static function (not a pointer) and belongs
-// to an equivalence class i.e. is pool allocated
-Value* FuncTransform::retCloneIfFunc(Value *V) {
- if (Function *fixedFunc = dyn_cast<Function>(V))
- if (getFuncClass(V))
- return PAInfo.getFuncInfo(*fixedFunc)->Clone;
-
- return 0;
-}
-
-void FuncTransform::visitReturnInst (ReturnInst &RI) {
- if (RI.getNumOperands())
- if (Value *clonedFunc = retCloneIfFunc(RI.getOperand(0))) {
- // Cast the clone of RI.getOperand(0) to the non-pool-allocated type
- CastInst *CastI = new CastInst(clonedFunc, RI.getOperand(0)->getType(),
- "tmp", &RI);
- // Insert return instruction that returns the casted value
- ReturnInst *RetI = new ReturnInst(CastI, &RI);
-
- // Remove original return instruction
- RI.getParent()->getInstList().erase(&RI);
-
- if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&RI);
- assert(II != FI.NewToOldValueMap.end() &&
- "RI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(RetI, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-}
-
-void FuncTransform::visitStoreInst (StoreInst &SI) {
- // Check if a constant function is being stored
- if (Value *clonedFunc = retCloneIfFunc(SI.getOperand(0))) {
- CastInst *CastI = new CastInst(clonedFunc, SI.getOperand(0)->getType(),
- "tmp", &SI);
- StoreInst *StoreI = new StoreInst(CastI, SI.getOperand(1), &SI);
- SI.getParent()->getInstList().erase(&SI);
-
- // Update the NewToOldValueMap if this is a clone
- if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&SI);
- assert(II != FI.NewToOldValueMap.end() &&
- "SI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(StoreI, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-}
-
-void FuncTransform::visitPHINode(PHINode &PI) {
- // If any of the operands of the PHI node is a constant function pointer
- // that is cloned, the cast instruction has to be inserted at the end of the
- // previous basic block
-
- if (isFuncPtr(&PI)) {
- PHINode *V = new PHINode(PI.getType(), PI.getName(), &PI);
- for (unsigned i = 0 ; i < PI.getNumIncomingValues(); ++i) {
- if (Value *clonedFunc = retCloneIfFunc(PI.getIncomingValue(i))) {
- // Insert CastInst at the end of PI.getIncomingBlock(i)
- BasicBlock::iterator BBI = --PI.getIncomingBlock(i)->end();
- // BBI now points to the terminator instruction of the basic block.
- CastInst *CastI = new CastInst(clonedFunc, PI.getType(), "tmp", BBI);
- V->addIncoming(CastI, PI.getIncomingBlock(i));
- } else {
- V->addIncoming(PI.getIncomingValue(i), PI.getIncomingBlock(i));
- }
-
- }
- PI.replaceAllUsesWith(V);
- PI.getParent()->getInstList().erase(&PI);
-
- DSGraph::ScalarMapTy &SM = G.getScalarMap();
- DSGraph::ScalarMapTy::iterator PII = SM.find(&PI);
-
- // Update Scalar map of DSGraph if this is one of the original functions
- // Otherwise update the NewToOldValueMap
- if (PII != SM.end()) {
- SM.insert(std::make_pair(V, PII->second));
- SM.erase(PII); // Destroy the PHINode
- } else {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&PI);
- assert(II != FI.NewToOldValueMap.end() &&
- "PhiI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(V, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-}
-
-void FuncTransform::visitMallocInst(MallocInst &MI) {
- // Get the pool handle for the node that this contributes to...
- Value *PH = getPoolHandle(&MI);
-
- // NB: PH is zero even if the node is collapsed
- if (PH == 0) return;
-
- // Insert a call to poolalloc
- Value *V;
- if (MI.isArrayAllocation())
- V = new CallInst(PAInfo.PoolAllocArray,
- make_vector(PH, MI.getOperand(0), 0),
- MI.getName(), &MI);
- else
- V = new CallInst(PAInfo.PoolAlloc, make_vector(PH, 0),
- MI.getName(), &MI);
-
- MI.setName(""); // Nuke MIs name
-
- Value *Casted = V;
-
- // Cast to the appropriate type if necessary
- if (V->getType() != MI.getType()) {
- Casted = new CastInst(V, MI.getType(), V->getName(), &MI);
- }
-
- // Update def-use info
- MI.replaceAllUsesWith(Casted);
-
- // Remove old malloc instruction
- MI.getParent()->getInstList().erase(&MI);
-
- DSGraph::ScalarMapTy &SM = G.getScalarMap();
- DSGraph::ScalarMapTy::iterator MII = SM.find(&MI);
-
- // If we are modifying the original function, update the DSGraph...
- if (MII != SM.end()) {
- // V and Casted now point to whatever the original malloc did...
- SM.insert(std::make_pair(V, MII->second));
- if (V != Casted)
- SM.insert(std::make_pair(Casted, MII->second));
- SM.erase(MII); // The malloc is now destroyed
- } else { // Otherwise, update the NewToOldValueMap
- std::map<Value*,const Value*>::iterator MII =
- FI.NewToOldValueMap.find(&MI);
- assert(MII != FI.NewToOldValueMap.end() && "MI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(V, MII->second));
- if (V != Casted)
- FI.NewToOldValueMap.insert(std::make_pair(Casted, MII->second));
- FI.NewToOldValueMap.erase(MII);
- }
-}
-
-void FuncTransform::visitFreeInst(FreeInst &FrI) {
- Value *Arg = FrI.getOperand(0);
- Value *PH = getPoolHandle(Arg); // Get the pool handle for this DSNode...
- if (PH == 0) return;
- // Insert a cast and a call to poolfree...
- Value *Casted = Arg;
- if (Arg->getType() != PointerType::get(Type::SByteTy))
- Casted = new CastInst(Arg, PointerType::get(Type::SByteTy),
- Arg->getName()+".casted", &FrI);
-
- CallInst *FreeI = new CallInst(PAInfo.PoolFree, make_vector(PH, Casted, 0),
- "", &FrI);
- // Delete the now obsolete free instruction...
- FrI.getParent()->getInstList().erase(&FrI);
-
- // Update the NewToOldValueMap if this is a clone
- if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&FrI);
- assert(II != FI.NewToOldValueMap.end() &&
- "FrI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(FreeI, II->second));
- FI.NewToOldValueMap.erase(II);
- }
-}
-
-static void CalcNodeMapping(DSNodeHandle& Caller, DSNodeHandle& Callee,
- std::map<DSNode*, DSNode*> &NodeMapping) {
- DSNode *CalleeNode = Callee.getNode();
- DSNode *CallerNode = Caller.getNode();
-
- unsigned CalleeOffset = Callee.getOffset();
- unsigned CallerOffset = Caller.getOffset();
-
- if (CalleeNode == 0) return;
-
- // If callee has a node and caller doesn't, then a constant argument was
- // passed by the caller
- if (CallerNode == 0) {
- NodeMapping.insert(NodeMapping.end(), std::make_pair(CalleeNode,
- (DSNode *) 0));
- }
-
- // Map the callee node to the caller node.
- // NB: The callee node could be of a different type. Eg. if it points to the
- // field of a struct that the caller points to
- std::map<DSNode*, DSNode*>::iterator I = NodeMapping.find(CalleeNode);
- if (I != NodeMapping.end()) { // Node already in map...
- assert(I->second == CallerNode &&
- "Node maps to different nodes on paths?");
- } else {
- NodeMapping.insert(I, std::make_pair(CalleeNode, CallerNode));
-
- if (CalleeNode->getType() != CallerNode->getType() && CallerOffset == 0)
- DEBUG(std::cerr << "NB: Mapping of nodes between different types\n");
-
- // Recursively map the callee links to the caller links starting from the
- // offset in the node into which they are mapped.
- // Being a BU Graph, the callee ought to have smaller number of links unless
- // there is collapsing in the caller
- unsigned numCallerLinks = CallerNode->getNumLinks() - CallerOffset;
- unsigned numCalleeLinks = CalleeNode->getNumLinks() - CalleeOffset;
-
- if (numCallerLinks > 0) {
- if (numCallerLinks < numCalleeLinks) {
- DEBUG(std::cerr << "Potential node collapsing in caller\n");
- for (unsigned i = 0, e = numCalleeLinks; i != e; ++i)
- CalcNodeMapping(CallerNode->getLink(((i%numCallerLinks) << DS::PointerShift) + CallerOffset), CalleeNode->getLink((i << DS::PointerShift) + CalleeOffset), NodeMapping);
- } else {
- for (unsigned i = 0, e = numCalleeLinks; i != e; ++i)
- CalcNodeMapping(CallerNode->getLink((i << DS::PointerShift) + CallerOffset), CalleeNode->getLink((i << DS::PointerShift) + CalleeOffset), NodeMapping);
- }
- } else if (numCalleeLinks > 0) {
- DEBUG(std::cerr <<
- "Caller has unexpanded node, due to indirect call perhaps!\n");
- }
- }
-}
-
-void FuncTransform::visitCallInst(CallInst &CI) {
- Function *CF = CI.getCalledFunction();
-
- // optimization for function pointers that are basically gotten from a cast
- // with only one use and constant expressions with casts in them
- if (!CF) {
- if (CastInst* CastI = dyn_cast<CastInst>(CI.getCalledValue())) {
- if (isa<Function>(CastI->getOperand(0)) &&
- CastI->getOperand(0)->getType() == CastI->getType())
- CF = dyn_cast<Function>(CastI->getOperand(0));
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(CI.getOperand(0))) {