Mercurial > projects > ldc
comparison gen/passes/SimplifyDRuntimeCalls.cpp @ 1329:e5b57fd8307c
Turn new _d_array_slice_copy runtime call into memcpy when the slice lengths are
equal and alias analysis says it's safe.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sun, 10 May 2009 04:18:14 +0200 |
parents | c32e27f9a61d |
children | f86fd3b77285 |
comparison
equal
deleted
inserted
replaced
1328:c78fd2d30da1 | 1329:e5b57fd8307c |
---|---|
17 #define DEBUG_TYPE "simplify-drtcalls" | 17 #define DEBUG_TYPE "simplify-drtcalls" |
18 | 18 |
19 #include "Passes.h" | 19 #include "Passes.h" |
20 | 20 |
21 #include "llvm/Pass.h" | 21 #include "llvm/Pass.h" |
22 #include "llvm/Intrinsics.h" | |
22 #include "llvm/Support/IRBuilder.h" | 23 #include "llvm/Support/IRBuilder.h" |
24 #include "llvm/Analysis/AliasAnalysis.h" | |
23 #include "llvm/Analysis/ValueTracking.h" | 25 #include "llvm/Analysis/ValueTracking.h" |
24 #include "llvm/Target/TargetData.h" | 26 #include "llvm/Target/TargetData.h" |
25 #include "llvm/ADT/StringMap.h" | 27 #include "llvm/ADT/StringMap.h" |
26 #include "llvm/ADT/Statistic.h" | 28 #include "llvm/ADT/Statistic.h" |
27 #include "llvm/Support/Compiler.h" | 29 #include "llvm/Support/Compiler.h" |
40 namespace { | 42 namespace { |
41 class VISIBILITY_HIDDEN LibCallOptimization { | 43 class VISIBILITY_HIDDEN LibCallOptimization { |
42 protected: | 44 protected: |
43 Function *Caller; | 45 Function *Caller; |
44 const TargetData *TD; | 46 const TargetData *TD; |
47 AliasAnalysis *AA; | |
48 | |
49 /// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*. | |
50 Value *CastToCStr(Value *V, IRBuilder<> &B); | |
51 | |
52 /// EmitMemCpy - Emit a call to the memcpy function to the builder. This | |
53 /// always expects that the size has type 'intptr_t' and Dst/Src are pointers. | |
54 Value *EmitMemCpy(Value *Dst, Value *Src, Value *Len, | |
55 unsigned Align, IRBuilder<> &B); | |
45 public: | 56 public: |
46 LibCallOptimization() { } | 57 LibCallOptimization() { } |
47 virtual ~LibCallOptimization() {} | 58 virtual ~LibCallOptimization() {} |
48 | 59 |
49 /// CallOptimizer - This pure virtual method is implemented by base classes to | 60 /// CallOptimizer - This pure virtual method is implemented by base classes to |
51 /// performed. If it returns CI, then it transformed the call and CI is to be | 62 /// performed. If it returns CI, then it transformed the call and CI is to be |
52 /// deleted. If it returns something else, replace CI with the new value and | 63 /// deleted. If it returns something else, replace CI with the new value and |
53 /// delete CI. | 64 /// delete CI. |
54 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0; | 65 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)=0; |
55 | 66 |
56 Value *OptimizeCall(CallInst *CI, const TargetData &TD, IRBuilder<> &B) { | 67 Value *OptimizeCall(CallInst *CI, const TargetData &TD, |
68 AliasAnalysis& AA, IRBuilder<> &B) { | |
57 Caller = CI->getParent()->getParent(); | 69 Caller = CI->getParent()->getParent(); |
58 this->TD = &TD; | 70 this->TD = &TD; |
71 this->AA = &AA; | |
59 return CallOptimizer(CI->getCalledFunction(), CI, B); | 72 return CallOptimizer(CI->getCalledFunction(), CI, B); |
60 } | 73 } |
61 }; | 74 }; |
62 } // End anonymous namespace. | 75 } // End anonymous namespace. |
63 | 76 |
77 /// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*. | |
78 Value *LibCallOptimization::CastToCStr(Value *V, IRBuilder<> &B) { | |
79 return B.CreateBitCast(V, PointerType::getUnqual(Type::Int8Ty), "cstr"); | |
80 } | |
81 | |
82 /// EmitMemCpy - Emit a call to the memcpy function to the builder. This always | |
83 /// expects that the size has type 'intptr_t' and Dst/Src are pointers. | |
84 Value *LibCallOptimization::EmitMemCpy(Value *Dst, Value *Src, Value *Len, | |
85 unsigned Align, IRBuilder<> &B) { | |
86 Module *M = Caller->getParent(); | |
87 Intrinsic::ID IID = Intrinsic::memcpy; | |
88 const Type *Tys[1]; | |
89 Tys[0] = Len->getType(); | |
90 Value *MemCpy = Intrinsic::getDeclaration(M, IID, Tys, 1); | |
91 return B.CreateCall4(MemCpy, CastToCStr(Dst, B), CastToCStr(Src, B), Len, | |
92 ConstantInt::get(Type::Int32Ty, Align)); | |
93 } | |
64 | 94 |
65 //===----------------------------------------------------------------------===// | 95 //===----------------------------------------------------------------------===// |
66 // Miscellaneous LibCall Optimizations | 96 // Miscellaneous LibCall Optimizations |
67 //===----------------------------------------------------------------------===// | 97 //===----------------------------------------------------------------------===// |
68 | 98 |
158 return CI; | 188 return CI; |
159 return 0; | 189 return 0; |
160 } | 190 } |
161 }; | 191 }; |
162 | 192 |
193 /// ArraySliceCopyOpt - Turn slice copies into llvm.memcpy when safe | |
194 struct VISIBILITY_HIDDEN ArraySliceCopyOpt : public LibCallOptimization { | |
195 virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { | |
196 // Verify we have a reasonable prototype for _d_array_slice_copy | |
197 const FunctionType *FT = Callee->getFunctionType(); | |
198 const Type* VoidPtrTy = PointerType::getUnqual(Type::Int8Ty); | |
199 if (Callee->arg_size() != 4 || FT->getReturnType() != Type::VoidTy || | |
200 FT->getParamType(0) != VoidPtrTy || | |
201 !isa<IntegerType>(FT->getParamType(1)) || | |
202 FT->getParamType(2) != VoidPtrTy || | |
203 FT->getParamType(3) != FT->getParamType(1)) | |
204 return 0; | |
205 | |
206 Value* Size = CI->getOperand(2); | |
207 | |
208 // Check the lengths match | |
209 if (CI->getOperand(4) != Size) | |
210 return 0; | |
211 | |
212 // Assume unknown size unless we have constant size (that fits in an uint) | |
213 unsigned Sz = ~0U; | |
214 if (ConstantInt* Int = dyn_cast<ConstantInt>(Size)) | |
215 if (Int->getValue().isIntN(32)) | |
216 Sz = Int->getValue().getZExtValue(); | |
217 | |
218 // Check if the pointers may alias | |
219 if (AA->alias(CI->getOperand(1), Sz, CI->getOperand(3), Sz)) | |
220 return 0; | |
221 | |
222 // Equal length and the pointers definitely don't alias, so it's safe to | |
223 // replace the call with memcpy | |
224 return EmitMemCpy(CI->getOperand(1), CI->getOperand(3), Size, 0, B); | |
225 } | |
226 }; | |
227 | |
163 // TODO: More optimizations! :) | 228 // TODO: More optimizations! :) |
164 | 229 |
165 } // end anonymous namespace. | 230 } // end anonymous namespace. |
166 | 231 |
167 //===----------------------------------------------------------------------===// | 232 //===----------------------------------------------------------------------===// |
175 StringMap<LibCallOptimization*> Optimizations; | 240 StringMap<LibCallOptimization*> Optimizations; |
176 | 241 |
177 // Array operations | 242 // Array operations |
178 ArraySetLengthOpt ArraySetLength; | 243 ArraySetLengthOpt ArraySetLength; |
179 ArrayCastLenOpt ArrayCastLen; | 244 ArrayCastLenOpt ArrayCastLen; |
245 ArraySliceCopyOpt ArraySliceCopy; | |
180 | 246 |
181 // GC allocations | 247 // GC allocations |
182 DeleteUnusedOpt DeleteUnused; | 248 DeleteUnusedOpt DeleteUnused; |
183 | 249 |
184 public: | 250 public: |
186 SimplifyDRuntimeCalls() : FunctionPass(&ID) {} | 252 SimplifyDRuntimeCalls() : FunctionPass(&ID) {} |
187 | 253 |
188 void InitOptimizations(); | 254 void InitOptimizations(); |
189 bool runOnFunction(Function &F); | 255 bool runOnFunction(Function &F); |
190 | 256 |
191 bool runOnce(Function &F, const TargetData& TD); | 257 bool runOnce(Function &F, const TargetData& TD, AliasAnalysis& AA); |
192 | 258 |
193 virtual void getAnalysisUsage(AnalysisUsage &AU) const { | 259 virtual void getAnalysisUsage(AnalysisUsage &AU) const { |
194 AU.addRequired<TargetData>(); | 260 AU.addRequired<TargetData>(); |
261 AU.addRequired<AliasAnalysis>(); | |
195 } | 262 } |
196 }; | 263 }; |
197 char SimplifyDRuntimeCalls::ID = 0; | 264 char SimplifyDRuntimeCalls::ID = 0; |
198 } // end anonymous namespace. | 265 } // end anonymous namespace. |
199 | 266 |
210 void SimplifyDRuntimeCalls::InitOptimizations() { | 277 void SimplifyDRuntimeCalls::InitOptimizations() { |
211 // Some array-related optimizations | 278 // Some array-related optimizations |
212 Optimizations["_d_arraysetlengthT"] = &ArraySetLength; | 279 Optimizations["_d_arraysetlengthT"] = &ArraySetLength; |
213 Optimizations["_d_arraysetlengthiT"] = &ArraySetLength; | 280 Optimizations["_d_arraysetlengthiT"] = &ArraySetLength; |
214 Optimizations["_d_array_cast_len"] = &ArrayCastLen; | 281 Optimizations["_d_array_cast_len"] = &ArrayCastLen; |
282 Optimizations["_d_array_slice_copy"] = &ArraySliceCopy; | |
215 | 283 |
216 /* Delete calls to runtime functions which aren't needed if their result is | 284 /* Delete calls to runtime functions which aren't needed if their result is |
217 * unused. That comes down to functions that don't do anything but | 285 * unused. That comes down to functions that don't do anything but |
218 * GC-allocate and initialize some memory. | 286 * GC-allocate and initialize some memory. |
219 * We don't need to do this for functions which are marked 'readnone' or | 287 * We don't need to do this for functions which are marked 'readnone' or |
238 bool SimplifyDRuntimeCalls::runOnFunction(Function &F) { | 306 bool SimplifyDRuntimeCalls::runOnFunction(Function &F) { |
239 if (Optimizations.empty()) | 307 if (Optimizations.empty()) |
240 InitOptimizations(); | 308 InitOptimizations(); |
241 | 309 |
242 const TargetData &TD = getAnalysis<TargetData>(); | 310 const TargetData &TD = getAnalysis<TargetData>(); |
311 AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); | |
243 | 312 |
244 // Iterate to catch opportunities opened up by other optimizations, | 313 // Iterate to catch opportunities opened up by other optimizations, |
245 // such as calls that are only used as arguments to unused calls: | 314 // such as calls that are only used as arguments to unused calls: |
246 // When the second call gets deleted the first call will become unused, but | 315 // When the second call gets deleted the first call will become unused, but |
247 // without iteration we wouldn't notice if we inspected the first call | 316 // without iteration we wouldn't notice if we inspected the first call |
248 // before the second one. | 317 // before the second one. |
249 bool EverChanged = false; | 318 bool EverChanged = false; |
250 bool Changed; | 319 bool Changed; |
251 do { | 320 do { |
252 Changed = runOnce(F, TD); | 321 Changed = runOnce(F, TD, AA); |
253 EverChanged |= Changed; | 322 EverChanged |= Changed; |
254 } while (Changed); | 323 } while (Changed); |
255 | 324 |
256 return EverChanged; | 325 return EverChanged; |
257 } | 326 } |
258 | 327 |
259 bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD) { | 328 bool SimplifyDRuntimeCalls::runOnce(Function &F, const TargetData& TD, AliasAnalysis& AA) { |
260 IRBuilder<> Builder; | 329 IRBuilder<> Builder; |
261 | 330 |
262 bool Changed = false; | 331 bool Changed = false; |
263 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { | 332 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { |
264 for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { | 333 for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) { |
270 Function *Callee = CI->getCalledFunction(); | 339 Function *Callee = CI->getCalledFunction(); |
271 if (Callee == 0 || !Callee->isDeclaration() || | 340 if (Callee == 0 || !Callee->isDeclaration() || |
272 !(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage())) | 341 !(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage())) |
273 continue; | 342 continue; |
274 | 343 |
275 DEBUG(DOUT << "SimplifyDRuntimeCalls inspecting: " << *CI); | |
276 | |
277 // Ignore unknown calls. | 344 // Ignore unknown calls. |
278 const char *CalleeName = Callee->getNameStart(); | 345 const char *CalleeName = Callee->getNameStart(); |
279 StringMap<LibCallOptimization*>::iterator OMI = | 346 StringMap<LibCallOptimization*>::iterator OMI = |
280 Optimizations.find(CalleeName, CalleeName+Callee->getNameLen()); | 347 Optimizations.find(CalleeName, CalleeName+Callee->getNameLen()); |
281 if (OMI == Optimizations.end()) continue; | 348 if (OMI == Optimizations.end()) continue; |
282 | 349 |
350 DEBUG(DOUT << "SimplifyDRuntimeCalls inspecting: " << *CI); | |
351 | |
283 // Set the builder to the instruction after the call. | 352 // Set the builder to the instruction after the call. |
284 Builder.SetInsertPoint(BB, I); | 353 Builder.SetInsertPoint(BB, I); |
285 | 354 |
286 // Try to optimize this call. | 355 // Try to optimize this call. |
287 Value *Result = OMI->second->OptimizeCall(CI, TD, Builder); | 356 Value *Result = OMI->second->OptimizeCall(CI, TD, AA, Builder); |
288 if (Result == 0) continue; | 357 if (Result == 0) continue; |
289 | 358 |
290 DEBUG(DOUT << "SimplifyDRuntimeCalls simplified: " << *CI; | 359 DEBUG(DOUT << "SimplifyDRuntimeCalls simplified: " << *CI; |
291 DOUT << " into: " << *Result << "\n"); | 360 DOUT << " into: " << *Result << "\n"); |
292 | 361 |
294 Changed = true; | 363 Changed = true; |
295 | 364 |
296 if (Result == CI) { | 365 if (Result == CI) { |
297 assert(CI->use_empty()); | 366 assert(CI->use_empty()); |
298 ++NumDeleted; | 367 ++NumDeleted; |
368 AA.deleteValue(CI); | |
299 } else { | 369 } else { |
300 ++NumSimplified; | 370 ++NumSimplified; |
371 AA.replaceWithNewValue(CI, Result); | |
301 | 372 |
302 if (!CI->use_empty()) | 373 if (!CI->use_empty()) |
303 CI->replaceAllUsesWith(Result); | 374 CI->replaceAllUsesWith(Result); |
304 | 375 |
305 if (!Result->hasName()) | 376 if (!Result->hasName()) |