Mercurial > projects > ldc
comparison gen/passes/GarbageCollect2Stack.cpp @ 1424:ad999630aa35
Teach -dgc2stack to preserve the call graph. This should allow for more
efficient execution by the pass manager.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Thu, 28 May 2009 02:14:01 +0200 |
parents | 67ac63740c7f |
children | c363d131c1ef |
comparison
equal
deleted
inserted
replaced
1423:42bd767ec5a4 | 1424:ad999630aa35 |
---|---|
28 #include "llvm/Intrinsics.h" | 28 #include "llvm/Intrinsics.h" |
29 #include "llvm/Support/CallSite.h" | 29 #include "llvm/Support/CallSite.h" |
30 #include "llvm/Support/CommandLine.h" | 30 #include "llvm/Support/CommandLine.h" |
31 #include "llvm/Support/IRBuilder.h" | 31 #include "llvm/Support/IRBuilder.h" |
32 #include "llvm/Analysis/CaptureTracking.h" | 32 #include "llvm/Analysis/CaptureTracking.h" |
33 #include "llvm/Analysis/CallGraph.h" | |
33 #include "llvm/Analysis/ValueTracking.h" | 34 #include "llvm/Analysis/ValueTracking.h" |
34 #include "llvm/Analysis/LoopInfo.h" | 35 #include "llvm/Analysis/LoopInfo.h" |
35 #include "llvm/Target/TargetData.h" | 36 #include "llvm/Target/TargetData.h" |
36 #include "llvm/ADT/StringMap.h" | 37 #include "llvm/ADT/StringMap.h" |
37 #include "llvm/ADT/Statistic.h" | 38 #include "llvm/ADT/Statistic.h" |
41 | 42 |
42 STATISTIC(NumGcToStack, "Number of calls promoted to constant-size allocas"); | 43 STATISTIC(NumGcToStack, "Number of calls promoted to constant-size allocas"); |
43 STATISTIC(NumToDynSize, "Number of calls promoted to dynamically-sized allocas"); | 44 STATISTIC(NumToDynSize, "Number of calls promoted to dynamically-sized allocas"); |
44 STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); | 45 STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); |
45 | 46 |
46 //===----------------------------------------------------------------------===// | |
47 // Helper functions | |
48 //===----------------------------------------------------------------------===// | |
49 | |
50 void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len) { | |
51 Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); | |
52 | |
53 Module *M = B.GetInsertBlock()->getParent()->getParent(); | |
54 const Type* Tys[1]; | |
55 Tys[0] = Len->getType(); | |
56 Value *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); | |
57 Value *Align = ConstantInt::get(Type::Int32Ty, 1); | |
58 | |
59 B.CreateCall4(MemSet, Dst, Val, Len, Align); | |
60 } | |
61 | |
62 static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) { | |
63 EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len); | |
64 } | |
65 | |
66 | |
67 //===----------------------------------------------------------------------===// | |
68 // Helpers for specific types of GC calls. | |
69 //===----------------------------------------------------------------------===// | |
70 | 47 |
71 namespace { | 48 namespace { |
72 struct Analysis { | 49 struct Analysis { |
73 TargetData& TD; | 50 TargetData& TD; |
74 const Module& M; | 51 const Module& M; |
52 CallGraph* CG; | |
53 CallGraphNode* CGNode; | |
75 | 54 |
76 const Type* getTypeFor(Value* typeinfo) const; | 55 const Type* getTypeFor(Value* typeinfo) const; |
77 }; | 56 }; |
78 | 57 } |
58 | |
59 //===----------------------------------------------------------------------===// | |
60 // Helper functions | |
61 //===----------------------------------------------------------------------===// | |
62 | |
63 void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len, | |
64 const Analysis& A) { | |
65 Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); | |
66 | |
67 Module *M = B.GetInsertBlock()->getParent()->getParent(); | |
68 const Type* Tys[1]; | |
69 Tys[0] = Len->getType(); | |
70 Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); | |
71 Value *Align = ConstantInt::get(Type::Int32Ty, 1); | |
72 | |
73 CallSite CS = B.CreateCall4(MemSet, Dst, Val, Len, Align); | |
74 if (A.CGNode) | |
75 A.CGNode->addCalledFunction(CS, A.CG->getOrInsertFunction(MemSet)); | |
76 } | |
77 | |
78 static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len, | |
79 const Analysis& A) { | |
80 EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len, A); | |
81 } | |
82 | |
83 | |
84 //===----------------------------------------------------------------------===// | |
85 // Helpers for specific types of GC calls. | |
86 //===----------------------------------------------------------------------===// | |
87 | |
88 namespace { | |
79 class FunctionInfo { | 89 class FunctionInfo { |
80 protected: | 90 protected: |
81 const Type* Ty; | 91 const Type* Ty; |
82 | 92 |
83 public: | 93 public: |
172 uint64_t size = A.TD.getTypeStoreSize(Ty); | 182 uint64_t size = A.TD.getTypeStoreSize(Ty); |
173 Value* TypeSize = ConstantInt::get(arrSize->getType(), size); | 183 Value* TypeSize = ConstantInt::get(arrSize->getType(), size); |
174 // Use the original B to put initialization at the | 184 // Use the original B to put initialization at the |
175 // allocation site. | 185 // allocation site. |
176 Value* Size = B.CreateMul(TypeSize, arrSize); | 186 Value* Size = B.CreateMul(TypeSize, arrSize); |
177 EmitMemZero(B, alloca, Size); | 187 EmitMemZero(B, alloca, Size, A); |
178 } | 188 } |
179 | 189 |
180 return alloca; | 190 return alloca; |
181 } | 191 } |
182 }; | 192 }; |
257 bool runOnFunction(Function &F); | 267 bool runOnFunction(Function &F); |
258 | 268 |
259 virtual void getAnalysisUsage(AnalysisUsage &AU) const { | 269 virtual void getAnalysisUsage(AnalysisUsage &AU) const { |
260 AU.addRequired<TargetData>(); | 270 AU.addRequired<TargetData>(); |
261 AU.addRequired<LoopInfo>(); | 271 AU.addRequired<LoopInfo>(); |
272 AU.addPreserved<CallGraph>(); | |
262 } | 273 } |
263 }; | 274 }; |
264 char GarbageCollect2Stack::ID = 0; | 275 char GarbageCollect2Stack::ID = 0; |
265 } // end anonymous namespace. | 276 } // end anonymous namespace. |
266 | 277 |
282 KnownFunctions["_d_newarrayvT"] = &NewArrayVT; | 293 KnownFunctions["_d_newarrayvT"] = &NewArrayVT; |
283 KnownFunctions["_d_newarrayT"] = &NewArrayT; | 294 KnownFunctions["_d_newarrayT"] = &NewArrayT; |
284 KnownFunctions["_d_allocclass"] = &AllocClass; | 295 KnownFunctions["_d_allocclass"] = &AllocClass; |
285 } | 296 } |
286 | 297 |
287 static void RemoveCall(Instruction* Inst) { | 298 static void RemoveCall(CallSite CS, const Analysis& A) { |
288 if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) { | 299 if (CS.isInvoke()) { |
300 InvokeInst* Invoke = cast<InvokeInst>(CS.getInstruction()); | |
289 // If this was an invoke instruction, we need to do some extra | 301 // If this was an invoke instruction, we need to do some extra |
290 // work to preserve the control flow. | 302 // work to preserve the control flow. |
291 | 303 |
292 // First notify the exception landing pad block that we won't be | 304 // First notify the exception landing pad block that we won't be |
293 // going there anymore. | 305 // going there anymore. |
294 Invoke->getUnwindDest()->removePredecessor(Invoke->getParent()); | 306 Invoke->getUnwindDest()->removePredecessor(Invoke->getParent()); |
295 // Create a branch to the "normal" destination. | 307 // Create a branch to the "normal" destination. |
296 BranchInst::Create(Invoke->getNormalDest(), Invoke->getParent()); | 308 BranchInst::Create(Invoke->getNormalDest(), Invoke->getParent()); |
297 } | 309 } |
298 // Remove the runtime call. | 310 // Remove the runtime call. |
299 Inst->eraseFromParent(); | 311 if (A.CGNode) |
312 A.CGNode->removeCallEdgeFor(CS); | |
313 CS.getInstruction()->eraseFromParent(); | |
300 } | 314 } |
301 | 315 |
302 /// runOnFunction - Top level algorithm. | 316 /// runOnFunction - Top level algorithm. |
303 /// | 317 /// |
304 bool GarbageCollect2Stack::runOnFunction(Function &F) { | 318 bool GarbageCollect2Stack::runOnFunction(Function &F) { |
305 DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); | 319 DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); |
306 | 320 |
307 TargetData &TD = getAnalysis<TargetData>(); | 321 TargetData &TD = getAnalysis<TargetData>(); |
308 const LoopInfo &LI = getAnalysis<LoopInfo>(); | 322 const LoopInfo &LI = getAnalysis<LoopInfo>(); |
309 | 323 CallGraph* CG = getAnalysisIfAvailable<CallGraph>(); |
310 Analysis A = { TD, *M }; | 324 CallGraphNode* CGNode = CG ? (*CG)[&F] : NULL; |
325 | |
326 Analysis A = { TD, *M, CG, CGNode }; | |
311 | 327 |
312 BasicBlock& Entry = F.getEntryBlock(); | 328 BasicBlock& Entry = F.getEntryBlock(); |
313 | 329 |
314 IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); | 330 IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); |
315 | 331 |
349 FunctionInfo* info = OMI->getValue(); | 365 FunctionInfo* info = OMI->getValue(); |
350 | 366 |
351 if (Inst->use_empty() && info->SafeToDelete) { | 367 if (Inst->use_empty() && info->SafeToDelete) { |
352 Changed = true; | 368 Changed = true; |
353 NumDeleted++; | 369 NumDeleted++; |
354 RemoveCall(Inst); | 370 RemoveCall(CS, A); |
355 continue; | 371 continue; |
356 } | 372 } |
357 | 373 |
358 DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); | 374 DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); |
359 | 375 |
372 // uses of the runtime call with the alloca. | 388 // uses of the runtime call with the alloca. |
373 if (newVal->getType() != Inst->getType()) | 389 if (newVal->getType() != Inst->getType()) |
374 newVal = Builder.CreateBitCast(newVal, Inst->getType()); | 390 newVal = Builder.CreateBitCast(newVal, Inst->getType()); |
375 Inst->replaceAllUsesWith(newVal); | 391 Inst->replaceAllUsesWith(newVal); |
376 | 392 |
377 RemoveCall(Inst); | 393 RemoveCall(CS, A); |
378 } | 394 } |
379 } | 395 } |
380 | 396 |
381 return Changed; | 397 return Changed; |
382 } | 398 } |