mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +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 | ||||
| // | ||||
| @@ -14,6 +14,8 @@ | ||||
| // 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 | ||||
| // 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. | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
| @@ -32,12 +34,14 @@ | ||||
| #include "llvm/IR/IntrinsicInst.h" | ||||
| #include "llvm/IR/LLVMContext.h" | ||||
| #include "llvm/Support/InstIterator.h" | ||||
| #include "llvm/Target/TargetLibraryInfo.h" | ||||
| using namespace llvm; | ||||
|  | ||||
| STATISTIC(NumReadNone, "Number of functions marked readnone"); | ||||
| STATISTIC(NumReadOnly, "Number of functions marked readonly"); | ||||
| STATISTIC(NumNoCapture, "Number of arguments marked nocapture"); | ||||
| STATISTIC(NumNoAlias, "Number of function returns marked noalias"); | ||||
| STATISTIC(NumAnnotated, "Number of attributes added to library functions"); | ||||
|  | ||||
| namespace { | ||||
|   struct FunctionAttrs : public CallGraphSCCPass { | ||||
| @@ -62,14 +66,63 @@ namespace { | ||||
|     // AddNoAliasAttrs - Deduce noalias attributes for the 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 { | ||||
|       AU.setPreservesCFG(); | ||||
|       AU.addRequired<AliasAnalysis>(); | ||||
|       AU.addRequired<TargetLibraryInfo>(); | ||||
|       CallGraphSCCPass::getAnalysisUsage(AU); | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|     AliasAnalysis *AA; | ||||
|     TargetLibraryInfo *TLI; | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @@ -77,6 +130,7 @@ char FunctionAttrs::ID = 0; | ||||
| INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs", | ||||
|                 "Deduce function attributes", false, false) | ||||
| INITIALIZE_AG_DEPENDENCY(CallGraph) | ||||
| INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo) | ||||
| INITIALIZE_PASS_END(FunctionAttrs, "functionattrs", | ||||
|                 "Deduce function attributes", false, false) | ||||
|  | ||||
| @@ -598,10 +652,693 @@ bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) { | ||||
|   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) { | ||||
|   AA = &getAnalysis<AliasAnalysis>(); | ||||
|   TLI = &getAnalysis<TargetLibraryInfo>(); | ||||
|  | ||||
|   bool Changed = AddReadAttrs(SCC); | ||||
|   bool Changed = annotateLibraryCalls(SCC); | ||||
|   Changed |= AddReadAttrs(SCC); | ||||
|   Changed |= AddNoCaptureAttrs(SCC); | ||||
|   Changed |= AddNoAliasAttrs(SCC); | ||||
|   return Changed; | ||||
|   | ||||
| @@ -19,7 +19,6 @@ | ||||
| #include "llvm/Transforms/Scalar.h" | ||||
| #include "llvm/ADT/STLExtras.h" | ||||
| #include "llvm/ADT/SmallPtrSet.h" | ||||
| #include "llvm/ADT/Statistic.h" | ||||
| #include "llvm/ADT/StringMap.h" | ||||
| #include "llvm/Analysis/ValueTracking.h" | ||||
| #include "llvm/Config/config.h"            // FIXME: Shouldn't depend on host! | ||||
| @@ -35,7 +34,6 @@ | ||||
| #include "llvm/Transforms/Utils/BuildLibCalls.h" | ||||
| using namespace llvm; | ||||
|  | ||||
| STATISTIC(NumAnnotated, "Number of attributes added to library functions"); | ||||
|  | ||||
| //===----------------------------------------------------------------------===// | ||||
| // Optimizer Base Class | ||||
| @@ -104,14 +102,6 @@ namespace { | ||||
|     void InitOptimizations(); | ||||
|     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 { | ||||
|       AU.addRequired<TargetLibraryInfo>(); | ||||
|     } | ||||
| @@ -208,697 +198,6 @@ bool SimplifyLibCalls::runOnFunction(Function &F) { | ||||
|   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: | ||||
| //   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 | ||||
| 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. | ||||
| ; | ||||
| ; 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" | ||||
|  | ||||
| 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) | ||||
| ; CHECK: declare double @strtod(i8*, i8**, i32) | ||||
| ; CHECK: declare double @strtod(i8*, i8** nocapture, i32) | ||||
|  | ||||
| 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) | ||||
| ; CHECK: declare i64 @strtoul(i8*, i8**, i32) | ||||
| ; CHECK: declare i64 @strtoul(i8*, i8** nocapture, i32) | ||||
|  | ||||
| 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) | ||||
| ; CHECK: declare double @strtold(i8*, i8**) | ||||
| ; CHECK: declare double @strtold(i8*, i8** nocapture) | ||||
|  | ||||
| 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) { | ||||
| ; 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