Mercurial > projects > ldc
comparison gen/passes/SimplifyDRuntimeCalls.cpp @ 1507:f86fd3b77285
Eliminate comparisons between GC allocations and constants. This removes some
`assert(this !is null)`s when member functions get inlined.
Also tweak pass order a bit.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sat, 20 Jun 2009 14:28:59 +0200 |
parents | e5b57fd8307c |
children | ad7f2f1862d6 |
comparison
equal
deleted
inserted
replaced
1506:76936858d1c6 | 1507:f86fd3b77285 |
---|---|
41 /// corresponds to one library call. | 41 /// corresponds to one library call. |
42 namespace { | 42 namespace { |
43 class VISIBILITY_HIDDEN LibCallOptimization { | 43 class VISIBILITY_HIDDEN LibCallOptimization { |
44 protected: | 44 protected: |
45 Function *Caller; | 45 Function *Caller; |
46 bool* Changed; | |
46 const TargetData *TD; | 47 const TargetData *TD; |
47 AliasAnalysis *AA; | 48 AliasAnalysis *AA; |
48 | 49 |
49 /// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*. | 50 /// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*. |
50 Value *CastToCStr(Value *V, IRBuilder<> &B); | 51 Value *CastToCStr(Value *V, IRBuilder<> &B); |
62 /// performed. If it returns CI, then it transformed the call and CI is to be | 63 /// performed. If it returns CI, then it transformed the call and CI is to be |
63 /// deleted. If it returns something else, replace CI with the new value and | 64 /// deleted. If it returns something else, replace CI with the new value and |
64 /// delete CI. | 65 /// delete CI. |
65 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0; | 66 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0; |
66 | 67 |
67 Value *OptimizeCall(CallInst *CI, const TargetData &TD, | 68 Value *OptimizeCall(CallInst *CI, bool& Changed, const TargetData &TD, |
68 AliasAnalysis& AA, IRBuilder<> &B) { | 69 AliasAnalysis& AA, IRBuilder<> &B) { |
69 Caller = CI->getParent()->getParent(); | 70 Caller = CI->getParent()->getParent(); |
71 this->Changed = &Changed; | |
70 this->TD = &TD; | 72 this->TD = &TD; |
71 this->AA = &AA; | 73 this->AA = &AA; |
72 return CallOptimizer(CI->getCalledFunction(), CI, B); | 74 return CallOptimizer(CI->getCalledFunction(), CI, B); |
73 } | 75 } |
74 }; | 76 }; |
179 } | 181 } |
180 return 0; | 182 return 0; |
181 } | 183 } |
182 }; | 184 }; |
183 | 185 |
184 /// DeleteUnusedOpt - remove libcall if the return value is unused. | 186 /// AllocationOpt - Common optimizations for various GC allocations. |
185 struct VISIBILITY_HIDDEN DeleteUnusedOpt : public LibCallOptimization { | 187 struct VISIBILITY_HIDDEN AllocationOpt : public LibCallOptimization { |
186 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { | 188 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { |
189 // Allocations are never equal to constants, so remove any equality | |
190 // comparisons to constants. (Most importantly comparisons to null at | |
191 // the start of inlined member functions) | |
192 for (CallInst::use_iterator I = CI->use_begin(), E = CI->use_end() ; I != E;) { | |
193 Instruction* User = cast<Instruction>(*I++); | |
194 | |
195 if (ICmpInst* Cmp = dyn_cast<ICmpInst>(User)) { | |
196 if (!Cmp->isEquality()) | |
197 continue; | |
198 Constant* C = 0; | |
199 if ((C = dyn_cast<Constant>(Cmp->getOperand(0))) | |
200 || (C = dyn_cast<Constant>(Cmp->getOperand(1)))) { | |
201 Value* Result = ConstantInt::get(Type::Int1Ty, !Cmp->isTrueWhenEqual()); | |
202 Cmp->replaceAllUsesWith(Result); | |
203 // Don't delete the comparison because there may be an | |
204 // iterator to it. Instead, set the operands to constants | |
205 // and let dead code elimination clean it up later. | |
206 // (It doesn't matter that this changes the value of the | |
207 // icmp because it's not used anymore anyway) | |
208 Cmp->setOperand(0, C); | |
209 Cmp->setOperand(1, C); | |
210 *Changed = true; | |
211 } | |
212 } | |
213 } | |
214 | |
215 // If it's not used (anymore), pre-emptively GC it. | |
187 if (CI->use_empty()) | 216 if (CI->use_empty()) |
188 return CI; | 217 return CI; |
189 return 0; | 218 return 0; |
190 } | 219 } |
191 }; | 220 }; |
243 ArraySetLengthOpt ArraySetLength; | 272 ArraySetLengthOpt ArraySetLength; |
244 ArrayCastLenOpt ArrayCastLen; | 273 ArrayCastLenOpt ArrayCastLen; |
245 ArraySliceCopyOpt ArraySliceCopy; | 274 ArraySliceCopyOpt ArraySliceCopy; |
246 | 275 |
247 // GC allocations | 276 // GC allocations |
248 DeleteUnusedOpt DeleteUnused; | 277 AllocationOpt Allocation; |
249 | 278 |
250 public: | 279 public: |
251 static char ID; // Pass identification | 280 static char ID; // Pass identification |
252 SimplifyDRuntimeCalls() : FunctionPass(&ID) {} | 281 SimplifyDRuntimeCalls() : FunctionPass(&ID) {} |
253 | 282 |
288 * 'readonly', since LLVM doesn't need our help figuring out when those can | 317 * 'readonly', since LLVM doesn't need our help figuring out when those can |
289 * be deleted. | 318 * be deleted. |
290 * (We can't mark allocating calls as readonly/readnone because they don't | 319 * (We can't mark allocating calls as readonly/readnone because they don't |
291 * return the same pointer every time when called with the same arguments) | 320 * return the same pointer every time when called with the same arguments) |
292 */ | 321 */ |
293 Optimizations["_d_allocmemoryT"] = &DeleteUnused; | 322 Optimizations["_d_allocmemoryT"] = &Allocation; |
294 Optimizations["_d_newarrayT"] = &DeleteUnused; | 323 Optimizations["_d_newarrayT"] = &Allocation; |
295 Optimizations["_d_newarrayiT"] = &DeleteUnused; | 324 Optimizations["_d_newarrayiT"] = &Allocation; |
296 Optimizations["_d_newarrayvT"] = &DeleteUnused; | 325 Optimizations["_d_newarrayvT"] = &Allocation; |
297 Optimizations["_d_newarraymT"] = &DeleteUnused; | 326 Optimizations["_d_newarraymT"] = &Allocation; |
298 Optimizations["_d_newarraymiT"] = &DeleteUnused; | 327 Optimizations["_d_newarraymiT"] = &Allocation; |
299 Optimizations["_d_newarraymvT"] = &DeleteUnused; | 328 Optimizations["_d_newarraymvT"] = &Allocation; |
300 Optimizations["_d_allocclass"] = &DeleteUnused; | 329 Optimizations["_d_allocclass"] = &Allocation; |
301 } | 330 } |
302 | 331 |
303 | 332 |
304 /// runOnFunction - Top level algorithm. | 333 /// runOnFunction - Top level algorithm. |
305 /// | 334 /// |
351 | 380 |
352 // Set the builder to the instruction after the call. | 381 // Set the builder to the instruction after the call. |
353 Builder.SetInsertPoint(BB, I); | 382 Builder.SetInsertPoint(BB, I); |
354 | 383 |
355 // Try to optimize this call. | 384 // Try to optimize this call. |
356 Value *Result = OMI->second->OptimizeCall(CI, TD, AA, Builder); | 385 Value *Result = OMI->second->OptimizeCall(CI, Changed, TD, AA, Builder); |
357 if (Result == 0) continue; | 386 if (Result == 0) continue; |
358 | 387 |
359 DEBUG(DOUT << "SimplifyDRuntimeCalls simplified: " << *CI; | 388 DEBUG(DOUT << "SimplifyDRuntimeCalls simplified: " << *CI; |
360 DOUT << " into: " << *Result << "\n"); | 389 DOUT << " into: " << *Result << "\n"); |
361 | 390 |