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 }