Mercurial > projects > ldc
comparison gen/passes/GarbageCollect2Stack.cpp @ 1554:d6e8d5db259f
LLVMContext changes up to r77366
author | Benjamin Kramer <benny.kra@gmail.com> |
---|---|
date | Thu, 30 Jul 2009 15:25:10 +0200 |
parents | f55ca8a1598c |
children | ed0cffe895ec |
comparison
equal
deleted
inserted
replaced
1553:f55ca8a1598c | 1554:d6e8d5db259f |
---|---|
56 | 56 |
57 //===----------------------------------------------------------------------===// | 57 //===----------------------------------------------------------------------===// |
58 // Helper functions | 58 // Helper functions |
59 //===----------------------------------------------------------------------===// | 59 //===----------------------------------------------------------------------===// |
60 | 60 |
61 void EmitMemSet(LLVMContext& Context, IRBuilder<>& B, Value* Dst, Value* Val, | 61 void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len, |
62 Value* Len, const Analysis& A) { | 62 const Analysis& A) { |
63 Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); | 63 Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); |
64 | 64 |
65 Module *M = B.GetInsertBlock()->getParent()->getParent(); | 65 Module *M = B.GetInsertBlock()->getParent()->getParent(); |
66 const Type* Tys[1]; | 66 const Type* Tys[1]; |
67 Tys[0] = Len->getType(); | 67 Tys[0] = Len->getType(); |
68 Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); | 68 Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); |
69 Value *Align = Context.getConstantInt(Type::Int32Ty, 1); | 69 Value *Align = ConstantInt::get(Type::Int32Ty, 1); |
70 | 70 |
71 CallSite CS = B.CreateCall4(MemSet, Dst, Val, Len, Align); | 71 CallSite CS = B.CreateCall4(MemSet, Dst, Val, Len, Align); |
72 if (A.CGNode) | 72 if (A.CGNode) |
73 A.CGNode->addCalledFunction(CS, A.CG->getOrInsertFunction(MemSet)); | 73 A.CGNode->addCalledFunction(CS, A.CG->getOrInsertFunction(MemSet)); |
74 } | 74 } |
75 | 75 |
76 static void EmitMemZero(LLVMContext& Context, IRBuilder<>& B, Value* Dst, | 76 static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len, |
77 Value* Len, const Analysis& A) { | 77 const Analysis& A) { |
78 EmitMemSet(Context, B, Dst, Context.getConstantInt(Type::Int8Ty, 0), Len, A); | 78 EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len, A); |
79 } | 79 } |
80 | 80 |
81 | 81 |
82 //===----------------------------------------------------------------------===// | 82 //===----------------------------------------------------------------------===// |
83 // Helpers for specific types of GC calls. | 83 // Helpers for specific types of GC calls. |
92 unsigned TypeInfoArgNr; | 92 unsigned TypeInfoArgNr; |
93 bool SafeToDelete; | 93 bool SafeToDelete; |
94 | 94 |
95 // Analyze the current call, filling in some fields. Returns true if | 95 // Analyze the current call, filling in some fields. Returns true if |
96 // this is an allocation we can stack-allocate. | 96 // this is an allocation we can stack-allocate. |
97 virtual bool analyze(LLVMContext& context, CallSite CS, const Analysis& A) { | 97 virtual bool analyze(CallSite CS, const Analysis& A) { |
98 Value* TypeInfo = CS.getArgument(TypeInfoArgNr); | 98 Value* TypeInfo = CS.getArgument(TypeInfoArgNr); |
99 Ty = A.getTypeFor(TypeInfo); | 99 Ty = A.getTypeFor(TypeInfo); |
100 return (Ty != NULL); | 100 return (Ty != NULL); |
101 } | 101 } |
102 | 102 |
103 // Returns the alloca to replace this call. | 103 // Returns the alloca to replace this call. |
104 // It will always be inserted before the call. | 104 // It will always be inserted before the call. |
105 virtual AllocaInst* promote(LLVMContext& context, CallSite CS, IRBuilder<>& B, const Analysis& A) { | 105 virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) { |
106 NumGcToStack++; | 106 NumGcToStack++; |
107 | 107 |
108 Instruction* Begin = CS.getCaller()->getEntryBlock().begin(); | 108 Instruction* Begin = CS.getCaller()->getEntryBlock().begin(); |
109 return new AllocaInst(Ty, ".nongc_mem", Begin); // FIXME: align? | 109 return new AllocaInst(Ty, ".nongc_mem", Begin); // FIXME: align? |
110 } | 110 } |
117 Value* arrSize; | 117 Value* arrSize; |
118 int ArrSizeArgNr; | 118 int ArrSizeArgNr; |
119 bool Initialized; | 119 bool Initialized; |
120 | 120 |
121 public: | 121 public: |
122 ArrayFI(unsigned tiArgNr, bool safeToDelete, | 122 ArrayFI(unsigned tiArgNr, bool safeToDelete, bool initialized, |
123 bool initialized, unsigned arrSizeArgNr) | 123 unsigned arrSizeArgNr) |
124 : FunctionInfo(tiArgNr, safeToDelete), | 124 : FunctionInfo(tiArgNr, safeToDelete), |
125 ArrSizeArgNr(arrSizeArgNr), | 125 ArrSizeArgNr(arrSizeArgNr), |
126 Initialized(initialized) | 126 Initialized(initialized) |
127 {} | 127 {} |
128 | 128 |
129 virtual bool analyze(LLVMContext& context, CallSite CS, const Analysis& A) { | 129 virtual bool analyze(CallSite CS, const Analysis& A) { |
130 if (!FunctionInfo::analyze(context, CS, A)) | 130 if (!FunctionInfo::analyze(CS, A)) |
131 return false; | 131 return false; |
132 | 132 |
133 arrSize = CS.getArgument(ArrSizeArgNr); | 133 arrSize = CS.getArgument(ArrSizeArgNr); |
134 const IntegerType* SizeType = | 134 const IntegerType* SizeType = |
135 dyn_cast<IntegerType>(arrSize->getType()); | 135 dyn_cast<IntegerType>(arrSize->getType()); |
153 cast<PointerType>(ArrTy->getElementType(1)); | 153 cast<PointerType>(ArrTy->getElementType(1)); |
154 Ty = PtrTy->getElementType(); | 154 Ty = PtrTy->getElementType(); |
155 return true; | 155 return true; |
156 } | 156 } |
157 | 157 |
158 virtual AllocaInst* promote(LLVMContext& context, CallSite CS, IRBuilder<>& B, const Analysis& A) { | 158 virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) { |
159 IRBuilder<> Builder = B; | 159 IRBuilder<> Builder = B; |
160 // If the allocation is of constant size it's best to put it in the | 160 // If the allocation is of constant size it's best to put it in the |
161 // entry block, so do so if we're not already there. | 161 // entry block, so do so if we're not already there. |
162 // For dynamically-sized allocations it's best to avoid the overhead | 162 // For dynamically-sized allocations it's best to avoid the overhead |
163 // of allocating them if possible, so leave those where they are. | 163 // of allocating them if possible, so leave those where they are. |
176 AllocaInst* alloca = Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align? | 176 AllocaInst* alloca = Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align? |
177 | 177 |
178 if (Initialized) { | 178 if (Initialized) { |
179 // For now, only zero-init is supported. | 179 // For now, only zero-init is supported. |
180 uint64_t size = A.TD.getTypeStoreSize(Ty); | 180 uint64_t size = A.TD.getTypeStoreSize(Ty); |
181 Value* TypeSize = context.getConstantInt(arrSize->getType(), size); | 181 Value* TypeSize = ConstantInt::get(arrSize->getType(), size); |
182 // Use the original B to put initialization at the | 182 // Use the original B to put initialization at the |
183 // allocation site. | 183 // allocation site. |
184 Value* Size = B.CreateMul(TypeSize, arrSize); | 184 Value* Size = B.CreateMul(TypeSize, arrSize); |
185 EmitMemZero(context, B, alloca, Size, A); | 185 EmitMemZero(B, alloca, Size, A); |
186 } | 186 } |
187 | 187 |
188 return alloca; | 188 return alloca; |
189 } | 189 } |
190 }; | 190 }; |
191 | 191 |
192 // FunctionInfo for _d_allocclass | 192 // FunctionInfo for _d_allocclass |
193 class AllocClassFI : public FunctionInfo { | 193 class AllocClassFI : public FunctionInfo { |
194 public: | 194 public: |
195 virtual bool analyze(LLVMContext& context, CallSite CS, const Analysis& A) { | 195 virtual bool analyze(CallSite CS, const Analysis& A) { |
196 // This call contains no TypeInfo parameter, so don't call the | 196 // This call contains no TypeInfo parameter, so don't call the |
197 // base class implementation here... | 197 // base class implementation here... |
198 if (CS.arg_size() != 1) | 198 if (CS.arg_size() != 1) |
199 return false; | 199 return false; |
200 Value* arg = CS.getArgument(0)->stripPointerCasts(); | 200 Value* arg = CS.getArgument(0)->stripPointerCasts(); |
221 // those can be ignored) | 221 // those can be ignored) |
222 Constant* hasCustomDelete = dyn_cast<Constant>(MD_GetElement(node, CD_CustomDelete)); | 222 Constant* hasCustomDelete = dyn_cast<Constant>(MD_GetElement(node, CD_CustomDelete)); |
223 if (hasDestructor == NULL || hasCustomDelete == NULL) | 223 if (hasDestructor == NULL || hasCustomDelete == NULL) |
224 return false; | 224 return false; |
225 | 225 |
226 if (context.getConstantExprOr(hasDestructor, hasCustomDelete) | 226 if (ConstantExpr::getOr(hasDestructor, hasCustomDelete) |
227 != context.getConstantIntFalse()) | 227 != A.M.getContext().getFalse()) |
228 return false; | 228 return false; |
229 | 229 |
230 Ty = MD_GetElement(node, CD_BodyType)->getType(); | 230 Ty = MD_GetElement(node, CD_BodyType)->getType(); |
231 return true; | 231 return true; |
232 } | 232 } |
257 public: | 257 public: |
258 static char ID; // Pass identification | 258 static char ID; // Pass identification |
259 GarbageCollect2Stack(); | 259 GarbageCollect2Stack(); |
260 | 260 |
261 bool doInitialization(Module &M) { | 261 bool doInitialization(Module &M) { |
262 Context = &M.getContext(); | |
263 this->M = &M; | 262 this->M = &M; |
264 return false; | 263 return false; |
265 } | 264 } |
266 | 265 |
267 bool runOnFunction(Function &F); | 266 bool runOnFunction(Function &F); |
295 KnownFunctions["_d_newarrayvT"] = &NewArrayVT; | 294 KnownFunctions["_d_newarrayvT"] = &NewArrayVT; |
296 KnownFunctions["_d_newarrayT"] = &NewArrayT; | 295 KnownFunctions["_d_newarrayT"] = &NewArrayT; |
297 KnownFunctions["_d_allocclass"] = &AllocClass; | 296 KnownFunctions["_d_allocclass"] = &AllocClass; |
298 } | 297 } |
299 | 298 |
300 static void RemoveCall(LLVMContext& context, CallSite CS, const Analysis& A) { | 299 static void RemoveCall(CallSite CS, const Analysis& A) { |
301 if (CS.isInvoke()) { | 300 if (CS.isInvoke()) { |
302 InvokeInst* Invoke = cast<InvokeInst>(CS.getInstruction()); | 301 InvokeInst* Invoke = cast<InvokeInst>(CS.getInstruction()); |
303 // If this was an invoke instruction, we need to do some extra | 302 // If this was an invoke instruction, we need to do some extra |
304 // work to preserve the control flow. | 303 // work to preserve the control flow. |
305 | 304 |
306 // Create a "conditional" branch that -simplifycfg can clean up, so we | 305 // Create a "conditional" branch that -simplifycfg can clean up, so we |
307 // can keep using the DominatorTree without updating it. | 306 // can keep using the DominatorTree without updating it. |
308 BranchInst::Create(Invoke->getNormalDest(), Invoke->getUnwindDest(), | 307 BranchInst::Create(Invoke->getNormalDest(), Invoke->getUnwindDest(), |
309 context.getConstantIntTrue(), Invoke->getParent()); | 308 A.M.getContext().getTrue(), Invoke->getParent()); |
310 } | 309 } |
311 // Remove the runtime call. | 310 // Remove the runtime call. |
312 if (A.CGNode) | 311 if (A.CGNode) |
313 A.CGNode->removeCallEdgeFor(CS); | 312 A.CGNode->removeCallEdgeFor(CS); |
314 CS.getInstruction()->eraseFromParent(); | 313 CS.getInstruction()->eraseFromParent(); |
358 FunctionInfo* info = OMI->getValue(); | 357 FunctionInfo* info = OMI->getValue(); |
359 | 358 |
360 if (Inst->use_empty() && info->SafeToDelete) { | 359 if (Inst->use_empty() && info->SafeToDelete) { |
361 Changed = true; | 360 Changed = true; |
362 NumDeleted++; | 361 NumDeleted++; |
363 RemoveCall(*Context, CS, A); | 362 RemoveCall(CS, A); |
364 continue; | 363 continue; |
365 } | 364 } |
366 | 365 |
367 DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *Inst); | 366 DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *Inst); |
368 | 367 |
369 if (!info->analyze(*Context, CS, A) || !isSafeToStackAllocate(Inst, DT)) | 368 if (!info->analyze(CS, A) || !isSafeToStackAllocate(Inst, DT)) |
370 continue; | 369 continue; |
371 | 370 |
372 // Let's alloca this! | 371 // Let's alloca this! |
373 Changed = true; | 372 Changed = true; |
374 | 373 |
375 IRBuilder<> Builder(BB, Inst); | 374 IRBuilder<> Builder(BB, Inst); |
376 Value* newVal = info->promote(*Context, CS, Builder, A); | 375 Value* newVal = info->promote(CS, Builder, A); |
377 | 376 |
378 DEBUG(errs() << "Promoted to: " << *newVal); | 377 DEBUG(errs() << "Promoted to: " << *newVal); |
379 | 378 |
380 // Make sure the type is the same as it was before, and replace all | 379 // Make sure the type is the same as it was before, and replace all |
381 // uses of the runtime call with the alloca. | 380 // uses of the runtime call with the alloca. |
382 if (newVal->getType() != Inst->getType()) | 381 if (newVal->getType() != Inst->getType()) |
383 newVal = Builder.CreateBitCast(newVal, Inst->getType()); | 382 newVal = Builder.CreateBitCast(newVal, Inst->getType()); |
384 Inst->replaceAllUsesWith(newVal); | 383 Inst->replaceAllUsesWith(newVal); |
385 | 384 |
386 RemoveCall(*Context, CS, A); | 385 RemoveCall(CS, A); |
387 } | 386 } |
388 } | 387 } |
389 | 388 |
390 return Changed; | 389 return Changed; |
391 } | 390 } |