mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	Move library call prototype attribute inference to functionattrs
The simplify-libcalls pass implemented a doInitialization hook to infer function prototype attributes for well-known functions. Given that the simplify-libcalls pass is going away *and* that the functionattrs pass is already in place to deduce function attributes, I am moving this logic to the functionattrs pass. This approach was discussed during patch review: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20121126/157465.html. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177619 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
		| @@ -1,4 +1,4 @@ | |||||||
| //===- FunctionAttrs.cpp - Pass which marks functions readnone or readonly ===// | //===- FunctionAttrs.cpp - Pass which marks functions attributes ----------===// | ||||||
| // | // | ||||||
| //                     The LLVM Compiler Infrastructure | //                     The LLVM Compiler Infrastructure | ||||||
| // | // | ||||||
| @@ -14,6 +14,8 @@ | |||||||
| // to the function does not create any copies of the pointer value that | // to the function does not create any copies of the pointer value that | ||||||
| // outlive the call.  This more or less means that the pointer is only | // outlive the call.  This more or less means that the pointer is only | ||||||
| // dereferenced, and not returned from the function or stored in a global. | // dereferenced, and not returned from the function or stored in a global. | ||||||
|  | // Finally, well-known library call declarations are marked with all | ||||||
|  | // attributes that are consistent with the function's standard definition. | ||||||
| // This pass is implemented as a bottom-up traversal of the call-graph. | // This pass is implemented as a bottom-up traversal of the call-graph. | ||||||
| // | // | ||||||
| //===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||||
| @@ -32,12 +34,14 @@ | |||||||
| #include "llvm/IR/IntrinsicInst.h" | #include "llvm/IR/IntrinsicInst.h" | ||||||
| #include "llvm/IR/LLVMContext.h" | #include "llvm/IR/LLVMContext.h" | ||||||
| #include "llvm/Support/InstIterator.h" | #include "llvm/Support/InstIterator.h" | ||||||
|  | #include "llvm/Target/TargetLibraryInfo.h" | ||||||
| using namespace llvm; | using namespace llvm; | ||||||
|  |  | ||||||
| STATISTIC(NumReadNone, "Number of functions marked readnone"); | STATISTIC(NumReadNone, "Number of functions marked readnone"); | ||||||
| STATISTIC(NumReadOnly, "Number of functions marked readonly"); | STATISTIC(NumReadOnly, "Number of functions marked readonly"); | ||||||
| STATISTIC(NumNoCapture, "Number of arguments marked nocapture"); | STATISTIC(NumNoCapture, "Number of arguments marked nocapture"); | ||||||
| STATISTIC(NumNoAlias, "Number of function returns marked noalias"); | STATISTIC(NumNoAlias, "Number of function returns marked noalias"); | ||||||
|  | STATISTIC(NumAnnotated, "Number of attributes added to library functions"); | ||||||
|  |  | ||||||
| namespace { | namespace { | ||||||
|   struct FunctionAttrs : public CallGraphSCCPass { |   struct FunctionAttrs : public CallGraphSCCPass { | ||||||
| @@ -62,14 +66,63 @@ namespace { | |||||||
|     // AddNoAliasAttrs - Deduce noalias attributes for the SCC. |     // AddNoAliasAttrs - Deduce noalias attributes for the SCC. | ||||||
|     bool AddNoAliasAttrs(const CallGraphSCC &SCC); |     bool AddNoAliasAttrs(const CallGraphSCC &SCC); | ||||||
|  |  | ||||||
|  |     // Utility methods used by inferPrototypeAttributes to add attributes | ||||||
|  |     // and maintain annotation statistics. | ||||||
|  |  | ||||||
|  |     void setDoesNotAccessMemory(Function &F) { | ||||||
|  |       if (!F.doesNotAccessMemory()) { | ||||||
|  | 	F.setDoesNotAccessMemory(); | ||||||
|  | 	++NumAnnotated; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setOnlyReadsMemory(Function &F) { | ||||||
|  |       if (!F.onlyReadsMemory()) { | ||||||
|  | 	F.setOnlyReadsMemory(); | ||||||
|  | 	++NumAnnotated; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setDoesNotThrow(Function &F) { | ||||||
|  |       if (!F.doesNotThrow()) { | ||||||
|  | 	F.setDoesNotThrow(); | ||||||
|  | 	++NumAnnotated; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setDoesNotCapture(Function &F, unsigned n) { | ||||||
|  |       if (!F.doesNotCapture(n)) { | ||||||
|  | 	F.setDoesNotCapture(n); | ||||||
|  | 	++NumAnnotated; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setDoesNotAlias(Function &F, unsigned n) { | ||||||
|  |       if (!F.doesNotAlias(n)) { | ||||||
|  | 	F.setDoesNotAlias(n); | ||||||
|  | 	++NumAnnotated; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // inferPrototypeAttributes - Analyze the name and prototype of the | ||||||
|  |     // given function and set any applicable attributes.  Returns true | ||||||
|  |     // if any attributes were set and false otherwise. | ||||||
|  |     bool inferPrototypeAttributes(Function &F); | ||||||
|  |  | ||||||
|  |     // annotateLibraryCalls - Adds attributes to well-known standard library | ||||||
|  |     // call declarations. | ||||||
|  |     bool annotateLibraryCalls(const CallGraphSCC &SCC); | ||||||
|  |  | ||||||
|     virtual void getAnalysisUsage(AnalysisUsage &AU) const { |     virtual void getAnalysisUsage(AnalysisUsage &AU) const { | ||||||
|       AU.setPreservesCFG(); |       AU.setPreservesCFG(); | ||||||
|       AU.addRequired<AliasAnalysis>(); |       AU.addRequired<AliasAnalysis>(); | ||||||
|  |       AU.addRequired<TargetLibraryInfo>(); | ||||||
|       CallGraphSCCPass::getAnalysisUsage(AU); |       CallGraphSCCPass::getAnalysisUsage(AU); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   private: |   private: | ||||||
|     AliasAnalysis *AA; |     AliasAnalysis *AA; | ||||||
|  |     TargetLibraryInfo *TLI; | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -77,6 +130,7 @@ char FunctionAttrs::ID = 0; | |||||||
| INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs", | INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs", | ||||||
|                 "Deduce function attributes", false, false) |                 "Deduce function attributes", false, false) | ||||||
| INITIALIZE_AG_DEPENDENCY(CallGraph) | INITIALIZE_AG_DEPENDENCY(CallGraph) | ||||||
|  | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo) | ||||||
| INITIALIZE_PASS_END(FunctionAttrs, "functionattrs", | INITIALIZE_PASS_END(FunctionAttrs, "functionattrs", | ||||||
|                 "Deduce function attributes", false, false) |                 "Deduce function attributes", false, false) | ||||||
|  |  | ||||||
| @@ -598,10 +652,693 @@ bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) { | |||||||
|   return MadeChange; |   return MadeChange; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// inferPrototypeAttributes - Analyze the name and prototype of the | ||||||
|  | /// given function and set any applicable attributes.  Returns true | ||||||
|  | /// if any attributes were set and false otherwise. | ||||||
|  | bool FunctionAttrs::inferPrototypeAttributes(Function &F) { | ||||||
|  |   FunctionType *FTy = F.getFunctionType(); | ||||||
|  |   LibFunc::Func TheLibFunc; | ||||||
|  |   if (!(TLI->getLibFunc(F.getName(), TheLibFunc) && TLI->has(TheLibFunc))) | ||||||
|  |     return false; | ||||||
|  |  | ||||||
|  |   switch (TheLibFunc) { | ||||||
|  |   case LibFunc::strlen: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strchr: | ||||||
|  |   case LibFunc::strrchr: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isIntegerTy()) | ||||||
|  |       return false; | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strcpy: | ||||||
|  |   case LibFunc::stpcpy: | ||||||
|  |   case LibFunc::strcat: | ||||||
|  |   case LibFunc::strtol: | ||||||
|  |   case LibFunc::strtod: | ||||||
|  |   case LibFunc::strtof: | ||||||
|  |   case LibFunc::strtoul: | ||||||
|  |   case LibFunc::strtoll: | ||||||
|  |   case LibFunc::strtold: | ||||||
|  |   case LibFunc::strncat: | ||||||
|  |   case LibFunc::strncpy: | ||||||
|  |   case LibFunc::stpncpy: | ||||||
|  |   case LibFunc::strtoull: | ||||||
|  |     if (FTy->getNumParams() < 2 || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strxfrm: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strcmp: | ||||||
|  |   case LibFunc::strspn: | ||||||
|  |   case LibFunc::strncmp: | ||||||
|  |   case LibFunc::strcspn: | ||||||
|  |   case LibFunc::strcoll: | ||||||
|  |   case LibFunc::strcasecmp: | ||||||
|  |   case LibFunc::strncasecmp: | ||||||
|  |     if (FTy->getNumParams() < 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strstr: | ||||||
|  |   case LibFunc::strpbrk: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strtok: | ||||||
|  |   case LibFunc::strtok_r: | ||||||
|  |     if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::scanf: | ||||||
|  |   case LibFunc::setbuf: | ||||||
|  |   case LibFunc::setvbuf: | ||||||
|  |     if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::strdup: | ||||||
|  |   case LibFunc::strndup: | ||||||
|  |     if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::stat: | ||||||
|  |   case LibFunc::sscanf: | ||||||
|  |   case LibFunc::sprintf: | ||||||
|  |   case LibFunc::statvfs: | ||||||
|  |     if (FTy->getNumParams() < 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::snprintf: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(2)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 3); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::setitimer: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(2)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     setDoesNotCapture(F, 3); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::system: | ||||||
|  |     if (FTy->getNumParams() != 1 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; "system" is a valid pthread cancellation point. | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::malloc: | ||||||
|  |     if (FTy->getNumParams() != 1 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::memcmp: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::memchr: | ||||||
|  |   case LibFunc::memrchr: | ||||||
|  |     if (FTy->getNumParams() != 3) | ||||||
|  |       return false; | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::modf: | ||||||
|  |   case LibFunc::modff: | ||||||
|  |   case LibFunc::modfl: | ||||||
|  |   case LibFunc::memcpy: | ||||||
|  |   case LibFunc::memccpy: | ||||||
|  |   case LibFunc::memmove: | ||||||
|  |     if (FTy->getNumParams() < 2 || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::memalign: | ||||||
|  |     if (!FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::mkdir: | ||||||
|  |   case LibFunc::mktime: | ||||||
|  |     if (FTy->getNumParams() == 0 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::realloc: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::read: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; "read" is a valid pthread cancellation point. | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::rmdir: | ||||||
|  |   case LibFunc::rewind: | ||||||
|  |   case LibFunc::remove: | ||||||
|  |   case LibFunc::realpath: | ||||||
|  |     if (FTy->getNumParams() < 1 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::rename: | ||||||
|  |   case LibFunc::readlink: | ||||||
|  |     if (FTy->getNumParams() < 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::write: | ||||||
|  |     if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; "write" is a valid pthread cancellation point. | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::bcopy: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::bcmp: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::bzero: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::calloc: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::chmod: | ||||||
|  |   case LibFunc::chown: | ||||||
|  |   case LibFunc::ctermid: | ||||||
|  |   case LibFunc::clearerr: | ||||||
|  |   case LibFunc::closedir: | ||||||
|  |     if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::atoi: | ||||||
|  |   case LibFunc::atol: | ||||||
|  |   case LibFunc::atof: | ||||||
|  |   case LibFunc::atoll: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::access: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fopen: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fdopen: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::feof: | ||||||
|  |   case LibFunc::free: | ||||||
|  |   case LibFunc::fseek: | ||||||
|  |   case LibFunc::ftell: | ||||||
|  |   case LibFunc::fgetc: | ||||||
|  |   case LibFunc::fseeko: | ||||||
|  |   case LibFunc::ftello: | ||||||
|  |   case LibFunc::fileno: | ||||||
|  |   case LibFunc::fflush: | ||||||
|  |   case LibFunc::fclose: | ||||||
|  |   case LibFunc::fsetpos: | ||||||
|  |   case LibFunc::flockfile: | ||||||
|  |   case LibFunc::funlockfile: | ||||||
|  |   case LibFunc::ftrylockfile: | ||||||
|  |     if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::ferror: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fputc: | ||||||
|  |   case LibFunc::fstat: | ||||||
|  |   case LibFunc::frexp: | ||||||
|  |   case LibFunc::frexpf: | ||||||
|  |   case LibFunc::frexpl: | ||||||
|  |   case LibFunc::fstatvfs: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fgets: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(2)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 3); | ||||||
|  |   case LibFunc::fread: | ||||||
|  |   case LibFunc::fwrite: | ||||||
|  |     if (FTy->getNumParams() != 4 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(3)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 4); | ||||||
|  |   case LibFunc::fputs: | ||||||
|  |   case LibFunc::fscanf: | ||||||
|  |   case LibFunc::fprintf: | ||||||
|  |   case LibFunc::fgetpos: | ||||||
|  |     if (FTy->getNumParams() < 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::getc: | ||||||
|  |   case LibFunc::getlogin_r: | ||||||
|  |   case LibFunc::getc_unlocked: | ||||||
|  |     if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::getenv: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setOnlyReadsMemory(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::gets: | ||||||
|  |   case LibFunc::getchar: | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::getitimer: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::getpwnam: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::ungetc: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::uname: | ||||||
|  |   case LibFunc::unlink: | ||||||
|  |   case LibFunc::unsetenv: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::utime: | ||||||
|  |   case LibFunc::utimes: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::putc: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::puts: | ||||||
|  |   case LibFunc::printf: | ||||||
|  |   case LibFunc::perror: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::pread: | ||||||
|  |   case LibFunc::pwrite: | ||||||
|  |     if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; these are valid pthread cancellation points. | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::putchar: | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::popen: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::pclose: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::vscanf: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::vsscanf: | ||||||
|  |   case LibFunc::vfscanf: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(2)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::valloc: | ||||||
|  |     if (!FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::vprintf: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::vfprintf: | ||||||
|  |   case LibFunc::vsprintf: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::vsnprintf: | ||||||
|  |     if (FTy->getNumParams() != 4 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(2)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 3); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::open: | ||||||
|  |     if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; "open" is a valid pthread cancellation point. | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::opendir: | ||||||
|  |     if (FTy->getNumParams() != 1 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::tmpfile: | ||||||
|  |     if (!FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::times: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::htonl: | ||||||
|  |   case LibFunc::htons: | ||||||
|  |   case LibFunc::ntohl: | ||||||
|  |   case LibFunc::ntohs: | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAccessMemory(F); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::lstat: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::lchown: | ||||||
|  |     if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::qsort: | ||||||
|  |     if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; places call through function pointer. | ||||||
|  |     setDoesNotCapture(F, 4); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::dunder_strdup: | ||||||
|  |   case LibFunc::dunder_strndup: | ||||||
|  |     if (FTy->getNumParams() < 1 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::dunder_strtok_r: | ||||||
|  |     if (FTy->getNumParams() != 3 || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::under_IO_getc: | ||||||
|  |     if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::under_IO_putc: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::dunder_isoc99_scanf: | ||||||
|  |     if (FTy->getNumParams() < 1 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::stat64: | ||||||
|  |   case LibFunc::lstat64: | ||||||
|  |   case LibFunc::statvfs64: | ||||||
|  |   case LibFunc::dunder_isoc99_sscanf: | ||||||
|  |     if (FTy->getNumParams() < 1 || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fopen64: | ||||||
|  |     if (FTy->getNumParams() != 2 || | ||||||
|  |         !FTy->getReturnType()->isPointerTy() || | ||||||
|  |         !FTy->getParamType(0)->isPointerTy() || | ||||||
|  |         !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fseeko64: | ||||||
|  |   case LibFunc::ftello64: | ||||||
|  |     if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::tmpfile64: | ||||||
|  |     if (!FTy->getReturnType()->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotAlias(F, 0); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::fstat64: | ||||||
|  |   case LibFunc::fstatvfs64: | ||||||
|  |     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     setDoesNotThrow(F); | ||||||
|  |     setDoesNotCapture(F, 2); | ||||||
|  |     break; | ||||||
|  |   case LibFunc::open64: | ||||||
|  |     if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy()) | ||||||
|  |       return false; | ||||||
|  |     // May throw; "open" is a valid pthread cancellation point. | ||||||
|  |     setDoesNotCapture(F, 1); | ||||||
|  |     break; | ||||||
|  |   default: | ||||||
|  |     // Didn't mark any attributes. | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// annotateLibraryCalls - Adds attributes to well-known standard library | ||||||
|  | /// call declarations. | ||||||
|  | bool FunctionAttrs::annotateLibraryCalls(const CallGraphSCC &SCC) { | ||||||
|  |   bool MadeChange = false; | ||||||
|  |  | ||||||
|  |   // Check each function in turn annotating well-known library function | ||||||
|  |   // declarations with attributes. | ||||||
|  |   for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | ||||||
|  |     Function *F = (*I)->getFunction(); | ||||||
|  |  | ||||||
|  |     if (F != 0 && F->isDeclaration()) | ||||||
|  |       MadeChange |= inferPrototypeAttributes(*F); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return MadeChange; | ||||||
|  | } | ||||||
|  |  | ||||||
| bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) { | bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) { | ||||||
|   AA = &getAnalysis<AliasAnalysis>(); |   AA = &getAnalysis<AliasAnalysis>(); | ||||||
|  |   TLI = &getAnalysis<TargetLibraryInfo>(); | ||||||
|  |  | ||||||
|   bool Changed = AddReadAttrs(SCC); |   bool Changed = annotateLibraryCalls(SCC); | ||||||
|  |   Changed |= AddReadAttrs(SCC); | ||||||
|   Changed |= AddNoCaptureAttrs(SCC); |   Changed |= AddNoCaptureAttrs(SCC); | ||||||
|   Changed |= AddNoAliasAttrs(SCC); |   Changed |= AddNoAliasAttrs(SCC); | ||||||
|   return Changed; |   return Changed; | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ | |||||||
| #include "llvm/Transforms/Scalar.h" | #include "llvm/Transforms/Scalar.h" | ||||||
| #include "llvm/ADT/STLExtras.h" | #include "llvm/ADT/STLExtras.h" | ||||||
| #include "llvm/ADT/SmallPtrSet.h" | #include "llvm/ADT/SmallPtrSet.h" | ||||||
| #include "llvm/ADT/Statistic.h" |  | ||||||
| #include "llvm/ADT/StringMap.h" | #include "llvm/ADT/StringMap.h" | ||||||
| #include "llvm/Analysis/ValueTracking.h" | #include "llvm/Analysis/ValueTracking.h" | ||||||
| #include "llvm/Config/config.h"            // FIXME: Shouldn't depend on host! | #include "llvm/Config/config.h"            // FIXME: Shouldn't depend on host! | ||||||
| @@ -35,7 +34,6 @@ | |||||||
| #include "llvm/Transforms/Utils/BuildLibCalls.h" | #include "llvm/Transforms/Utils/BuildLibCalls.h" | ||||||
| using namespace llvm; | using namespace llvm; | ||||||
|  |  | ||||||
| STATISTIC(NumAnnotated, "Number of attributes added to library functions"); |  | ||||||
|  |  | ||||||
| //===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||||
| // Optimizer Base Class | // Optimizer Base Class | ||||||
| @@ -104,14 +102,6 @@ namespace { | |||||||
|     void InitOptimizations(); |     void InitOptimizations(); | ||||||
|     bool runOnFunction(Function &F); |     bool runOnFunction(Function &F); | ||||||
|  |  | ||||||
|     void setDoesNotAccessMemory(Function &F); |  | ||||||
|     void setOnlyReadsMemory(Function &F); |  | ||||||
|     void setDoesNotThrow(Function &F); |  | ||||||
|     void setDoesNotCapture(Function &F, unsigned n); |  | ||||||
|     void setDoesNotAlias(Function &F, unsigned n); |  | ||||||
|     bool doInitialization(Module &M); |  | ||||||
|  |  | ||||||
|     void inferPrototypeAttributes(Function &F); |  | ||||||
|     virtual void getAnalysisUsage(AnalysisUsage &AU) const { |     virtual void getAnalysisUsage(AnalysisUsage &AU) const { | ||||||
|       AU.addRequired<TargetLibraryInfo>(); |       AU.addRequired<TargetLibraryInfo>(); | ||||||
|     } |     } | ||||||
| @@ -208,697 +198,6 @@ bool SimplifyLibCalls::runOnFunction(Function &F) { | |||||||
|   return Changed; |   return Changed; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Utility methods for doInitialization. |  | ||||||
|  |  | ||||||
| void SimplifyLibCalls::setDoesNotAccessMemory(Function &F) { |  | ||||||
|   if (!F.doesNotAccessMemory()) { |  | ||||||
|     F.setDoesNotAccessMemory(); |  | ||||||
|     ++NumAnnotated; |  | ||||||
|     Modified = true; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| void SimplifyLibCalls::setOnlyReadsMemory(Function &F) { |  | ||||||
|   if (!F.onlyReadsMemory()) { |  | ||||||
|     F.setOnlyReadsMemory(); |  | ||||||
|     ++NumAnnotated; |  | ||||||
|     Modified = true; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| void SimplifyLibCalls::setDoesNotThrow(Function &F) { |  | ||||||
|   if (!F.doesNotThrow()) { |  | ||||||
|     F.setDoesNotThrow(); |  | ||||||
|     ++NumAnnotated; |  | ||||||
|     Modified = true; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| void SimplifyLibCalls::setDoesNotCapture(Function &F, unsigned n) { |  | ||||||
|   if (!F.doesNotCapture(n)) { |  | ||||||
|     F.setDoesNotCapture(n); |  | ||||||
|     ++NumAnnotated; |  | ||||||
|     Modified = true; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| void SimplifyLibCalls::setDoesNotAlias(Function &F, unsigned n) { |  | ||||||
|   if (!F.doesNotAlias(n)) { |  | ||||||
|     F.setDoesNotAlias(n); |  | ||||||
|     ++NumAnnotated; |  | ||||||
|     Modified = true; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void SimplifyLibCalls::inferPrototypeAttributes(Function &F) { |  | ||||||
|   FunctionType *FTy = F.getFunctionType(); |  | ||||||
|  |  | ||||||
|   StringRef Name = F.getName(); |  | ||||||
|   switch (Name[0]) { |  | ||||||
|   case 's': |  | ||||||
|     if (Name == "strlen") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "strchr" || |  | ||||||
|                Name == "strrchr") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isIntegerTy()) |  | ||||||
|         return; |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|     } else if (Name == "strcpy" || |  | ||||||
|                Name == "stpcpy" || |  | ||||||
|                Name == "strcat" || |  | ||||||
|                Name == "strtol" || |  | ||||||
|                Name == "strtod" || |  | ||||||
|                Name == "strtof" || |  | ||||||
|                Name == "strtoul" || |  | ||||||
|                Name == "strtoll" || |  | ||||||
|                Name == "strtold" || |  | ||||||
|                Name == "strncat" || |  | ||||||
|                Name == "strncpy" || |  | ||||||
|                Name == "stpncpy" || |  | ||||||
|                Name == "strtoull") { |  | ||||||
|       if (FTy->getNumParams() < 2 || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "strxfrm") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "strcmp" || |  | ||||||
|                Name == "strspn" || |  | ||||||
|                Name == "strncmp" || |  | ||||||
|                Name == "strcspn" || |  | ||||||
|                Name == "strcoll" || |  | ||||||
|                Name == "strcasecmp" || |  | ||||||
|                Name == "strncasecmp") { |  | ||||||
|       if (FTy->getNumParams() < 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "strstr" || |  | ||||||
|                Name == "strpbrk") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "strtok" || |  | ||||||
|                Name == "strtok_r") { |  | ||||||
|       if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "scanf" || |  | ||||||
|                Name == "setbuf" || |  | ||||||
|                Name == "setvbuf") { |  | ||||||
|       if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "strdup" || |  | ||||||
|                Name == "strndup") { |  | ||||||
|       if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "stat" || |  | ||||||
|                Name == "sscanf" || |  | ||||||
|                Name == "sprintf" || |  | ||||||
|                Name == "statvfs") { |  | ||||||
|       if (FTy->getNumParams() < 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "snprintf") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(2)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 3); |  | ||||||
|     } else if (Name == "setitimer") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(2)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|       setDoesNotCapture(F, 3); |  | ||||||
|     } else if (Name == "system") { |  | ||||||
|       if (FTy->getNumParams() != 1 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; "system" is a valid pthread cancellation point. |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'm': |  | ||||||
|     if (Name == "malloc") { |  | ||||||
|       if (FTy->getNumParams() != 1 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|     } else if (Name == "memcmp") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "memchr" || |  | ||||||
|                Name == "memrchr") { |  | ||||||
|       if (FTy->getNumParams() != 3) |  | ||||||
|         return; |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|     } else if (Name == "modf" || |  | ||||||
|                Name == "modff" || |  | ||||||
|                Name == "modfl" || |  | ||||||
|                Name == "memcpy" || |  | ||||||
|                Name == "memccpy" || |  | ||||||
|                Name == "memmove") { |  | ||||||
|       if (FTy->getNumParams() < 2 || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "memalign") { |  | ||||||
|       if (!FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|     } else if (Name == "mkdir" || |  | ||||||
|                Name == "mktime") { |  | ||||||
|       if (FTy->getNumParams() == 0 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'r': |  | ||||||
|     if (Name == "realloc") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "read") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; "read" is a valid pthread cancellation point. |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "rmdir" || |  | ||||||
|                Name == "rewind" || |  | ||||||
|                Name == "remove" || |  | ||||||
|                Name == "realpath") { |  | ||||||
|       if (FTy->getNumParams() < 1 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "rename" || |  | ||||||
|                Name == "readlink") { |  | ||||||
|       if (FTy->getNumParams() < 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'w': |  | ||||||
|     if (Name == "write") { |  | ||||||
|       if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; "write" is a valid pthread cancellation point. |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'b': |  | ||||||
|     if (Name == "bcopy") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "bcmp") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "bzero") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'c': |  | ||||||
|     if (Name == "calloc") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|     } else if (Name == "chmod" || |  | ||||||
|                Name == "chown" || |  | ||||||
|                Name == "ctermid" || |  | ||||||
|                Name == "clearerr" || |  | ||||||
|                Name == "closedir") { |  | ||||||
|       if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'a': |  | ||||||
|     if (Name == "atoi" || |  | ||||||
|         Name == "atol" || |  | ||||||
|         Name == "atof" || |  | ||||||
|         Name == "atoll") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "access") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'f': |  | ||||||
|     if (Name == "fopen") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "fdopen") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "feof" || |  | ||||||
|                Name == "free" || |  | ||||||
|                Name == "fseek" || |  | ||||||
|                Name == "ftell" || |  | ||||||
|                Name == "fgetc" || |  | ||||||
|                Name == "fseeko" || |  | ||||||
|                Name == "ftello" || |  | ||||||
|                Name == "fileno" || |  | ||||||
|                Name == "fflush" || |  | ||||||
|                Name == "fclose" || |  | ||||||
|                Name == "fsetpos" || |  | ||||||
|                Name == "flockfile" || |  | ||||||
|                Name == "funlockfile" || |  | ||||||
|                Name == "ftrylockfile") { |  | ||||||
|       if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "ferror") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|     } else if (Name == "fputc" || |  | ||||||
|                Name == "fstat" || |  | ||||||
|                Name == "frexp" || |  | ||||||
|                Name == "frexpf" || |  | ||||||
|                Name == "frexpl" || |  | ||||||
|                Name == "fstatvfs") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "fgets") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(2)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 3); |  | ||||||
|     } else if (Name == "fread" || |  | ||||||
|                Name == "fwrite") { |  | ||||||
|       if (FTy->getNumParams() != 4 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(3)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 4); |  | ||||||
|     } else if (Name == "fputs" || |  | ||||||
|                Name == "fscanf" || |  | ||||||
|                Name == "fprintf" || |  | ||||||
|                Name == "fgetpos") { |  | ||||||
|       if (FTy->getNumParams() < 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'g': |  | ||||||
|     if (Name == "getc" || |  | ||||||
|         Name == "getlogin_r" || |  | ||||||
|         Name == "getc_unlocked") { |  | ||||||
|       if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "getenv") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setOnlyReadsMemory(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "gets" || |  | ||||||
|                Name == "getchar") { |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|     } else if (Name == "getitimer") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "getpwnam") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'u': |  | ||||||
|     if (Name == "ungetc") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "uname" || |  | ||||||
|                Name == "unlink" || |  | ||||||
|                Name == "unsetenv") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "utime" || |  | ||||||
|                Name == "utimes") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'p': |  | ||||||
|     if (Name == "putc") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "puts" || |  | ||||||
|                Name == "printf" || |  | ||||||
|                Name == "perror") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "pread" || |  | ||||||
|                Name == "pwrite") { |  | ||||||
|       if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; these are valid pthread cancellation points. |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "putchar") { |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|     } else if (Name == "popen") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "pclose") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'v': |  | ||||||
|     if (Name == "vscanf") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "vsscanf" || |  | ||||||
|                Name == "vfscanf") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(2)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "valloc") { |  | ||||||
|       if (!FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|     } else if (Name == "vprintf") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "vfprintf" || |  | ||||||
|                Name == "vsprintf") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "vsnprintf") { |  | ||||||
|       if (FTy->getNumParams() != 4 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(2)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 3); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'o': |  | ||||||
|     if (Name == "open") { |  | ||||||
|       if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; "open" is a valid pthread cancellation point. |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "opendir") { |  | ||||||
|       if (FTy->getNumParams() != 1 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 't': |  | ||||||
|     if (Name == "tmpfile") { |  | ||||||
|       if (!FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|     } else if (Name == "times") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'h': |  | ||||||
|     if (Name == "htonl" || |  | ||||||
|         Name == "htons") { |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAccessMemory(F); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'n': |  | ||||||
|     if (Name == "ntohl" || |  | ||||||
|         Name == "ntohs") { |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAccessMemory(F); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'l': |  | ||||||
|     if (Name == "lstat") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "lchown") { |  | ||||||
|       if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 'q': |  | ||||||
|     if (Name == "qsort") { |  | ||||||
|       if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; places call through function pointer. |  | ||||||
|       setDoesNotCapture(F, 4); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case '_': |  | ||||||
|     if (Name == "__strdup" || |  | ||||||
|         Name == "__strndup") { |  | ||||||
|       if (FTy->getNumParams() < 1 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "__strtok_r") { |  | ||||||
|       if (FTy->getNumParams() != 3 || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "_IO_getc") { |  | ||||||
|       if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "_IO_putc") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   case 1: |  | ||||||
|     if (Name == "\1__isoc99_scanf") { |  | ||||||
|       if (FTy->getNumParams() < 1 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "\1stat64" || |  | ||||||
|                Name == "\1lstat64" || |  | ||||||
|                Name == "\1statvfs64" || |  | ||||||
|                Name == "\1__isoc99_sscanf") { |  | ||||||
|       if (FTy->getNumParams() < 1 || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "\1fopen64") { |  | ||||||
|       if (FTy->getNumParams() != 2 || |  | ||||||
|           !FTy->getReturnType()->isPointerTy() || |  | ||||||
|           !FTy->getParamType(0)->isPointerTy() || |  | ||||||
|           !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "\1fseeko64" || |  | ||||||
|                Name == "\1ftello64") { |  | ||||||
|       if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } else if (Name == "\1tmpfile64") { |  | ||||||
|       if (!FTy->getReturnType()->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotAlias(F, 0); |  | ||||||
|     } else if (Name == "\1fstat64" || |  | ||||||
|                Name == "\1fstatvfs64") { |  | ||||||
|       if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       setDoesNotThrow(F); |  | ||||||
|       setDoesNotCapture(F, 2); |  | ||||||
|     } else if (Name == "\1open64") { |  | ||||||
|       if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy()) |  | ||||||
|         return; |  | ||||||
|       // May throw; "open" is a valid pthread cancellation point. |  | ||||||
|       setDoesNotCapture(F, 1); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// doInitialization - Add attributes to well-known functions. |  | ||||||
| /// |  | ||||||
| bool SimplifyLibCalls::doInitialization(Module &M) { |  | ||||||
|   Modified = false; |  | ||||||
|   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { |  | ||||||
|     Function &F = *I; |  | ||||||
|     if (F.isDeclaration() && F.hasName()) |  | ||||||
|       inferPrototypeAttributes(F); |  | ||||||
|   } |  | ||||||
|   return Modified; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // TODO: | // TODO: | ||||||
| //   Additional cases that we need to add to this file: | //   Additional cases that we need to add to this file: | ||||||
| // | // | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| ; RUN: opt < %s -simplify-libcalls -S | FileCheck %s | ; RUN: opt < %s -functionattrs -S | FileCheck %s | ||||||
| 
 | 
 | ||||||
| ; CHECK: declare noalias i8* @fopen(i8* nocapture, i8* nocapture) #0 | ; CHECK: declare noalias i8* @fopen(i8* nocapture, i8* nocapture) #0 | ||||||
| declare i8* @fopen(i8*, i8*) | declare i8* @fopen(i8*, i8*) | ||||||
							
								
								
									
										18
									
								
								test/Transforms/FunctionAttrs/annotate-1.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								test/Transforms/FunctionAttrs/annotate-1.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | ; RUN: opt < %s -functionattrs -S | FileCheck %s | ||||||
|  |  | ||||||
|  | declare i8* @fopen(i8*, i8*) | ||||||
|  | ; CHECK: declare noalias i8* @fopen(i8* nocapture, i8* nocapture) [[G0:#[0-9]]]  | ||||||
|  |  | ||||||
|  | declare i8 @strlen(i8*) | ||||||
|  | ; CHECK: declare i8 @strlen(i8* nocapture) [[G1:#[0-9]]] | ||||||
|  |  | ||||||
|  | declare i32* @realloc(i32*, i32) | ||||||
|  | ; CHECK: declare noalias i32* @realloc(i32* nocapture, i32) [[G0]] | ||||||
|  |  | ||||||
|  | ; Test deliberately wrong declaration | ||||||
|  |  | ||||||
|  | declare i32 @strcpy(...) | ||||||
|  | ; CHECK: declare i32 @strcpy(...) | ||||||
|  |  | ||||||
|  | ; CHECK: attributes [[G0]] = { nounwind } | ||||||
|  | ; CHECK: attributes [[G1]] = { nounwind readonly } | ||||||
							
								
								
									
										14
									
								
								test/Transforms/InstCombine/2009-02-11-NotInitialized.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								test/Transforms/InstCombine/2009-02-11-NotInitialized.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | ; RUN: opt < %s -inline -instcombine -functionattrs | llvm-dis | ||||||
|  | ; | ||||||
|  | ; Check that nocapture attributes are added when run after an SCC pass. | ||||||
|  | ; PR3520 | ||||||
|  |  | ||||||
|  | define i32 @use(i8* %x) nounwind readonly { | ||||||
|  | ; CHECK: @use(i8* nocapture %x) | ||||||
|  |   %1 = tail call i64 @strlen(i8* %x) nounwind readonly | ||||||
|  |   %2 = trunc i64 %1 to i32 | ||||||
|  |   ret i32 %2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | declare i64 @strlen(i8*) nounwind readonly | ||||||
|  | ; CHECK: declare i64 @strlen(i8* nocapture) nounwind readonly | ||||||
| @@ -1,29 +1,29 @@ | |||||||
| ; Test that the strto* library call simplifiers works correctly. | ; Test that the strto* library call simplifiers works correctly. | ||||||
| ; | ; | ||||||
| ; RUN: opt < %s -instcombine -S | FileCheck %s | ; RUN: opt < %s -instcombine -functionattrs -S | FileCheck %s | ||||||
|  |  | ||||||
| target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" | target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" | ||||||
|  |  | ||||||
| declare i64 @strtol(i8* %s, i8** %endptr, i32 %base) | declare i64 @strtol(i8* %s, i8** %endptr, i32 %base) | ||||||
| ; CHECK: declare i64 @strtol(i8*, i8**, i32) | ; CHECK: declare i64 @strtol(i8*, i8** nocapture, i32) | ||||||
|  |  | ||||||
| declare double @strtod(i8* %s, i8** %endptr, i32 %base) | declare double @strtod(i8* %s, i8** %endptr, i32 %base) | ||||||
| ; CHECK: declare double @strtod(i8*, i8**, i32) | ; CHECK: declare double @strtod(i8*, i8** nocapture, i32) | ||||||
|  |  | ||||||
| declare float @strtof(i8* %s, i8** %endptr, i32 %base) | declare float @strtof(i8* %s, i8** %endptr, i32 %base) | ||||||
| ; CHECK: declare float @strtof(i8*, i8**, i32) | ; CHECK: declare float @strtof(i8*, i8** nocapture, i32) | ||||||
|  |  | ||||||
| declare i64 @strtoul(i8* %s, i8** %endptr, i32 %base) | declare i64 @strtoul(i8* %s, i8** %endptr, i32 %base) | ||||||
| ; CHECK: declare i64 @strtoul(i8*, i8**, i32) | ; CHECK: declare i64 @strtoul(i8*, i8** nocapture, i32) | ||||||
|  |  | ||||||
| declare i64 @strtoll(i8* %s, i8** %endptr, i32 %base) | declare i64 @strtoll(i8* %s, i8** %endptr, i32 %base) | ||||||
| ; CHECK: declare i64 @strtoll(i8*, i8**, i32) | ; CHECK: declare i64 @strtoll(i8*, i8** nocapture, i32) | ||||||
|  |  | ||||||
| declare double @strtold(i8* %s, i8** %endptr) | declare double @strtold(i8* %s, i8** %endptr) | ||||||
| ; CHECK: declare double @strtold(i8*, i8**) | ; CHECK: declare double @strtold(i8*, i8** nocapture) | ||||||
|  |  | ||||||
| declare i64 @strtoull(i8* %s, i8** %endptr, i32 %base) | declare i64 @strtoull(i8* %s, i8** %endptr, i32 %base) | ||||||
| ; CHECK: declare i64 @strtoull(i8*, i8**, i32) | ; CHECK: declare i64 @strtoull(i8*, i8** nocapture, i32) | ||||||
|  |  | ||||||
| define void @test_simplify1(i8* %x, i8** %endptr) { | define void @test_simplify1(i8* %x, i8** %endptr) { | ||||||
| ; CHECK: @test_simplify1 | ; CHECK: @test_simplify1 | ||||||
|   | |||||||
| @@ -1,13 +0,0 @@ | |||||||
| ; RUN: opt < %s -inline -simplify-libcalls -functionattrs | \ |  | ||||||
| ; RUN:   llvm-dis | grep nocapture | count 2 |  | ||||||
| ; Check that nocapture attributes are added when run after an SCC pass. |  | ||||||
| ; PR3520 |  | ||||||
|  |  | ||||||
| define i32 @use(i8* %x) nounwind readonly { |  | ||||||
| entry: |  | ||||||
| 	%0 = tail call i64 @strlen(i8* %x) nounwind readonly		; <i64> [#uses=1] |  | ||||||
| 	%1 = trunc i64 %0 to i32		; <i32> [#uses=1] |  | ||||||
| 	ret i32 %1 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| declare i64 @strlen(i8*) nounwind readonly |  | ||||||
		Reference in New Issue
	
	Block a user