Mercurial > projects > ldc
comparison gen/passes/GarbageCollect2Stack.cpp @ 1306:b61db48127fd
Some refactoring
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Wed, 06 May 2009 15:58:15 +0200 |
parents | 8215dbf0e09f |
children | e2ec50329af1 |
comparison
equal
deleted
inserted
replaced
1305:8215dbf0e09f | 1306:b61db48127fd |
---|---|
45 //===----------------------------------------------------------------------===// | 45 //===----------------------------------------------------------------------===// |
46 // GarbageCollect2Stack Pass Implementation | 46 // GarbageCollect2Stack Pass Implementation |
47 //===----------------------------------------------------------------------===// | 47 //===----------------------------------------------------------------------===// |
48 | 48 |
49 namespace { | 49 namespace { |
50 struct FunctionInfo { | 50 struct Analysis { |
51 TargetData& TD; | |
52 const Module& M; | |
53 | |
54 const Type* getTypeFor(Value* typeinfo) const; | |
55 }; | |
56 | |
57 class FunctionInfo { | |
58 protected: | |
59 const Type* Ty; | |
60 | |
61 public: | |
51 unsigned TypeInfoArgNr; | 62 unsigned TypeInfoArgNr; |
63 bool SafeToDelete; | |
64 | |
65 // Analyze the current call, filling in some fields. Returns true if | |
66 // this is an allocation we can stack-allocate. | |
67 virtual bool analyze(CallSite CS, const Analysis& A) { | |
68 Value* TypeInfo = CS.getArgument(TypeInfoArgNr); | |
69 Ty = A.getTypeFor(TypeInfo); | |
70 return (Ty != NULL); | |
71 } | |
72 | |
73 // Returns the alloca to replace this call. | |
74 // It will always be inserted before the call. | |
75 virtual AllocaInst* promote(CallSite CS) { | |
76 NumGcToStack++; | |
77 | |
78 Instruction* Begin = CS.getCaller()->getEntryBlock().begin(); | |
79 return new AllocaInst(Ty, ".nongc_mem", Begin); | |
80 } | |
81 | |
82 FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete) | |
83 : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {} | |
84 }; | |
85 | |
86 class ArrayFI : public FunctionInfo { | |
87 Value* arrSize; | |
52 int ArrSizeArgNr; | 88 int ArrSizeArgNr; |
53 bool SafeToDelete; | 89 |
54 | 90 public: |
55 FunctionInfo(unsigned typeInfoArgNr, int arrSizeArgNr, bool safeToDelete) | 91 ArrayFI(unsigned tiArgNr, bool safeToDelete, unsigned arrSizeArgNr) |
56 : TypeInfoArgNr(typeInfoArgNr), ArrSizeArgNr(arrSizeArgNr), | 92 : FunctionInfo(tiArgNr, safeToDelete), ArrSizeArgNr(arrSizeArgNr) {} |
57 SafeToDelete(safeToDelete) {} | 93 |
94 virtual bool analyze(CallSite CS, const Analysis& A) { | |
95 if (!FunctionInfo::analyze(CS, A)) | |
96 return false; | |
97 | |
98 arrSize = CS.getArgument(ArrSizeArgNr); | |
99 const IntegerType* SizeType = | |
100 dyn_cast<IntegerType>(arrSize->getType()); | |
101 if (!SizeType) | |
102 return false; | |
103 unsigned bits = SizeType->getBitWidth(); | |
104 if (bits > 32) { | |
105 // The array size of an alloca must be an i32, so make sure | |
106 // the conversion is safe. | |
107 APInt Mask = APInt::getHighBitsSet(bits, bits - 32); | |
108 APInt KnownZero(bits, 0), KnownOne(bits, 0); | |
109 ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &A.TD); | |
110 if ((KnownZero & Mask) != Mask) | |
111 return false; | |
112 } | |
113 // Extract the element type from the array type. | |
114 const StructType* ArrTy = dyn_cast<StructType>(Ty); | |
115 assert(ArrTy && "Dynamic array type not a struct?"); | |
116 assert(isa<IntegerType>(ArrTy->getElementType(0))); | |
117 const PointerType* PtrTy = | |
118 cast<PointerType>(ArrTy->getElementType(1)); | |
119 Ty = PtrTy->getElementType(); | |
120 return true; | |
121 } | |
122 | |
123 virtual AllocaInst* promote(CallSite CS) { | |
124 Instruction* I = CS.getInstruction(); | |
125 IRBuilder<> Builder(I->getParent(), I); | |
126 | |
127 // If the allocation is of constant size it's best to put it in the | |
128 // entry block, so do so if we're not already there. | |
129 // For dynamically-sized allocations it's best to avoid the overhead | |
130 // of allocating them if possible, so leave those where they are. | |
131 // While we're at it, update statistics too. | |
132 if (isa<Constant>(arrSize)) { | |
133 BasicBlock& Entry = CS.getCaller()->getEntryBlock(); | |
134 if (Builder.GetInsertBlock() != &Entry) | |
135 Builder.SetInsertPoint(&Entry, Entry.begin()); | |
136 NumGcToStack++; | |
137 } else { | |
138 NumToDynSize++; | |
139 } | |
140 | |
141 // Convert array size to 32 bits if necessary | |
142 arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); | |
143 | |
144 return Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); | |
145 } | |
58 }; | 146 }; |
59 | 147 |
60 /// This pass replaces GC calls with alloca's | 148 /// This pass replaces GC calls with alloca's |
61 /// | 149 /// |
62 class VISIBILITY_HIDDEN GarbageCollect2Stack : public FunctionPass { | 150 class VISIBILITY_HIDDEN GarbageCollect2Stack : public FunctionPass { |
63 StringMap<FunctionInfo*> KnownFunctions; | 151 StringMap<FunctionInfo*> KnownFunctions; |
64 Module* M; | 152 Module* M; |
65 | 153 |
66 public: | 154 FunctionInfo AllocMemoryT; |
155 ArrayFI NewArrayVT; | |
156 | |
157 public: | |
67 static char ID; // Pass identification | 158 static char ID; // Pass identification |
68 GarbageCollect2Stack() : FunctionPass(&ID) {} | 159 GarbageCollect2Stack(); |
69 | 160 |
70 bool doInitialization(Module &M); | 161 bool doInitialization(Module &M) { |
162 this->M = &M; | |
163 } | |
71 | 164 |
72 bool runOnFunction(Function &F); | 165 bool runOnFunction(Function &F); |
73 | 166 |
74 virtual void getAnalysisUsage(AnalysisUsage &AU) const { | 167 virtual void getAnalysisUsage(AnalysisUsage &AU) const { |
75 AU.addRequired<TargetData>(); | 168 AU.addRequired<TargetData>(); |
76 AU.addRequired<LoopInfo>(); | 169 AU.addRequired<LoopInfo>(); |
77 } | 170 } |
78 | |
79 private: | |
80 const Type* getTypeFor(Value* typeinfo); | |
81 }; | 171 }; |
82 char GarbageCollect2Stack::ID = 0; | 172 char GarbageCollect2Stack::ID = 0; |
83 } // end anonymous namespace. | 173 } // end anonymous namespace. |
84 | 174 |
85 static RegisterPass<GarbageCollect2Stack> | 175 static RegisterPass<GarbageCollect2Stack> |
88 // Public interface to the pass. | 178 // Public interface to the pass. |
89 FunctionPass *createGarbageCollect2Stack() { | 179 FunctionPass *createGarbageCollect2Stack() { |
90 return new GarbageCollect2Stack(); | 180 return new GarbageCollect2Stack(); |
91 } | 181 } |
92 | 182 |
93 bool GarbageCollect2Stack::doInitialization(Module &M) { | 183 GarbageCollect2Stack::GarbageCollect2Stack() |
94 this->M = &M; | 184 : FunctionPass(&ID), |
95 KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, -1, true); | 185 AllocMemoryT(0, true), |
96 KnownFunctions["_d_newarrayvT"] = new FunctionInfo(0, 1, true); | 186 NewArrayVT(0, true, 1) |
187 { | |
188 KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; | |
189 KnownFunctions["_d_newarrayvT"] = &NewArrayVT; | |
97 } | 190 } |
98 | 191 |
99 static void RemoveCall(Instruction* Inst) { | 192 static void RemoveCall(Instruction* Inst) { |
100 if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) { | 193 if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) { |
101 // If this was an invoke instruction, we need to do some extra | 194 // If this was an invoke instruction, we need to do some extra |
116 bool GarbageCollect2Stack::runOnFunction(Function &F) { | 209 bool GarbageCollect2Stack::runOnFunction(Function &F) { |
117 DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); | 210 DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); |
118 | 211 |
119 TargetData &TD = getAnalysis<TargetData>(); | 212 TargetData &TD = getAnalysis<TargetData>(); |
120 const LoopInfo &LI = getAnalysis<LoopInfo>(); | 213 const LoopInfo &LI = getAnalysis<LoopInfo>(); |
214 | |
215 Analysis A = { TD, *M }; | |
121 | 216 |
122 BasicBlock& Entry = F.getEntryBlock(); | 217 BasicBlock& Entry = F.getEntryBlock(); |
123 | 218 |
124 IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); | 219 IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); |
125 | 220 |
165 continue; | 260 continue; |
166 } | 261 } |
167 | 262 |
168 DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); | 263 DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); |
169 | 264 |
170 Value* TypeInfo = CS.getArgument(info->TypeInfoArgNr); | 265 if (!info->analyze(CS, A) || PointerMayBeCaptured(Inst, true)) |
171 const Type* Ty = getTypeFor(TypeInfo); | |
172 if (!Ty) { | |
173 continue; | 266 continue; |
174 } | |
175 | |
176 Value* arrSize = 0; | |
177 if (info->ArrSizeArgNr != -1) { | |
178 arrSize = CS.getArgument(info->ArrSizeArgNr); | |
179 const IntegerType* SizeType = | |
180 dyn_cast<IntegerType>(arrSize->getType()); | |
181 if (!SizeType) | |
182 continue; | |
183 unsigned bits = SizeType->getBitWidth(); | |
184 if (bits > 32) { | |
185 // The array size of an alloca must be an i32, so make sure | |
186 // the conversion is safe. | |
187 APInt Mask = APInt::getHighBitsSet(bits, bits - 32); | |
188 APInt KnownZero(bits, 0), KnownOne(bits, 0); | |
189 ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &TD); | |
190 if ((KnownZero & Mask) != Mask) | |
191 continue; | |
192 } | |
193 // Extract the element type from the array type. | |
194 const StructType* ArrTy = dyn_cast<StructType>(Ty); | |
195 assert(ArrTy && "Dynamic array type not a struct?"); | |
196 assert(isa<IntegerType>(ArrTy->getElementType(0))); | |
197 const PointerType* PtrTy = | |
198 cast<PointerType>(ArrTy->getElementType(1)); | |
199 Ty = PtrTy->getElementType(); | |
200 } | |
201 | |
202 if (PointerMayBeCaptured(Inst, true)) { | |
203 continue; | |
204 } | |
205 | 267 |
206 // Let's alloca this! | 268 // Let's alloca this! |
207 Changed = true; | 269 Changed = true; |
208 | 270 |
209 IRBuilder<> Builder(BB, I); | 271 Value* newVal = info->promote(CS); |
210 | |
211 // If the allocation is of constant size it's best to put it in the | |
212 // entry block, so do so if we're not already there. | |
213 // For dynamically-sized allocations it's best to avoid the overhead | |
214 // of allocating them if possible, so leave those where they are. | |
215 // While we're at it, update statistics too. | |
216 if (!arrSize || isa<Constant>(arrSize)) { | |
217 if (&*BB != &Entry) | |
218 Builder = AllocaBuilder; | |
219 NumGcToStack++; | |
220 } else { | |
221 NumToDynSize++; | |
222 } | |
223 | |
224 // Convert array size to 32 bits if necessary | |
225 if (arrSize) | |
226 arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); | |
227 | |
228 Value* newVal = Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); | |
229 | 272 |
230 // Make sure the type is the same as it was before, and replace all | 273 // Make sure the type is the same as it was before, and replace all |
231 // uses of the runtime call with the alloca. | 274 // uses of the runtime call with the alloca. |
232 if (newVal->getType() != Inst->getType()) | 275 if (newVal->getType() != Inst->getType()) |
233 newVal = Builder.CreateBitCast(newVal, Inst->getType()); | 276 newVal = new BitCastInst(newVal, Inst->getType(), "", Inst); |
234 Inst->replaceAllUsesWith(newVal); | 277 Inst->replaceAllUsesWith(newVal); |
235 | 278 |
236 RemoveCall(Inst); | 279 RemoveCall(Inst); |
237 } | 280 } |
238 } | 281 } |
239 | 282 |
240 return Changed; | 283 return Changed; |
241 } | 284 } |
242 | 285 |
243 const Type* GarbageCollect2Stack::getTypeFor(Value* typeinfo) { | 286 const Type* Analysis::getTypeFor(Value* typeinfo) const { |
244 GlobalVariable* ti_global = dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts()); | 287 GlobalVariable* ti_global = dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts()); |
245 if (!ti_global) | 288 if (!ti_global) |
246 return NULL; | 289 return NULL; |
247 | 290 |
248 std::string metaname = TD_PREFIX; | 291 std::string metaname = TD_PREFIX; |
249 metaname.append(ti_global->getNameStart(), ti_global->getNameEnd()); | 292 metaname.append(ti_global->getNameStart(), ti_global->getNameEnd()); |
250 | 293 |
251 GlobalVariable* global = M->getGlobalVariable(metaname); | 294 GlobalVariable* global = M.getGlobalVariable(metaname); |
252 if (!global || !global->hasInitializer()) | 295 if (!global || !global->hasInitializer()) |
253 return NULL; | 296 return NULL; |
254 | 297 |
255 MDNode* node = dyn_cast<MDNode>(global->getInitializer()); | 298 MDNode* node = dyn_cast<MDNode>(global->getInitializer()); |
256 if (!node) | 299 if (!node) |