blob: 64616cd8fb649d745fad51be2c4a994de580a619 [file] [log] [blame]
Chris Lattner64fd9352002-03-28 18:08:31 +00001//===-- PoolAllocate.cpp - Pool Allocation Pass ---------------------------===//
2//
3// This transform changes programs so that disjoint data structures are
4// allocated out of different pools of memory, increasing locality and shrinking
5// pointer size.
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Transforms/IPO/PoolAllocate.h"
10#include "llvm/Analysis/DataStructure.h"
11#include "llvm/Pass.h"
Chris Lattner175f37c2002-03-29 03:40:59 +000012#include "llvm/Module.h"
13#include "llvm/Function.h"
14#include "llvm/iMemory.h"
Chris Lattnere0618ca2002-03-29 05:50:20 +000015#include "llvm/iTerminators.h"
16#include "llvm/iOther.h"
17#include "llvm/ConstantVals.h"
18#include "llvm/Target/TargetData.h"
19#include "Support/STLExtras.h"
Chris Lattner175f37c2002-03-29 03:40:59 +000020#include <algorithm>
Chris Lattner64fd9352002-03-28 18:08:31 +000021
Chris Lattnere0618ca2002-03-29 05:50:20 +000022// FIXME: This is dependant on the sparc backend layout conventions!!
23static TargetData TargetData("test");
24
Chris Lattner175f37c2002-03-29 03:40:59 +000025// Define the pass class that we implement...
Chris Lattner64fd9352002-03-28 18:08:31 +000026namespace {
Chris Lattner175f37c2002-03-29 03:40:59 +000027 class PoolAllocate : public Pass {
28 // PoolTy - The type of a scalar value that contains a pool pointer.
29 PointerType *PoolTy;
30 public:
31
32 PoolAllocate() {
33 // Initialize the PoolTy instance variable, since the type never changes.
34 vector<const Type*> PoolElements;
35 PoolElements.push_back(PointerType::get(Type::SByteTy));
36 PoolElements.push_back(Type::UIntTy);
37 PoolTy = PointerType::get(StructType::get(PoolElements));
38 // PoolTy = { sbyte*, uint }*
39
40 CurModule = 0; DS = 0;
41 PoolInit = PoolDestroy = PoolAlloc = PoolFree = 0;
Chris Lattner64fd9352002-03-28 18:08:31 +000042 }
43
Chris Lattner175f37c2002-03-29 03:40:59 +000044 bool run(Module *M);
45
46 // getAnalysisUsageInfo - This function requires data structure information
47 // to be able to see what is pool allocatable.
Chris Lattner64fd9352002-03-28 18:08:31 +000048 //
49 virtual void getAnalysisUsageInfo(Pass::AnalysisSet &Required,
Chris Lattner175f37c2002-03-29 03:40:59 +000050 Pass::AnalysisSet &,Pass::AnalysisSet &) {
Chris Lattner64fd9352002-03-28 18:08:31 +000051 Required.push_back(DataStructure::ID);
52 }
Chris Lattner175f37c2002-03-29 03:40:59 +000053
54 private:
55 // CurModule - The module being processed.
56 Module *CurModule;
57
58 // DS - The data structure graph for the module being processed.
59 DataStructure *DS;
60
61 // Prototypes that we add to support pool allocation...
62 Function *PoolInit, *PoolDestroy, *PoolAlloc, *PoolFree;
63
64 // addPoolPrototypes - Add prototypes for the pool methods to the specified
65 // module and update the Pool* instance variables to point to them.
66 //
67 void addPoolPrototypes(Module *M);
68
69 // processFunction - Convert a function to use pool allocation where
70 // available.
71 //
72 bool processFunction(Function *F);
Chris Lattner64fd9352002-03-28 18:08:31 +000073 };
74}
75
Chris Lattner175f37c2002-03-29 03:40:59 +000076
77
78// isNotPoolableAlloc - This is a predicate that returns true if the specified
79// allocation node in a data structure graph is eligable for pool allocation.
80//
81static bool isNotPoolableAlloc(const AllocDSNode *DS) {
Chris Lattnere0618ca2002-03-29 05:50:20 +000082 if (DS->isAllocaNode()) return true; // Do not pool allocate alloca's.
Chris Lattner175f37c2002-03-29 03:40:59 +000083
84 MallocInst *MI = cast<MallocInst>(DS->getAllocation());
85 if (MI->isArrayAllocation() && !isa<Constant>(MI->getArraySize()))
Chris Lattnere0618ca2002-03-29 05:50:20 +000086 return true; // Do not allow variable size allocations...
Chris Lattner175f37c2002-03-29 03:40:59 +000087
Chris Lattnere0618ca2002-03-29 05:50:20 +000088 return false;
Chris Lattner175f37c2002-03-29 03:40:59 +000089}
90
91
92// processFunction - Convert a function to use pool allocation where
93// available.
94//
95bool PoolAllocate::processFunction(Function *F) {
96 // Get the closed datastructure graph for the current function... if there are
97 // any allocations in this graph that are not escaping, we need to pool
98 // allocate them here!
99 //
100 FunctionDSGraph &IPGraph = DS->getClosedDSGraph(F);
101
102 // Get all of the allocations that do not escape the current function. Since
103 // they are still live (they exist in the graph at all), this means we must
104 // have scalar references to these nodes, but the scalars are never returned.
105 //
106 std::vector<AllocDSNode*> Allocs;
107 IPGraph.getNonEscapingAllocations(Allocs);
108
109 // Filter out allocations that we cannot handle. Currently, this includes
110 // variable sized array allocations and alloca's (which we do not want to
111 // pool allocate)
112 //
113 Allocs.erase(remove_if(Allocs.begin(), Allocs.end(), isNotPoolableAlloc),
114 Allocs.end());
115
116
117 if (Allocs.empty()) return false; // Nothing to do.
118
119 // Loop through the value map looking for scalars that refer to nonescaping
120 // allocations.
121 //
122 map<Value*, PointerValSet> &ValMap = IPGraph.getValueMap();
123 vector<pair<Value*, AllocDSNode*> > Scalars;
124
125 for (map<Value*, PointerValSet>::iterator I = ValMap.begin(),
126 E = ValMap.end(); I != E; ++I) {
127 const PointerValSet &PVS = I->second; // Set of things pointed to by scalar
128 // Check to see if the scalar points to anything that is an allocation...
129 for (unsigned i = 0, e = PVS.size(); i != e; ++i)
130 if (AllocDSNode *Alloc = dyn_cast<AllocDSNode>(PVS[i].Node)) {
131 assert(PVS[i].Index == 0 && "Nonzero not handled yet!");
132
133 // If the allocation is in the nonescaping set...
134 if (find(Allocs.begin(), Allocs.end(), Alloc) != Allocs.end())
135 // Add it to the list of scalars we have
136 Scalars.push_back(make_pair(I->first, Alloc));
137 }
138 }
139
140 cerr << "In '" << F->getName()
141 << "': Found the following values that point to poolable nodes:\n";
142
143 for (unsigned i = 0, e = Scalars.size(); i != e; ++i)
144 Scalars[i].first->dump();
Chris Lattnere0618ca2002-03-29 05:50:20 +0000145
146 // FIXME: This should use an IP version of the UnifyAllExits pass!
147 vector<BasicBlock*> ReturnNodes;
148 for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I)
149 if (isa<ReturnInst>((*I)->getTerminator()))
150 ReturnNodes.push_back(*I);
151
152
153 // Create the code that goes in the entry and exit nodes for the method...
154 vector<Instruction*> EntryNodeInsts;
155 for (unsigned i = 0, e = Allocs.size(); i != e; ++i) {
156 // Add an allocation and a free for each pool...
157 AllocaInst *PoolAlloc = new AllocaInst(PoolTy, 0, "pool");
158 EntryNodeInsts.push_back(PoolAlloc);
159
160 AllocationInst *AI = Allocs[i]->getAllocation();
161
162 // Initialize the pool. We need to know how big each allocation is. For
163 // our purposes here, we assume we are allocating a scalar, or array of
164 // constant size.
165 //
166 unsigned ElSize = TargetData.getTypeSize(AI->getAllocatedType());
167 ElSize *= cast<ConstantUInt>(AI->getArraySize())->getValue();
168
169 vector<Value*> Args;
170 Args.push_back(PoolAlloc); // Pool to initialize
171 Args.push_back(ConstantUInt::get(Type::UIntTy, ElSize));
172 EntryNodeInsts.push_back(new CallInst(PoolInit, Args));
173
174 // Destroy the pool...
175 Args.pop_back();
176
177 for (unsigned EN = 0, ENE = ReturnNodes.size(); EN != ENE; ++EN) {
178 Instruction *Destroy = new CallInst(PoolDestroy, Args);
179
180 // Insert it before the return instruction...
181 BasicBlock *RetNode = ReturnNodes[EN];
182 RetNode->getInstList().insert(RetNode->end()-1, Destroy);
183 }
184 }
185
186 // Insert the entry node code into the entry block...
187 F->getEntryNode()->getInstList().insert(F->getEntryNode()->begin()+1,
188 EntryNodeInsts.begin(),
189 EntryNodeInsts.end());
190
Chris Lattner175f37c2002-03-29 03:40:59 +0000191 return false;
192}
193
194
Chris Lattner175f37c2002-03-29 03:40:59 +0000195// addPoolPrototypes - Add prototypes for the pool methods to the specified
196// module and update the Pool* instance variables to point to them.
197//
198void PoolAllocate::addPoolPrototypes(Module *M) {
Chris Lattnere0618ca2002-03-29 05:50:20 +0000199 // Get PoolInit function...
200 vector<const Type*> Args;
201 Args.push_back(PoolTy); // Pool to initialize
202 Args.push_back(Type::UIntTy); // Num bytes per element
203 FunctionType *PoolInitTy = FunctionType::get(Type::VoidTy, Args, false);
204 PoolInit = M->getOrInsertFunction("poolinit", PoolInitTy);
Chris Lattner175f37c2002-03-29 03:40:59 +0000205
Chris Lattnere0618ca2002-03-29 05:50:20 +0000206 // Get pooldestroy function...
207 Args.pop_back(); // Only takes a pool...
208 FunctionType *PoolDestroyTy = FunctionType::get(Type::VoidTy, Args, false);
209 PoolDestroy = M->getOrInsertFunction("pooldestroy", PoolDestroyTy);
210
211 const Type *PtrVoid = PointerType::get(Type::SByteTy);
212
213 // Get the poolalloc function...
214 FunctionType *PoolAllocTy = FunctionType::get(PtrVoid, Args, false);
215 PoolAlloc = M->getOrInsertFunction("poolalloc", PoolAllocTy);
216
217 // Get the poolfree function...
218 Args.push_back(PtrVoid);
219 FunctionType *PoolFreeTy = FunctionType::get(Type::VoidTy, Args, false);
220 PoolFree = M->getOrInsertFunction("poolfree", PoolFreeTy);
221
222 // Add the %PoolTy type to the symbol table of the module...
223 M->addTypeName("PoolTy", PoolTy->getElementType());
Chris Lattner175f37c2002-03-29 03:40:59 +0000224}
225
226
227bool PoolAllocate::run(Module *M) {
228 addPoolPrototypes(M);
229 CurModule = M;
230
231 DS = &getAnalysis<DataStructure>();
232 bool Changed = false;
233 for (Module::iterator I = M->begin(); I != M->end(); ++I)
234 if (!(*I)->isExternal())
235 Changed |= processFunction(*I);
236
237 CurModule = 0;
238 DS = 0;
239 return false;
240}
241
242
243// createPoolAllocatePass - Global function to access the functionality of this
244// pass...
245//
Chris Lattner64fd9352002-03-28 18:08:31 +0000246Pass *createPoolAllocatePass() { return new PoolAllocate(); }