diff options
Diffstat (limited to 'contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp')
-rw-r--r-- | contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 437 |
1 files changed, 389 insertions, 48 deletions
diff --git a/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index bc5109b..60e5f06 100644 --- a/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/contrib/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -9,14 +9,12 @@ // // This file implements a simple interprocedural pass which walks the // call-graph, looking for functions which do not access or only read -// non-local memory, and marking them readnone/readonly. In addition, -// it marks function arguments (of pointer type) 'nocapture' if a call -// 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. +// non-local memory, and marking them readnone/readonly. It does the +// same with function arguments independently, marking them readonly/ +// readnone/nocapture. 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. // //===----------------------------------------------------------------------===// @@ -40,6 +38,8 @@ 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(NumReadNoneArg, "Number of arguments marked readnone"); +STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly"); STATISTIC(NumNoAlias, "Number of function returns marked noalias"); STATISTIC(NumAnnotated, "Number of attributes added to library functions"); @@ -56,8 +56,8 @@ namespace { // AddReadAttrs - Deduce readonly/readnone attributes for the SCC. bool AddReadAttrs(const CallGraphSCC &SCC); - // AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. - bool AddNoCaptureAttrs(const CallGraphSCC &SCC); + // AddArgumentAttrs - Deduce nocapture attributes for the SCC. + bool AddArgumentAttrs(const CallGraphSCC &SCC); // IsFunctionMallocLike - Does this function allocate new memory? bool IsFunctionMallocLike(Function *F, @@ -71,36 +71,43 @@ namespace { void setDoesNotAccessMemory(Function &F) { if (!F.doesNotAccessMemory()) { - F.setDoesNotAccessMemory(); - ++NumAnnotated; + F.setDoesNotAccessMemory(); + ++NumAnnotated; } } void setOnlyReadsMemory(Function &F) { if (!F.onlyReadsMemory()) { - F.setOnlyReadsMemory(); - ++NumAnnotated; + F.setOnlyReadsMemory(); + ++NumAnnotated; } } void setDoesNotThrow(Function &F) { if (!F.doesNotThrow()) { - F.setDoesNotThrow(); - ++NumAnnotated; + F.setDoesNotThrow(); + ++NumAnnotated; } } void setDoesNotCapture(Function &F, unsigned n) { if (!F.doesNotCapture(n)) { - F.setDoesNotCapture(n); - ++NumAnnotated; + F.setDoesNotCapture(n); + ++NumAnnotated; + } + } + + void setOnlyReadsMemory(Function &F, unsigned n) { + if (!F.onlyReadsMemory(n)) { + F.setOnlyReadsMemory(n); + ++NumAnnotated; } } void setDoesNotAlias(Function &F, unsigned n) { if (!F.doesNotAlias(n)) { - F.setDoesNotAlias(n); - ++NumAnnotated; + F.setDoesNotAlias(n); + ++NumAnnotated; } } @@ -129,7 +136,8 @@ namespace { char FunctionAttrs::ID = 0; INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs", "Deduce function attributes", false, false) -INITIALIZE_AG_DEPENDENCY(CallGraph) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_DEPENDENCY(CallGraph) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo) INITIALIZE_PASS_END(FunctionAttrs, "functionattrs", "Deduce function attributes", false, false) @@ -343,6 +351,7 @@ namespace { Function *F = CS.getCalledFunction(); if (!F || !SCCNodes.count(F)) { Captured = true; return true; } + bool Found = false; Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); for (CallSite::arg_iterator PI = CS.arg_begin(), PE = CS.arg_end(); PI != PE; ++PI, ++AI) { @@ -353,10 +362,12 @@ namespace { } if (PI == U) { Uses.push_back(AI); + Found = true; break; } } - assert(!Uses.empty() && "Capturing call-site captured nothing?"); + assert(Found && "Capturing call-site captured nothing?"); + (void)Found; return false; } @@ -394,8 +405,100 @@ namespace llvm { }; } -/// AddNoCaptureAttrs - Deduce nocapture attributes for the SCC. -bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) { +// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone. +static Attribute::AttrKind +determinePointerReadAttrs(Argument *A, + const SmallPtrSet<Argument*, 8> &SCCNodes) { + + SmallVector<Use*, 32> Worklist; + SmallSet<Use*, 32> Visited; + int Count = 0; + + bool IsRead = false; + // We don't need to track IsWritten. If A is written to, return immediately. + + for (Value::use_iterator UI = A->use_begin(), UE = A->use_end(); + UI != UE; ++UI) { + if (Count++ >= 20) + return Attribute::None; + + Use *U = &UI.getUse(); + Visited.insert(U); + Worklist.push_back(U); + } + + while (!Worklist.empty()) { + Use *U = Worklist.pop_back_val(); + Instruction *I = cast<Instruction>(U->getUser()); + Value *V = U->get(); + + switch (I->getOpcode()) { + case Instruction::BitCast: + case Instruction::GetElementPtr: + case Instruction::PHI: + case Instruction::Select: + // The original value is not read/written via this if the new value isn't. + for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end(); + UI != UE; ++UI) { + Use *U = &UI.getUse(); + if (Visited.insert(U)) + Worklist.push_back(U); + } + break; + + case Instruction::Call: + case Instruction::Invoke: { + CallSite CS(I); + if (CS.doesNotAccessMemory()) + continue; + + Function *F = CS.getCalledFunction(); + if (!F) { + if (CS.onlyReadsMemory()) { + IsRead = true; + continue; + } + return Attribute::None; + } + + Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); + CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end(); + for (CallSite::arg_iterator A = B; A != E; ++A, ++AI) { + if (A->get() == V) { + if (AI == AE) { + assert(F->isVarArg() && + "More params than args in non-varargs call."); + return Attribute::None; + } + if (SCCNodes.count(AI)) + continue; + if (!CS.onlyReadsMemory() && !CS.onlyReadsMemory(A - B)) + return Attribute::None; + if (!CS.doesNotAccessMemory(A - B)) + IsRead = true; + } + } + break; + } + + case Instruction::Load: + IsRead = true; + break; + + case Instruction::ICmp: + case Instruction::Ret: + break; + + default: + return Attribute::None; + } + } + + return IsRead ? Attribute::ReadOnly : Attribute::ReadNone; +} + +/// AddArgumentAttrs - Deduce nocapture attributes for the SCC. +bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { bool Changed = false; SmallPtrSet<Function*, 8> SCCNodes; @@ -442,8 +545,11 @@ bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) { continue; } - for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A!=E; ++A) - if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { + for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); + A != E; ++A) { + if (!A->getType()->isPointerTy()) continue; + bool HasNonLocalUses = false; + if (!A->hasNoCaptureAttr()) { ArgumentUsesTracker Tracker(SCCNodes); PointerMayBeCaptured(A, &Tracker); if (!Tracker.Captured) { @@ -458,12 +564,32 @@ bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) { // its particulars for Argument-SCC analysis later. ArgumentGraphNode *Node = AG[A]; for (SmallVectorImpl<Argument*>::iterator UI = Tracker.Uses.begin(), - UE = Tracker.Uses.end(); UI != UE; ++UI) + UE = Tracker.Uses.end(); UI != UE; ++UI) { Node->Uses.push_back(AG[*UI]); + if (*UI != A) + HasNonLocalUses = true; + } } } // Otherwise, it's captured. Don't bother doing SCC analysis on it. } + if (!HasNonLocalUses && !A->onlyReadsMemory()) { + // Can we determine that it's readonly/readnone without doing an SCC? + // Note that we don't allow any calls at all here, or else our result + // will be dependent on the iteration order through the functions in the + // SCC. + SmallPtrSet<Argument*, 8> Self; + Self.insert(A); + Attribute::AttrKind R = determinePointerReadAttrs(A, Self); + if (R != Attribute::None) { + AttrBuilder B; + B.addAttribute(R); + A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); + Changed = true; + R == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg; + } + } + } } // The graph we've collected is partial because we stopped scanning for @@ -482,11 +608,8 @@ bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) { // eg. "void f(int* x) { if (...) f(x); }" if (ArgumentSCC[0]->Uses.size() == 1 && ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) { - ArgumentSCC[0]-> - Definition-> - addAttr(AttributeSet::get(ArgumentSCC[0]->Definition->getContext(), - ArgumentSCC[0]->Definition->getArgNo() + 1, - B)); + Argument *A = ArgumentSCC[0]->Definition; + A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; Changed = true; } @@ -532,6 +655,42 @@ bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) { ++NumNoCapture; Changed = true; } + + // We also want to compute readonly/readnone. With a small number of false + // negatives, we can assume that any pointer which is captured isn't going + // to be provably readonly or readnone, since by definition we can't + // analyze all uses of a captured pointer. + // + // The false negatives happen when the pointer is captured by a function + // that promises readonly/readnone behaviour on the pointer, then the + // pointer's lifetime ends before anything that writes to arbitrary memory. + // Also, a readonly/readnone pointer may be returned, but returning a + // pointer is capturing it. + + Attribute::AttrKind ReadAttr = Attribute::ReadNone; + for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { + Argument *A = ArgumentSCC[i]->Definition; + Attribute::AttrKind K = determinePointerReadAttrs(A, ArgumentSCCNodes); + if (K == Attribute::ReadNone) + continue; + if (K == Attribute::ReadOnly) { + ReadAttr = Attribute::ReadOnly; + continue; + } + ReadAttr = K; + break; + } + + if (ReadAttr != Attribute::None) { + AttrBuilder B; + B.addAttribute(ReadAttr); + for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { + Argument *A = ArgumentSCC[i]->Definition; + A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); + ReadAttr == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg; + Changed = true; + } + } } return Changed; @@ -678,24 +837,32 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { 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::strtoull: + if (FTy->getNumParams() < 2 || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + break; + case LibFunc::strcpy: + case LibFunc::stpcpy: + case LibFunc::strcat: 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); + setOnlyReadsMemory(F, 2); break; case LibFunc::strxfrm: if (FTy->getNumParams() != 3 || @@ -705,14 +872,15 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { 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: + setOnlyReadsMemory(F, 2); + break; + case LibFunc::strcmp: //0,1 + case LibFunc::strspn: // 0,1 + case LibFunc::strncmp: // 0,1 + case LibFunc::strcspn: //0,1 + case LibFunc::strcoll: //0,1 + case LibFunc::strcasecmp: // 0,1 + case LibFunc::strncasecmp: // if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) @@ -736,8 +904,15 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::scanf: + if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); + break; case LibFunc::setbuf: case LibFunc::setvbuf: if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) @@ -753,11 +928,31 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::stat: + 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); + setOnlyReadsMemory(F, 1); + break; case LibFunc::sscanf: + if (FTy->getNumParams() < 2 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); + break; case LibFunc::sprintf: - case LibFunc::statvfs: if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) @@ -765,6 +960,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::snprintf: if (FTy->getNumParams() != 3 || @@ -774,6 +970,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 3); + setOnlyReadsMemory(F, 3); break; case LibFunc::setitimer: if (FTy->getNumParams() != 3 || @@ -783,6 +980,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 2); setDoesNotCapture(F, 3); + setOnlyReadsMemory(F, 2); break; case LibFunc::system: if (FTy->getNumParams() != 1 || @@ -790,6 +988,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; // May throw; "system" is a valid pthread cancellation point. setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::malloc: if (FTy->getNumParams() != 1 || @@ -818,6 +1017,12 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::modf: case LibFunc::modff: case LibFunc::modfl: + if (FTy->getNumParams() < 2 || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 2); + break; case LibFunc::memcpy: case LibFunc::memccpy: case LibFunc::memmove: @@ -826,6 +1031,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::memalign: if (!FTy->getReturnType()->isPointerTy()) @@ -833,6 +1039,13 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotAlias(F, 0); break; case LibFunc::mkdir: + if (FTy->getNumParams() == 0 || + !FTy->getParamType(0)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); + break; case LibFunc::mktime: if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) @@ -856,8 +1069,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { // May throw; "read" is a valid pthread cancellation point. setDoesNotCapture(F, 2); break; - case LibFunc::rmdir: case LibFunc::rewind: + if (FTy->getNumParams() < 1 || + !FTy->getParamType(0)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + break; + case LibFunc::rmdir: case LibFunc::remove: case LibFunc::realpath: if (FTy->getNumParams() < 1 || @@ -865,8 +1084,19 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::rename: + if (FTy->getNumParams() < 2 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); + break; case LibFunc::readlink: if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || @@ -875,12 +1105,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); 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); + setOnlyReadsMemory(F, 2); break; case LibFunc::bcopy: if (FTy->getNumParams() != 3 || @@ -890,6 +1122,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); break; case LibFunc::bcmp: if (FTy->getNumParams() != 3 || @@ -916,6 +1149,12 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::chmod: case LibFunc::chown: + if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); + break; case LibFunc::ctermid: case LibFunc::clearerr: case LibFunc::closedir: @@ -939,6 +1178,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::fopen: if (FTy->getNumParams() != 2 || @@ -950,6 +1190,8 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); break; case LibFunc::fdopen: if (FTy->getNumParams() != 2 || @@ -959,6 +1201,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotAlias(F, 0); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::feof: case LibFunc::free: @@ -1004,7 +1247,16 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 3); + break; case LibFunc::fread: + if (FTy->getNumParams() != 4 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(3)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 4); + break; case LibFunc::fwrite: if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() || @@ -1013,9 +1265,28 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 4); + break; case LibFunc::fputs: + if (FTy->getNumParams() < 2 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + break; case LibFunc::fscanf: case LibFunc::fprintf: + if (FTy->getNumParams() < 2 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); + break; case LibFunc::fgetpos: if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || @@ -1055,6 +1326,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::ungetc: if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) @@ -1063,12 +1335,24 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 2); break; case LibFunc::uname: + if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + break; case LibFunc::unlink: + if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); + break; case LibFunc::unsetenv: if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::utime: case LibFunc::utimes: @@ -1079,6 +1363,8 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); break; case LibFunc::putc: if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy()) @@ -1093,13 +1379,20 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::pread: + if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy()) + return false; + // May throw; "pread" is a valid pthread cancellation point. + setDoesNotCapture(F, 2); + break; case LibFunc::pwrite: if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy()) return false; - // May throw; these are valid pthread cancellation points. + // May throw; "pwrite" is a valid pthread cancellation point. setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::putchar: setDoesNotThrow(F); @@ -1114,6 +1407,8 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); break; case LibFunc::pclose: if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) @@ -1126,8 +1421,19 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::vsscanf: + if (FTy->getNumParams() != 3 || + !FTy->getParamType(1)->isPointerTy() || + !FTy->getParamType(2)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); + break; case LibFunc::vfscanf: if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() || @@ -1136,6 +1442,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::valloc: if (!FTy->getReturnType()->isPointerTy()) @@ -1148,6 +1455,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::vfprintf: case LibFunc::vsprintf: @@ -1158,6 +1466,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::vsnprintf: if (FTy->getNumParams() != 4 || @@ -1167,12 +1476,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 3); + setOnlyReadsMemory(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); + setOnlyReadsMemory(F, 1); break; case LibFunc::opendir: if (FTy->getNumParams() != 1 || @@ -1182,6 +1493,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::tmpfile: if (!FTy->getReturnType()->isPointerTy()) @@ -1210,12 +1522,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); break; case LibFunc::lchown: if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::qsort: if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy()) @@ -1232,6 +1546,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::dunder_strtok_r: if (FTy->getNumParams() != 3 || @@ -1239,6 +1554,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 2); break; case LibFunc::under_IO_getc: if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) @@ -1258,10 +1574,20 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; case LibFunc::stat64: case LibFunc::lstat64: case LibFunc::statvfs64: + if (FTy->getNumParams() < 1 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isPointerTy()) + return false; + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + break; case LibFunc::dunder_isoc99_sscanf: if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() || @@ -1270,6 +1596,8 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); break; case LibFunc::fopen64: if (FTy->getNumParams() != 2 || @@ -1281,6 +1609,8 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); + setOnlyReadsMemory(F, 1); + setOnlyReadsMemory(F, 2); break; case LibFunc::fseeko64: case LibFunc::ftello64: @@ -1307,7 +1637,18 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { return false; // May throw; "open" is a valid pthread cancellation point. setDoesNotCapture(F, 1); + setOnlyReadsMemory(F, 1); break; + case LibFunc::gettimeofday: + if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isPointerTy()) + return false; + // Currently some platforms have the restrict keyword on the arguments to + // gettimeofday. To be conservative, do not add noalias to gettimeofday's + // arguments. + setDoesNotThrow(F); + setDoesNotCapture(F, 1); + setDoesNotCapture(F, 2); default: // Didn't mark any attributes. return false; @@ -1339,7 +1680,7 @@ bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) { bool Changed = annotateLibraryCalls(SCC); Changed |= AddReadAttrs(SCC); - Changed |= AddNoCaptureAttrs(SCC); + Changed |= AddArgumentAttrs(SCC); Changed |= AddNoAliasAttrs(SCC); return Changed; } |