mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-28 06:00:28 +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:
parent
efe84421ca
commit
cf47ce616c
@ -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
|
Loading…
Reference in New Issue
Block a user