|  | //===- FunctionAttrs.cpp - Pass which marks functions attributes ----------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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.  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. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Transforms/IPO.h" | 
|  | #include "llvm/ADT/SCCIterator.h" | 
|  | #include "llvm/ADT/SetVector.h" | 
|  | #include "llvm/ADT/SmallSet.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/Analysis/AliasAnalysis.h" | 
|  | #include "llvm/Analysis/CallGraph.h" | 
|  | #include "llvm/Analysis/CallGraphSCCPass.h" | 
|  | #include "llvm/Analysis/CaptureTracking.h" | 
|  | #include "llvm/IR/GlobalVariable.h" | 
|  | #include "llvm/IR/InstIterator.h" | 
|  | #include "llvm/IR/IntrinsicInst.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  | #include "llvm/Target/TargetLibraryInfo.h" | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "functionattrs" | 
|  |  | 
|  | 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"); | 
|  |  | 
|  | namespace { | 
|  | struct FunctionAttrs : public CallGraphSCCPass { | 
|  | static char ID; // Pass identification, replacement for typeid | 
|  | FunctionAttrs() : CallGraphSCCPass(ID), AA(nullptr) { | 
|  | initializeFunctionAttrsPass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | // runOnSCC - Analyze the SCC, performing the transformation if possible. | 
|  | bool runOnSCC(CallGraphSCC &SCC) override; | 
|  |  | 
|  | // AddReadAttrs - Deduce readonly/readnone attributes for the SCC. | 
|  | bool AddReadAttrs(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, | 
|  | SmallPtrSet<Function*, 8> &) const; | 
|  |  | 
|  | // 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 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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); | 
|  |  | 
|  | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
|  | AU.setPreservesCFG(); | 
|  | AU.addRequired<AliasAnalysis>(); | 
|  | AU.addRequired<TargetLibraryInfo>(); | 
|  | CallGraphSCCPass::getAnalysisUsage(AU); | 
|  | } | 
|  |  | 
|  | private: | 
|  | AliasAnalysis *AA; | 
|  | TargetLibraryInfo *TLI; | 
|  | }; | 
|  | } | 
|  |  | 
|  | char FunctionAttrs::ID = 0; | 
|  | INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs", | 
|  | "Deduce function attributes", false, false) | 
|  | INITIALIZE_AG_DEPENDENCY(AliasAnalysis) | 
|  | INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) | 
|  | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo) | 
|  | INITIALIZE_PASS_END(FunctionAttrs, "functionattrs", | 
|  | "Deduce function attributes", false, false) | 
|  |  | 
|  | Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); } | 
|  |  | 
|  |  | 
|  | /// AddReadAttrs - Deduce readonly/readnone attributes for the SCC. | 
|  | bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { | 
|  | SmallPtrSet<Function*, 8> SCCNodes; | 
|  |  | 
|  | // Fill SCCNodes with the elements of the SCC.  Used for quickly | 
|  | // looking up whether a given CallGraphNode is in this SCC. | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) | 
|  | SCCNodes.insert((*I)->getFunction()); | 
|  |  | 
|  | // Check if any of the functions in the SCC read or write memory.  If they | 
|  | // write memory then they can't be marked readnone or readonly. | 
|  | bool ReadsMemory = false; | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | 
|  | Function *F = (*I)->getFunction(); | 
|  |  | 
|  | if (!F || F->hasFnAttribute(Attribute::OptimizeNone)) | 
|  | // External node or node we don't want to optimize - assume it may write | 
|  | // memory and give up. | 
|  | return false; | 
|  |  | 
|  | AliasAnalysis::ModRefBehavior MRB = AA->getModRefBehavior(F); | 
|  | if (MRB == AliasAnalysis::DoesNotAccessMemory) | 
|  | // Already perfect! | 
|  | continue; | 
|  |  | 
|  | // Definitions with weak linkage may be overridden at linktime with | 
|  | // something that writes memory, so treat them like declarations. | 
|  | if (F->isDeclaration() || F->mayBeOverridden()) { | 
|  | if (!AliasAnalysis::onlyReadsMemory(MRB)) | 
|  | // May write memory.  Just give up. | 
|  | return false; | 
|  |  | 
|  | ReadsMemory = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Scan the function body for instructions that may read or write memory. | 
|  | for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) { | 
|  | Instruction *I = &*II; | 
|  |  | 
|  | // Some instructions can be ignored even if they read or write memory. | 
|  | // Detect these now, skipping to the next instruction if one is found. | 
|  | CallSite CS(cast<Value>(I)); | 
|  | if (CS) { | 
|  | // Ignore calls to functions in the same SCC. | 
|  | if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction())) | 
|  | continue; | 
|  | AliasAnalysis::ModRefBehavior MRB = AA->getModRefBehavior(CS); | 
|  | // If the call doesn't access arbitrary memory, we may be able to | 
|  | // figure out something. | 
|  | if (AliasAnalysis::onlyAccessesArgPointees(MRB)) { | 
|  | // If the call does access argument pointees, check each argument. | 
|  | if (AliasAnalysis::doesAccessArgPointees(MRB)) | 
|  | // Check whether all pointer arguments point to local memory, and | 
|  | // ignore calls that only access local memory. | 
|  | for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); | 
|  | CI != CE; ++CI) { | 
|  | Value *Arg = *CI; | 
|  | if (Arg->getType()->isPointerTy()) { | 
|  | AAMDNodes AAInfo; | 
|  | I->getAAMetadata(AAInfo); | 
|  |  | 
|  | AliasAnalysis::Location Loc(Arg, | 
|  | AliasAnalysis::UnknownSize, AAInfo); | 
|  | if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) { | 
|  | if (MRB & AliasAnalysis::Mod) | 
|  | // Writes non-local memory.  Give up. | 
|  | return false; | 
|  | if (MRB & AliasAnalysis::Ref) | 
|  | // Ok, it reads non-local memory. | 
|  | ReadsMemory = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | continue; | 
|  | } | 
|  | // The call could access any memory. If that includes writes, give up. | 
|  | if (MRB & AliasAnalysis::Mod) | 
|  | return false; | 
|  | // If it reads, note it. | 
|  | if (MRB & AliasAnalysis::Ref) | 
|  | ReadsMemory = true; | 
|  | continue; | 
|  | } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) { | 
|  | // Ignore non-volatile loads from local memory. (Atomic is okay here.) | 
|  | if (!LI->isVolatile()) { | 
|  | AliasAnalysis::Location Loc = AA->getLocation(LI); | 
|  | if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) | 
|  | continue; | 
|  | } | 
|  | } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { | 
|  | // Ignore non-volatile stores to local memory. (Atomic is okay here.) | 
|  | if (!SI->isVolatile()) { | 
|  | AliasAnalysis::Location Loc = AA->getLocation(SI); | 
|  | if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) | 
|  | continue; | 
|  | } | 
|  | } else if (VAArgInst *VI = dyn_cast<VAArgInst>(I)) { | 
|  | // Ignore vaargs on local memory. | 
|  | AliasAnalysis::Location Loc = AA->getLocation(VI); | 
|  | if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Any remaining instructions need to be taken seriously!  Check if they | 
|  | // read or write memory. | 
|  | if (I->mayWriteToMemory()) | 
|  | // Writes memory.  Just give up. | 
|  | return false; | 
|  |  | 
|  | // If this instruction may read memory, remember that. | 
|  | ReadsMemory |= I->mayReadFromMemory(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Success!  Functions in this SCC do not access memory, or only read memory. | 
|  | // Give them the appropriate attribute. | 
|  | bool MadeChange = false; | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | 
|  | Function *F = (*I)->getFunction(); | 
|  |  | 
|  | if (F->doesNotAccessMemory()) | 
|  | // Already perfect! | 
|  | continue; | 
|  |  | 
|  | if (F->onlyReadsMemory() && ReadsMemory) | 
|  | // No change. | 
|  | continue; | 
|  |  | 
|  | MadeChange = true; | 
|  |  | 
|  | // Clear out any existing attributes. | 
|  | AttrBuilder B; | 
|  | B.addAttribute(Attribute::ReadOnly) | 
|  | .addAttribute(Attribute::ReadNone); | 
|  | F->removeAttributes(AttributeSet::FunctionIndex, | 
|  | AttributeSet::get(F->getContext(), | 
|  | AttributeSet::FunctionIndex, B)); | 
|  |  | 
|  | // Add in the new attribute. | 
|  | F->addAttribute(AttributeSet::FunctionIndex, | 
|  | ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone); | 
|  |  | 
|  | if (ReadsMemory) | 
|  | ++NumReadOnly; | 
|  | else | 
|  | ++NumReadNone; | 
|  | } | 
|  |  | 
|  | return MadeChange; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | // For a given pointer Argument, this retains a list of Arguments of functions | 
|  | // in the same SCC that the pointer data flows into. We use this to build an | 
|  | // SCC of the arguments. | 
|  | struct ArgumentGraphNode { | 
|  | Argument *Definition; | 
|  | SmallVector<ArgumentGraphNode*, 4> Uses; | 
|  | }; | 
|  |  | 
|  | class ArgumentGraph { | 
|  | // We store pointers to ArgumentGraphNode objects, so it's important that | 
|  | // that they not move around upon insert. | 
|  | typedef std::map<Argument*, ArgumentGraphNode> ArgumentMapTy; | 
|  |  | 
|  | ArgumentMapTy ArgumentMap; | 
|  |  | 
|  | // There is no root node for the argument graph, in fact: | 
|  | //   void f(int *x, int *y) { if (...) f(x, y); } | 
|  | // is an example where the graph is disconnected. The SCCIterator requires a | 
|  | // single entry point, so we maintain a fake ("synthetic") root node that | 
|  | // uses every node. Because the graph is directed and nothing points into | 
|  | // the root, it will not participate in any SCCs (except for its own). | 
|  | ArgumentGraphNode SyntheticRoot; | 
|  |  | 
|  | public: | 
|  | ArgumentGraph() { SyntheticRoot.Definition = nullptr; } | 
|  |  | 
|  | typedef SmallVectorImpl<ArgumentGraphNode*>::iterator iterator; | 
|  |  | 
|  | iterator begin() { return SyntheticRoot.Uses.begin(); } | 
|  | iterator end() { return SyntheticRoot.Uses.end(); } | 
|  | ArgumentGraphNode *getEntryNode() { return &SyntheticRoot; } | 
|  |  | 
|  | ArgumentGraphNode *operator[](Argument *A) { | 
|  | ArgumentGraphNode &Node = ArgumentMap[A]; | 
|  | Node.Definition = A; | 
|  | SyntheticRoot.Uses.push_back(&Node); | 
|  | return &Node; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // This tracker checks whether callees are in the SCC, and if so it does not | 
|  | // consider that a capture, instead adding it to the "Uses" list and | 
|  | // continuing with the analysis. | 
|  | struct ArgumentUsesTracker : public CaptureTracker { | 
|  | ArgumentUsesTracker(const SmallPtrSet<Function*, 8> &SCCNodes) | 
|  | : Captured(false), SCCNodes(SCCNodes) {} | 
|  |  | 
|  | void tooManyUses() override { Captured = true; } | 
|  |  | 
|  | bool captured(const Use *U) override { | 
|  | CallSite CS(U->getUser()); | 
|  | if (!CS.getInstruction()) { Captured = true; return true; } | 
|  |  | 
|  | 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) { | 
|  | if (AI == AE) { | 
|  | assert(F->isVarArg() && "More params than args in non-varargs call"); | 
|  | Captured = true; | 
|  | return true; | 
|  | } | 
|  | if (PI == U) { | 
|  | Uses.push_back(AI); | 
|  | Found = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | assert(Found && "Capturing call-site captured nothing?"); | 
|  | (void)Found; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Captured;  // True only if certainly captured (used outside our SCC). | 
|  | SmallVector<Argument*, 4> Uses;  // Uses within our SCC. | 
|  |  | 
|  | const SmallPtrSet<Function*, 8> &SCCNodes; | 
|  | }; | 
|  | } | 
|  |  | 
|  | namespace llvm { | 
|  | template<> struct GraphTraits<ArgumentGraphNode*> { | 
|  | typedef ArgumentGraphNode NodeType; | 
|  | typedef SmallVectorImpl<ArgumentGraphNode*>::iterator ChildIteratorType; | 
|  |  | 
|  | static inline NodeType *getEntryNode(NodeType *A) { return A; } | 
|  | static inline ChildIteratorType child_begin(NodeType *N) { | 
|  | return N->Uses.begin(); | 
|  | } | 
|  | static inline ChildIteratorType child_end(NodeType *N) { | 
|  | return N->Uses.end(); | 
|  | } | 
|  | }; | 
|  | template<> struct GraphTraits<ArgumentGraph*> | 
|  | : public GraphTraits<ArgumentGraphNode*> { | 
|  | static NodeType *getEntryNode(ArgumentGraph *AG) { | 
|  | return AG->getEntryNode(); | 
|  | } | 
|  | static ChildIteratorType nodes_begin(ArgumentGraph *AG) { | 
|  | return AG->begin(); | 
|  | } | 
|  | static ChildIteratorType nodes_end(ArgumentGraph *AG) { | 
|  | return AG->end(); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | // 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; | 
|  |  | 
|  | // inalloca arguments are always clobbered by the call. | 
|  | if (A->hasInAllocaAttr()) | 
|  | return Attribute::None; | 
|  |  | 
|  | bool IsRead = false; | 
|  | // We don't need to track IsWritten. If A is written to, return immediately. | 
|  |  | 
|  | for (Use &U : A->uses()) { | 
|  | if (Count++ >= 20) | 
|  | return Attribute::None; | 
|  |  | 
|  | 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: | 
|  | case Instruction::AddrSpaceCast: | 
|  | // The original value is not read/written via this if the new value isn't. | 
|  | for (Use &UU : I->uses()) | 
|  | if (Visited.insert(&UU).second) | 
|  | Worklist.push_back(&UU); | 
|  | break; | 
|  |  | 
|  | case Instruction::Call: | 
|  | case Instruction::Invoke: { | 
|  | bool Captures = true; | 
|  |  | 
|  | if (I->getType()->isVoidTy()) | 
|  | Captures = false; | 
|  |  | 
|  | auto AddUsersToWorklistIfCapturing = [&] { | 
|  | if (Captures) | 
|  | for (Use &UU : I->uses()) | 
|  | if (Visited.insert(&UU).second) | 
|  | Worklist.push_back(&UU); | 
|  | }; | 
|  |  | 
|  | CallSite CS(I); | 
|  | if (CS.doesNotAccessMemory()) { | 
|  | AddUsersToWorklistIfCapturing(); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | Function *F = CS.getCalledFunction(); | 
|  | if (!F) { | 
|  | if (CS.onlyReadsMemory()) { | 
|  | IsRead = true; | 
|  | AddUsersToWorklistIfCapturing(); | 
|  | 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; | 
|  | } | 
|  | Captures &= !CS.doesNotCapture(A - B); | 
|  | if (SCCNodes.count(AI)) | 
|  | continue; | 
|  | if (!CS.onlyReadsMemory() && !CS.onlyReadsMemory(A - B)) | 
|  | return Attribute::None; | 
|  | if (!CS.doesNotAccessMemory(A - B)) | 
|  | IsRead = true; | 
|  | } | 
|  | } | 
|  | AddUsersToWorklistIfCapturing(); | 
|  | 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; | 
|  |  | 
|  | // Fill SCCNodes with the elements of the SCC.  Used for quickly | 
|  | // looking up whether a given CallGraphNode is in this SCC. | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | 
|  | Function *F = (*I)->getFunction(); | 
|  | if (F && !F->isDeclaration() && !F->mayBeOverridden() && | 
|  | !F->hasFnAttribute(Attribute::OptimizeNone)) | 
|  | SCCNodes.insert(F); | 
|  | } | 
|  |  | 
|  | ArgumentGraph AG; | 
|  |  | 
|  | AttrBuilder B; | 
|  | B.addAttribute(Attribute::NoCapture); | 
|  |  | 
|  | // Check each function in turn, determining which pointer arguments are not | 
|  | // captured. | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | 
|  | Function *F = (*I)->getFunction(); | 
|  |  | 
|  | if (!F || F->hasFnAttribute(Attribute::OptimizeNone)) | 
|  | // External node or function we're trying not to optimize - only a problem | 
|  | // for arguments that we pass to it. | 
|  | continue; | 
|  |  | 
|  | // Definitions with weak linkage may be overridden at linktime with | 
|  | // something that captures pointers, so treat them like declarations. | 
|  | if (F->isDeclaration() || F->mayBeOverridden()) | 
|  | continue; | 
|  |  | 
|  | // Functions that are readonly (or readnone) and nounwind and don't return | 
|  | // a value can't capture arguments. Don't analyze them. | 
|  | if (F->onlyReadsMemory() && F->doesNotThrow() && | 
|  | F->getReturnType()->isVoidTy()) { | 
|  | for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); | 
|  | A != E; ++A) { | 
|  | if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { | 
|  | A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo() + 1, B)); | 
|  | ++NumNoCapture; | 
|  | Changed = true; | 
|  | } | 
|  | } | 
|  | continue; | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | if (Tracker.Uses.empty()) { | 
|  | // If it's trivially not captured, mark it nocapture now. | 
|  | A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo()+1, B)); | 
|  | ++NumNoCapture; | 
|  | Changed = true; | 
|  | } else { | 
|  | // If it's not trivially captured and not trivially not captured, | 
|  | // then it must be calling into another function in our SCC. Save | 
|  | // 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) { | 
|  | 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 | 
|  | // argument uses once we solved the argument trivially. These partial nodes | 
|  | // show up as ArgumentGraphNode objects with an empty Uses list, and for | 
|  | // these nodes the final decision about whether they capture has already been | 
|  | // made.  If the definition doesn't have a 'nocapture' attribute by now, it | 
|  | // captures. | 
|  |  | 
|  | for (scc_iterator<ArgumentGraph*> I = scc_begin(&AG); !I.isAtEnd(); ++I) { | 
|  | const std::vector<ArgumentGraphNode *> &ArgumentSCC = *I; | 
|  | if (ArgumentSCC.size() == 1) { | 
|  | if (!ArgumentSCC[0]->Definition) continue;  // synthetic root node | 
|  |  | 
|  | // eg. "void f(int* x) { if (...) f(x); }" | 
|  | if (ArgumentSCC[0]->Uses.size() == 1 && | 
|  | ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) { | 
|  | Argument *A = ArgumentSCC[0]->Definition; | 
|  | A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, B)); | 
|  | ++NumNoCapture; | 
|  | Changed = true; | 
|  | } | 
|  | continue; | 
|  | } | 
|  |  | 
|  | bool SCCCaptured = false; | 
|  | for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); | 
|  | I != E && !SCCCaptured; ++I) { | 
|  | ArgumentGraphNode *Node = *I; | 
|  | if (Node->Uses.empty()) { | 
|  | if (!Node->Definition->hasNoCaptureAttr()) | 
|  | SCCCaptured = true; | 
|  | } | 
|  | } | 
|  | if (SCCCaptured) continue; | 
|  |  | 
|  | SmallPtrSet<Argument*, 8> ArgumentSCCNodes; | 
|  | // Fill ArgumentSCCNodes with the elements of the ArgumentSCC.  Used for | 
|  | // quickly looking up whether a given Argument is in this ArgumentSCC. | 
|  | for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E; ++I) { | 
|  | ArgumentSCCNodes.insert((*I)->Definition); | 
|  | } | 
|  |  | 
|  | for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); | 
|  | I != E && !SCCCaptured; ++I) { | 
|  | ArgumentGraphNode *N = *I; | 
|  | for (SmallVectorImpl<ArgumentGraphNode*>::iterator UI = N->Uses.begin(), | 
|  | UE = N->Uses.end(); UI != UE; ++UI) { | 
|  | Argument *A = (*UI)->Definition; | 
|  | if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A)) | 
|  | continue; | 
|  | SCCCaptured = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (SCCCaptured) continue; | 
|  |  | 
|  | 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)); | 
|  | ++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; | 
|  | } | 
|  |  | 
|  | /// IsFunctionMallocLike - A function is malloc-like if it returns either null | 
|  | /// or a pointer that doesn't alias any other pointer visible to the caller. | 
|  | bool FunctionAttrs::IsFunctionMallocLike(Function *F, | 
|  | SmallPtrSet<Function*, 8> &SCCNodes) const { | 
|  | SmallSetVector<Value *, 8> FlowsToReturn; | 
|  | for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) | 
|  | if (ReturnInst *Ret = dyn_cast<ReturnInst>(I->getTerminator())) | 
|  | FlowsToReturn.insert(Ret->getReturnValue()); | 
|  |  | 
|  | for (unsigned i = 0; i != FlowsToReturn.size(); ++i) { | 
|  | Value *RetVal = FlowsToReturn[i]; | 
|  |  | 
|  | if (Constant *C = dyn_cast<Constant>(RetVal)) { | 
|  | if (!C->isNullValue() && !isa<UndefValue>(C)) | 
|  | return false; | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (isa<Argument>(RetVal)) | 
|  | return false; | 
|  |  | 
|  | if (Instruction *RVI = dyn_cast<Instruction>(RetVal)) | 
|  | switch (RVI->getOpcode()) { | 
|  | // Extend the analysis by looking upwards. | 
|  | case Instruction::BitCast: | 
|  | case Instruction::GetElementPtr: | 
|  | case Instruction::AddrSpaceCast: | 
|  | FlowsToReturn.insert(RVI->getOperand(0)); | 
|  | continue; | 
|  | case Instruction::Select: { | 
|  | SelectInst *SI = cast<SelectInst>(RVI); | 
|  | FlowsToReturn.insert(SI->getTrueValue()); | 
|  | FlowsToReturn.insert(SI->getFalseValue()); | 
|  | continue; | 
|  | } | 
|  | case Instruction::PHI: { | 
|  | PHINode *PN = cast<PHINode>(RVI); | 
|  | for (int i = 0, e = PN->getNumIncomingValues(); i != e; ++i) | 
|  | FlowsToReturn.insert(PN->getIncomingValue(i)); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Check whether the pointer came from an allocation. | 
|  | case Instruction::Alloca: | 
|  | break; | 
|  | case Instruction::Call: | 
|  | case Instruction::Invoke: { | 
|  | CallSite CS(RVI); | 
|  | if (CS.paramHasAttr(0, Attribute::NoAlias)) | 
|  | break; | 
|  | if (CS.getCalledFunction() && | 
|  | SCCNodes.count(CS.getCalledFunction())) | 
|  | break; | 
|  | } // fall-through | 
|  | default: | 
|  | return false;  // Did not come from an allocation. | 
|  | } | 
|  |  | 
|  | if (PointerMayBeCaptured(RetVal, false, /*StoreCaptures=*/false)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// AddNoAliasAttrs - Deduce noalias attributes for the SCC. | 
|  | bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) { | 
|  | SmallPtrSet<Function*, 8> SCCNodes; | 
|  |  | 
|  | // Fill SCCNodes with the elements of the SCC.  Used for quickly | 
|  | // looking up whether a given CallGraphNode is in this SCC. | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) | 
|  | SCCNodes.insert((*I)->getFunction()); | 
|  |  | 
|  | // Check each function in turn, determining which functions return noalias | 
|  | // pointers. | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | 
|  | Function *F = (*I)->getFunction(); | 
|  |  | 
|  | if (!F || F->hasFnAttribute(Attribute::OptimizeNone)) | 
|  | // External node or node we don't want to optimize - skip it; | 
|  | return false; | 
|  |  | 
|  | // Already noalias. | 
|  | if (F->doesNotAlias(0)) | 
|  | continue; | 
|  |  | 
|  | // Definitions with weak linkage may be overridden at linktime, so | 
|  | // treat them like declarations. | 
|  | if (F->isDeclaration() || F->mayBeOverridden()) | 
|  | return false; | 
|  |  | 
|  | // We annotate noalias return values, which are only applicable to | 
|  | // pointer types. | 
|  | if (!F->getReturnType()->isPointerTy()) | 
|  | continue; | 
|  |  | 
|  | if (!IsFunctionMallocLike(F, SCCNodes)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool MadeChange = false; | 
|  | for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { | 
|  | Function *F = (*I)->getFunction(); | 
|  | if (F->doesNotAlias(0) || !F->getReturnType()->isPointerTy()) | 
|  | continue; | 
|  |  | 
|  | F->setDoesNotAlias(0); | 
|  | ++NumNoAlias; | 
|  | MadeChange = true; | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | if (F.hasFnAttribute(Attribute::OptimizeNone)) | 
|  | return false; | 
|  |  | 
|  | 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::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: | 
|  | 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 || | 
|  | !FTy->getParamType(0)->isPointerTy() || | 
|  | !FTy->getParamType(1)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 1); | 
|  | setDoesNotCapture(F, 2); | 
|  | 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()) | 
|  | 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); | 
|  | 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()) | 
|  | 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); | 
|  | 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: | 
|  | 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::snprintf: | 
|  | if (FTy->getNumParams() != 3 || | 
|  | !FTy->getParamType(0)->isPointerTy() || | 
|  | !FTy->getParamType(2)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 1); | 
|  | setDoesNotCapture(F, 3); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(F, 2); | 
|  | 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); | 
|  | setOnlyReadsMemory(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: | 
|  | 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: | 
|  | if (FTy->getNumParams() < 2 || | 
|  | !FTy->getParamType(1)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 2); | 
|  | setOnlyReadsMemory(F, 2); | 
|  | break; | 
|  | case LibFunc::memalign: | 
|  | if (!FTy->getReturnType()->isPointerTy()) | 
|  | return false; | 
|  | 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()) | 
|  | 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::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 || | 
|  | !FTy->getParamType(0)->isPointerTy()) | 
|  | 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() || | 
|  | !FTy->getParamType(1)->isPointerTy()) | 
|  | return false; | 
|  | 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 || | 
|  | !FTy->getParamType(0)->isPointerTy() || | 
|  | !FTy->getParamType(1)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 1); | 
|  | setDoesNotCapture(F, 2); | 
|  | setOnlyReadsMemory(F, 1); | 
|  | 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: | 
|  | 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: | 
|  | 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); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(F, 1); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(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); | 
|  | 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() || | 
|  | !FTy->getParamType(3)->isPointerTy()) | 
|  | return false; | 
|  | 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() || | 
|  | !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); | 
|  | setOnlyReadsMemory(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: | 
|  | 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: | 
|  | 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::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); | 
|  | 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; "pwrite" is a valid pthread cancellation point. | 
|  | setDoesNotCapture(F, 2); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(F, 1); | 
|  | setOnlyReadsMemory(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); | 
|  | 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() || | 
|  | !FTy->getParamType(2)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 1); | 
|  | setDoesNotCapture(F, 2); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(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); | 
|  | 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 || | 
|  | !FTy->getReturnType()->isPointerTy() || | 
|  | !FTy->getParamType(0)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotAlias(F, 0); | 
|  | setDoesNotCapture(F, 1); | 
|  | setOnlyReadsMemory(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); | 
|  | 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()) | 
|  | 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); | 
|  | setOnlyReadsMemory(F, 1); | 
|  | break; | 
|  | case LibFunc::dunder_strtok_r: | 
|  | if (FTy->getNumParams() != 3 || | 
|  | !FTy->getParamType(1)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 2); | 
|  | setOnlyReadsMemory(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); | 
|  | 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() || | 
|  | !FTy->getParamType(1)->isPointerTy()) | 
|  | return false; | 
|  | setDoesNotThrow(F); | 
|  | setDoesNotCapture(F, 1); | 
|  | setDoesNotCapture(F, 2); | 
|  | setOnlyReadsMemory(F, 1); | 
|  | setOnlyReadsMemory(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); | 
|  | setOnlyReadsMemory(F, 1); | 
|  | setOnlyReadsMemory(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); | 
|  | 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); | 
|  | 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 && F->isDeclaration()) | 
|  | MadeChange |= inferPrototypeAttributes(*F); | 
|  | } | 
|  |  | 
|  | return MadeChange; | 
|  | } | 
|  |  | 
|  | bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) { | 
|  | AA = &getAnalysis<AliasAnalysis>(); | 
|  | TLI = &getAnalysis<TargetLibraryInfo>(); | 
|  |  | 
|  | bool Changed = annotateLibraryCalls(SCC); | 
|  | Changed |= AddReadAttrs(SCC); | 
|  | Changed |= AddArgumentAttrs(SCC); | 
|  | Changed |= AddNoAliasAttrs(SCC); | 
|  | return Changed; | 
|  | } |