<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Dec 27, 2015 at 12:41 AM, Chandler Carruth via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: chandlerc<br>
Date: Sun Dec 27 02:41:34 2015<br>
New Revision: 256466<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=256466&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=256466&view=rev</a><br>
Log:<br>
[attrs] Extract the pure inference of function attributes into<br>
a standalone pass.<br>
<br>
There is no call graph or even interesting analysis for this part of<br>
function attributes -- it is literally inferring attributes based on the<br>
target library identification. As such, we can do it using a much<br>
simpler module pass that just walks the declarations.</blockquote><div><br></div><div>Just for my own curiosity - why would this be a module pass rather than a function pass? (I assumed that you want the smallest scope pass possible (less power for the pass, more versatility for the pass manager in scheduling, etc) & it doesn't look like this does anything interprocedural, as far as I understand)<br><br>Maybe it's just an ordering constraint in the current/legacy pass manager that won't be present in the new one?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> This can also<br>
happen much earlier in the pass pipeline which has benefits for any<br>
number of other passes.<br>
<br>
In the process, I've cleaned up one particular aspect of the logic which<br>
was necessary in order to separate the two passes cleanly. It now counts<br>
inferred attributes independently rather than just counting all the<br>
inferred attributes as one, and the counts are more clearly explained.<br>
<br>
The two test cases we had for this code path are both ... woefully<br>
inadequate and copies of each other. I've kept the superset test and<br>
updated it. We need more testing here, but I had to pick somewhere to<br>
stop fixing everything broken I saw here.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D15676" rel="noreferrer" target="_blank">http://reviews.llvm.org/D15676</a><br>
<br>
Added:<br>
    llvm/trunk/include/llvm/Transforms/IPO/InferFunctionAttrs.h<br>
    llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp<br>
    llvm/trunk/test/Transforms/InferFunctionAttrs/<br>
    llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll<br>
      - copied, changed from r256465, llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll<br>
Removed:<br>
    llvm/trunk/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll<br>
    llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll<br>
Modified:<br>
    llvm/trunk/include/llvm/InitializePasses.h<br>
    llvm/trunk/lib/Passes/PassBuilder.cpp<br>
    llvm/trunk/lib/Passes/PassRegistry.def<br>
    llvm/trunk/lib/Transforms/IPO/CMakeLists.txt<br>
    llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp<br>
    llvm/trunk/lib/Transforms/IPO/IPO.cpp<br>
    llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp<br>
    llvm/trunk/test/Transforms/InstCombine/strto-1.ll<br>
<br>
Modified: llvm/trunk/include/llvm/InitializePasses.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/InitializePasses.h (original)<br>
+++ llvm/trunk/include/llvm/InitializePasses.h Sun Dec 27 02:41:34 2015<br>
@@ -145,6 +145,7 @@ void initializeIVUsersPass(PassRegistry&<br>
 void initializeIfConverterPass(PassRegistry&);<br>
 void initializeInductiveRangeCheckEliminationPass(PassRegistry&);<br>
 void initializeIndVarSimplifyPass(PassRegistry&);<br>
+void initializeInferFunctionAttrsLegacyPassPass(PassRegistry&);<br>
 void initializeInlineCostAnalysisPass(PassRegistry&);<br>
 void initializeInstructionCombiningPassPass(PassRegistry&);<br>
 void initializeInstCountPass(PassRegistry&);<br>
<br>
Added: llvm/trunk/include/llvm/Transforms/IPO/InferFunctionAttrs.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/InferFunctionAttrs.h?rev=256466&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/InferFunctionAttrs.h?rev=256466&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Transforms/IPO/InferFunctionAttrs.h (added)<br>
+++ llvm/trunk/include/llvm/Transforms/IPO/InferFunctionAttrs.h Sun Dec 27 02:41:34 2015<br>
@@ -0,0 +1,38 @@<br>
+//===-- InferFunctionAttrs.h - Infer implicit function attributes ---------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+///<br>
+/// \file<br>
+/// Interfaces for passes which infer implicit function attributes from the<br>
+/// name and signature of function declarations.<br>
+///<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_TRANSFORMS_IPO_INFERFUNCTIONATTRS_H<br>
+#define LLVM_TRANSFORMS_IPO_INFERFUNCTIONATTRS_H<br>
+<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/IR/PassManager.h"<br>
+<br>
+namespace llvm {<br>
+<br>
+/// A pass which infers function attributes from the names and signatures of<br>
+/// function declarations in a module.<br>
+class InferFunctionAttrsPass {<br>
+public:<br>
+  static StringRef name() { return "InferFunctionAttrsPass"; }<br>
+  PreservedAnalyses run(Module &M, AnalysisManager<Module> *AM);<br>
+};<br>
+<br>
+/// Create a legacy pass manager instance of a pass to infer function<br>
+/// attributes.<br>
+Pass *createInferFunctionAttrsLegacyPass();<br>
+<br>
+}<br>
+<br>
+#endif // LLVM_TRANSFORMS_IPO_INFERFUNCTIONATTRS_H<br>
<br>
Modified: llvm/trunk/lib/Passes/PassBuilder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassBuilder.cpp?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassBuilder.cpp?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Passes/PassBuilder.cpp (original)<br>
+++ llvm/trunk/lib/Passes/PassBuilder.cpp Sun Dec 27 02:41:34 2015<br>
@@ -30,6 +30,7 @@<br>
 #include "llvm/Support/Debug.h"<br>
 #include "llvm/Target/TargetMachine.h"<br>
 #include "llvm/Transforms/IPO/ForceFunctionAttrs.h"<br>
+#include "llvm/Transforms/IPO/InferFunctionAttrs.h"<br>
 #include "llvm/Transforms/IPO/StripDeadPrototypes.h"<br>
 #include "llvm/Transforms/InstCombine/InstCombine.h"<br>
 #include "llvm/Transforms/Scalar/ADCE.h"<br>
<br>
Modified: llvm/trunk/lib/Passes/PassRegistry.def<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassRegistry.def?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassRegistry.def?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Passes/PassRegistry.def (original)<br>
+++ llvm/trunk/lib/Passes/PassRegistry.def Sun Dec 27 02:41:34 2015<br>
@@ -28,6 +28,7 @@ MODULE_ANALYSIS("targetlibinfo", TargetL<br>
 #define MODULE_PASS(NAME, CREATE_PASS)<br>
 #endif<br>
 MODULE_PASS("forceattrs", ForceFunctionAttrsPass())<br>
+MODULE_PASS("inferattrs", InferFunctionAttrsPass())<br>
 MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())<br>
 MODULE_PASS("no-op-module", NoOpModulePass())<br>
 MODULE_PASS("print", PrintModulePass(dbgs()))<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/CMakeLists.txt?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/CMakeLists.txt?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/CMakeLists.txt Sun Dec 27 02:41:34 2015<br>
@@ -13,6 +13,7 @@ add_llvm_library(LLVMipo<br>
   GlobalOpt.cpp<br>
   IPConstantPropagation.cpp<br>
   IPO.cpp<br>
+  InferFunctionAttrs.cpp<br>
   InlineAlways.cpp<br>
   InlineSimple.cpp<br>
   Inliner.cpp<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp Sun Dec 27 02:41:34 2015<br>
@@ -50,7 +50,6 @@ STATISTIC(NumReadNoneArg, "Number of arg<br>
 STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");<br>
 STATISTIC(NumNoAlias, "Number of function returns marked noalias");<br>
 STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");<br>
-STATISTIC(NumAnnotated, "Number of attributes added to library functions");<br>
 STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");<br>
<br>
 namespace {<br>
@@ -942,48 +941,6 @@ static bool addNonNullAttrs(const SCCNod<br>
   return MadeChange;<br>
 }<br>
<br>
-static void setDoesNotAccessMemory(Function &F) {<br>
-  if (!F.doesNotAccessMemory()) {<br>
-    F.setDoesNotAccessMemory();<br>
-    ++NumAnnotated;<br>
-  }<br>
-}<br>
-<br>
-static void setOnlyReadsMemory(Function &F) {<br>
-  if (!F.onlyReadsMemory()) {<br>
-    F.setOnlyReadsMemory();<br>
-    ++NumAnnotated;<br>
-  }<br>
-}<br>
-<br>
-static void setDoesNotThrow(Function &F) {<br>
-  if (!F.doesNotThrow()) {<br>
-    F.setDoesNotThrow();<br>
-    ++NumAnnotated;<br>
-  }<br>
-}<br>
-<br>
-static void setDoesNotCapture(Function &F, unsigned n) {<br>
-  if (!F.doesNotCapture(n)) {<br>
-    F.setDoesNotCapture(n);<br>
-    ++NumAnnotated;<br>
-  }<br>
-}<br>
-<br>
-static void setOnlyReadsMemory(Function &F, unsigned n) {<br>
-  if (!F.onlyReadsMemory(n)) {<br>
-    F.setOnlyReadsMemory(n);<br>
-    ++NumAnnotated;<br>
-  }<br>
-}<br>
-<br>
-static void setDoesNotAlias(Function &F, unsigned n) {<br>
-  if (!F.doesNotAlias(n)) {<br>
-    F.setDoesNotAlias(n);<br>
-    ++NumAnnotated;<br>
-  }<br>
-}<br>
-<br>
 static bool setDoesNotRecurse(Function &F) {<br>
   if (F.doesNotRecurse())<br>
     return false;<br>
@@ -992,809 +949,6 @@ static bool setDoesNotRecurse(Function &<br>
   return true;<br>
 }<br>
<br>
-/// Analyze the name and prototype of the given function and set any applicable<br>
-/// attributes.<br>
-///<br>
-/// Returns true if any attributes were set and false otherwise.<br>
-static bool inferPrototypeAttributes(Function &F, const TargetLibraryInfo &TLI) {<br>
-  if (F.hasFnAttribute(Attribute::OptimizeNone))<br>
-    return false;<br>
-<br>
-  FunctionType *FTy = F.getFunctionType();<br>
-  LibFunc::Func TheLibFunc;<br>
-  if (!(TLI.getLibFunc(F.getName(), TheLibFunc) && TLI.has(TheLibFunc)))<br>
-    return false;<br>
-<br>
-  switch (TheLibFunc) {<br>
-  case LibFunc::strlen:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::strchr:<br>
-  case LibFunc::strrchr:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isIntegerTy())<br>
-      return false;<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotThrow(F);<br>
-    break;<br>
-  case LibFunc::strtol:<br>
-  case LibFunc::strtod:<br>
-  case LibFunc::strtof:<br>
-  case LibFunc::strtoul:<br>
-  case LibFunc::strtoll:<br>
-  case LibFunc::strtold:<br>
-  case LibFunc::strtoull:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::strcpy:<br>
-  case LibFunc::stpcpy:<br>
-  case LibFunc::strcat:<br>
-  case LibFunc::strncat:<br>
-  case LibFunc::strncpy:<br>
-  case LibFunc::stpncpy:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::strxfrm:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::strcmp: // 0,1<br>
-  case LibFunc::strspn:  // 0,1<br>
-  case LibFunc::strncmp: // 0,1<br>
-  case LibFunc::strcspn: // 0,1<br>
-  case LibFunc::strcoll: // 0,1<br>
-  case LibFunc::strcasecmp:  // 0,1<br>
-  case LibFunc::strncasecmp: //<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::strstr:<br>
-  case LibFunc::strpbrk:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::strtok:<br>
-  case LibFunc::strtok_r:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::scanf:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::setbuf:<br>
-  case LibFunc::setvbuf:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::strdup:<br>
-  case LibFunc::strndup:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::stat:<br>
-  case LibFunc::statvfs:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::sscanf:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::sprintf:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::snprintf:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(2)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 3);<br>
-    setOnlyReadsMemory(F, 3);<br>
-    break;<br>
-  case LibFunc::setitimer:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||<br>
-        !FTy->getParamType(2)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    setDoesNotCapture(F, 3);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::system:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "system" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::malloc:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    break;<br>
-  case LibFunc::memcmp:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::memchr:<br>
-  case LibFunc::memrchr:<br>
-    if (FTy->getNumParams() != 3)<br>
-      return false;<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotThrow(F);<br>
-    break;<br>
-  case LibFunc::modf:<br>
-  case LibFunc::modff:<br>
-  case LibFunc::modfl:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::memcpy:<br>
-  case LibFunc::memccpy:<br>
-  case LibFunc::memmove:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::memalign:<br>
-    if (!FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotAlias(F, 0);<br>
-    break;<br>
-  case LibFunc::mkdir:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::mktime:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::realloc:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::read:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "read" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::rewind:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::rmdir:<br>
-  case LibFunc::remove:<br>
-  case LibFunc::realpath:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::rename:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::readlink:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::write:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "write" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::bcopy:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::bcmp:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::bzero:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::calloc:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    break;<br>
-  case LibFunc::chmod:<br>
-  case LibFunc::chown:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::ctermid:<br>
-  case LibFunc::clearerr:<br>
-  case LibFunc::closedir:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::atoi:<br>
-  case LibFunc::atol:<br>
-  case LibFunc::atof:<br>
-  case LibFunc::atoll:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::access:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::fopen:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::fdopen:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::feof:<br>
-  case LibFunc::free:<br>
-  case LibFunc::fseek:<br>
-  case LibFunc::ftell:<br>
-  case LibFunc::fgetc:<br>
-  case LibFunc::fseeko:<br>
-  case LibFunc::ftello:<br>
-  case LibFunc::fileno:<br>
-  case LibFunc::fflush:<br>
-  case LibFunc::fclose:<br>
-  case LibFunc::fsetpos:<br>
-  case LibFunc::flockfile:<br>
-  case LibFunc::funlockfile:<br>
-  case LibFunc::ftrylockfile:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::ferror:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F);<br>
-    break;<br>
-  case LibFunc::fputc:<br>
-  case LibFunc::fstat:<br>
-  case LibFunc::frexp:<br>
-  case LibFunc::frexpf:<br>
-  case LibFunc::frexpl:<br>
-  case LibFunc::fstatvfs:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::fgets:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(2)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 3);<br>
-    break;<br>
-  case LibFunc::fread:<br>
-    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(3)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 4);<br>
-    break;<br>
-  case LibFunc::fwrite:<br>
-    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(3)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 4);<br>
-    break;<br>
-  case LibFunc::fputs:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::fscanf:<br>
-  case LibFunc::fprintf:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::fgetpos:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::getc:<br>
-  case LibFunc::getlogin_r:<br>
-  case LibFunc::getc_unlocked:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::getenv:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setOnlyReadsMemory(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::gets:<br>
-  case LibFunc::getchar:<br>
-    setDoesNotThrow(F);<br>
-    break;<br>
-  case LibFunc::getitimer:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::getpwnam:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::ungetc:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::uname:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::unlink:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::unsetenv:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::utime:<br>
-  case LibFunc::utimes:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::putc:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::puts:<br>
-  case LibFunc::printf:<br>
-  case LibFunc::perror:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::pread:<br>
-    if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "pread" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::pwrite:<br>
-    if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "pwrite" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::putchar:<br>
-    setDoesNotThrow(F);<br>
-    break;<br>
-  case LibFunc::popen:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::pclose:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::vscanf:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::vsscanf:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||<br>
-        !FTy->getParamType(2)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::vfscanf:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||<br>
-        !FTy->getParamType(2)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::valloc:<br>
-    if (!FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    break;<br>
-  case LibFunc::vprintf:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::vfprintf:<br>
-  case LibFunc::vsprintf:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::vsnprintf:<br>
-    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(2)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 3);<br>
-    setOnlyReadsMemory(F, 3);<br>
-    break;<br>
-  case LibFunc::open:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "open" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::opendir:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::tmpfile:<br>
-    if (!FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    break;<br>
-  case LibFunc::times:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::htonl:<br>
-  case LibFunc::htons:<br>
-  case LibFunc::ntohl:<br>
-  case LibFunc::ntohs:<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAccessMemory(F);<br>
-    break;<br>
-  case LibFunc::lstat:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::lchown:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::qsort:<br>
-    if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy())<br>
-      return false;<br>
-    // May throw; places call through function pointer.<br>
-    setDoesNotCapture(F, 4);<br>
-    break;<br>
-  case LibFunc::dunder_strdup:<br>
-  case LibFunc::dunder_strndup:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::dunder_strtok_r:<br>
-    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::under_IO_getc:<br>
-    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::under_IO_putc:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::dunder_isoc99_scanf:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::stat64:<br>
-  case LibFunc::lstat64:<br>
-  case LibFunc::statvfs64:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::dunder_isoc99_sscanf:<br>
-    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::fopen64:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
-        !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    setOnlyReadsMemory(F, 2);<br>
-    break;<br>
-  case LibFunc::fseeko64:<br>
-  case LibFunc::ftello64:<br>
-    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    break;<br>
-  case LibFunc::tmpfile64:<br>
-    if (!FTy->getReturnType()->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotAlias(F, 0);<br>
-    break;<br>
-  case LibFunc::fstat64:<br>
-  case LibFunc::fstatvfs64:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  case LibFunc::open64:<br>
-    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())<br>
-      return false;<br>
-    // May throw; "open" is a valid pthread cancellation point.<br>
-    setDoesNotCapture(F, 1);<br>
-    setOnlyReadsMemory(F, 1);<br>
-    break;<br>
-  case LibFunc::gettimeofday:<br>
-    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
-        !FTy->getParamType(1)->isPointerTy())<br>
-      return false;<br>
-    // Currently some platforms have the restrict keyword on the arguments to<br>
-    // gettimeofday. To be conservative, do not add noalias to gettimeofday's<br>
-    // arguments.<br>
-    setDoesNotThrow(F);<br>
-    setDoesNotCapture(F, 1);<br>
-    setDoesNotCapture(F, 2);<br>
-    break;<br>
-  default:<br>
-    // Didn't mark any attributes.<br>
-    return false;<br>
-  }<br>
-<br>
-  return true;<br>
-}<br>
-<br>
 static bool addNoRecurseAttrs(const CallGraphSCC &SCC,<br>
                               SmallVectorImpl<WeakVH> &Revisit) {<br>
   // Try and identify functions that do not recurse.<br>
@@ -1874,18 +1028,13 @@ bool FunctionAttrs::runOnSCC(CallGraphSC<br>
       continue;<br>
     }<br>
<br>
-    // When initially processing functions, also infer their prototype<br>
-    // attributes if they are declarations.<br>
-    if (F->isDeclaration())<br>
-      Changed |= inferPrototypeAttributes(*F, *TLI);<br>
-<br>
     SCCNodes.insert(F);<br>
   }<br>
<br>
   Changed |= addReadAttrs(SCCNodes, AARGetter);<br>
   Changed |= addArgumentAttrs(SCCNodes);<br>
<br>
-  // If we have no external nodes participating in the SCC, we can infer some<br>
+  // If we have no external nodes participating in the SCC, we can deduce some<br>
   // more precise attributes as well.<br>
   if (!ExternalNode) {<br>
     Changed |= addNoAliasAttrs(SCCNodes);<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/IPO.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/IPO.cpp?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/IPO.cpp?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/IPO.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/IPO.cpp Sun Dec 27 02:41:34 2015<br>
@@ -34,6 +34,7 @@ void llvm::initializeIPO(PassRegistry &R<br>
   initializeIPCPPass(Registry);<br>
   initializeAlwaysInlinerPass(Registry);<br>
   initializeSimpleInlinerPass(Registry);<br>
+  initializeInferFunctionAttrsLegacyPassPass(Registry);<br>
   initializeInternalizePassPass(Registry);<br>
   initializeLoopExtractorPass(Registry);<br>
   initializeBlockExtractorPassPass(Registry);<br>
<br>
Added: llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp?rev=256466&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp?rev=256466&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp (added)<br>
+++ llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp Sun Dec 27 02:41:34 2015<br>
@@ -0,0 +1,937 @@<br>
+//===- InferFunctionAttrs.cpp - Infer implicit function attributes --------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "llvm/Transforms/IPO/InferFunctionAttrs.h"<br>
+#include "llvm/ADT/Statistic.h"<br>
+#include "llvm/Analysis/TargetLibraryInfo.h"<br>
+#include "llvm/IR/Function.h"<br>
+#include "llvm/IR/LLVMContext.h"<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/Support/Debug.h"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+using namespace llvm;<br>
+<br>
+#define DEBUG_TYPE "inferattrs"<br>
+<br>
+STATISTIC(NumReadNone, "Number of functions inferred as readnone");<br>
+STATISTIC(NumReadOnly, "Number of functions inferred as readonly");<br>
+STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind");<br>
+STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture");<br>
+STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly");<br>
+STATISTIC(NumNoAlias, "Number of function returns inferred as noalias");<br>
+<br>
+static bool setDoesNotAccessMemory(Function &F) {<br>
+  if (F.doesNotAccessMemory())<br>
+    return false;<br>
+  F.setDoesNotAccessMemory();<br>
+  ++NumReadNone;<br>
+  return true;<br>
+}<br>
+<br>
+static bool setOnlyReadsMemory(Function &F) {<br>
+  if (F.onlyReadsMemory())<br>
+    return false;<br>
+  F.setOnlyReadsMemory();<br>
+  ++NumReadOnly;<br>
+  return true;<br>
+}<br>
+<br>
+static bool setDoesNotThrow(Function &F) {<br>
+  if (F.doesNotThrow())<br>
+    return false;<br>
+  F.setDoesNotThrow();<br>
+  ++NumNoUnwind;<br>
+  return true;<br>
+}<br>
+<br>
+static bool setDoesNotCapture(Function &F, unsigned n) {<br>
+  if (F.doesNotCapture(n))<br>
+    return false;<br>
+  F.setDoesNotCapture(n);<br>
+  ++NumNoCapture;<br>
+  return true;<br>
+}<br>
+<br>
+static bool setOnlyReadsMemory(Function &F, unsigned n) {<br>
+  if (F.onlyReadsMemory(n))<br>
+    return false;<br>
+  F.setOnlyReadsMemory(n);<br>
+  ++NumReadOnlyArg;<br>
+  return true;<br>
+}<br>
+<br>
+static bool setDoesNotAlias(Function &F, unsigned n) {<br>
+  if (F.doesNotAlias(n))<br>
+    return false;<br>
+  F.setDoesNotAlias(n);<br>
+  ++NumNoAlias;<br>
+  return true;<br>
+}<br>
+<br>
+/// Analyze the name and prototype of the given function and set any applicable<br>
+/// attributes.<br>
+///<br>
+/// Returns true if any attributes were set and false otherwise.<br>
+static bool inferPrototypeAttributes(Function &F,<br>
+                                     const TargetLibraryInfo &TLI) {<br>
+  if (F.hasFnAttribute(Attribute::OptimizeNone))<br>
+    return false;<br>
+<br>
+  FunctionType *FTy = F.getFunctionType();<br>
+  LibFunc::Func TheLibFunc;<br>
+  if (!(TLI.getLibFunc(F.getName(), TheLibFunc) && TLI.has(TheLibFunc)))<br>
+    return false;<br>
+<br>
+  bool Changed = false;<br>
+<br>
+  switch (TheLibFunc) {<br>
+  case LibFunc::strlen:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::strchr:<br>
+  case LibFunc::strrchr:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isIntegerTy())<br>
+      return false;<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotThrow(F);<br>
+    return Changed;<br>
+  case LibFunc::strtol:<br>
+  case LibFunc::strtod:<br>
+  case LibFunc::strtof:<br>
+  case LibFunc::strtoul:<br>
+  case LibFunc::strtoll:<br>
+  case LibFunc::strtold:<br>
+  case LibFunc::strtoull:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::strcpy:<br>
+  case LibFunc::stpcpy:<br>
+  case LibFunc::strcat:<br>
+  case LibFunc::strncat:<br>
+  case LibFunc::strncpy:<br>
+  case LibFunc::stpncpy:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::strxfrm:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::strcmp:      // 0,1<br>
+  case LibFunc::strspn:      // 0,1<br>
+  case LibFunc::strncmp:     // 0,1<br>
+  case LibFunc::strcspn:     // 0,1<br>
+  case LibFunc::strcoll:     // 0,1<br>
+  case LibFunc::strcasecmp:  // 0,1<br>
+  case LibFunc::strncasecmp: //<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::strstr:<br>
+  case LibFunc::strpbrk:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::strtok:<br>
+  case LibFunc::strtok_r:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::scanf:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::setbuf:<br>
+  case LibFunc::setvbuf:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::strdup:<br>
+  case LibFunc::strndup:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::stat:<br>
+  case LibFunc::statvfs:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::sscanf:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::sprintf:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::snprintf:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(2)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 3);<br>
+    Changed |= setOnlyReadsMemory(F, 3);<br>
+    return Changed;<br>
+  case LibFunc::setitimer:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||<br>
+        !FTy->getParamType(2)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setDoesNotCapture(F, 3);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::system:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "system" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::malloc:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    return Changed;<br>
+  case LibFunc::memcmp:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::memchr:<br>
+  case LibFunc::memrchr:<br>
+    if (FTy->getNumParams() != 3)<br>
+      return false;<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotThrow(F);<br>
+    return Changed;<br>
+  case LibFunc::modf:<br>
+  case LibFunc::modff:<br>
+  case LibFunc::modfl:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::memcpy:<br>
+  case LibFunc::memccpy:<br>
+  case LibFunc::memmove:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::memalign:<br>
+    if (!FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    return Changed;<br>
+  case LibFunc::mkdir:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::mktime:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::realloc:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::read:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "read" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::rewind:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::rmdir:<br>
+  case LibFunc::remove:<br>
+  case LibFunc::realpath:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::rename:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::readlink:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::write:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "write" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::bcopy:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::bcmp:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::bzero:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::calloc:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    return Changed;<br>
+  case LibFunc::chmod:<br>
+  case LibFunc::chown:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::ctermid:<br>
+  case LibFunc::clearerr:<br>
+  case LibFunc::closedir:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::atoi:<br>
+  case LibFunc::atol:<br>
+  case LibFunc::atof:<br>
+  case LibFunc::atoll:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::access:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::fopen:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::fdopen:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::feof:<br>
+  case LibFunc::free:<br>
+  case LibFunc::fseek:<br>
+  case LibFunc::ftell:<br>
+  case LibFunc::fgetc:<br>
+  case LibFunc::fseeko:<br>
+  case LibFunc::ftello:<br>
+  case LibFunc::fileno:<br>
+  case LibFunc::fflush:<br>
+  case LibFunc::fclose:<br>
+  case LibFunc::fsetpos:<br>
+  case LibFunc::flockfile:<br>
+  case LibFunc::funlockfile:<br>
+  case LibFunc::ftrylockfile:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::ferror:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    return Changed;<br>
+  case LibFunc::fputc:<br>
+  case LibFunc::fstat:<br>
+  case LibFunc::frexp:<br>
+  case LibFunc::frexpf:<br>
+  case LibFunc::frexpl:<br>
+  case LibFunc::fstatvfs:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::fgets:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(2)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 3);<br>
+    return Changed;<br>
+  case LibFunc::fread:<br>
+    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(3)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 4);<br>
+    return Changed;<br>
+  case LibFunc::fwrite:<br>
+    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(3)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 4);<br>
+    return Changed;<br>
+  case LibFunc::fputs:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::fscanf:<br>
+  case LibFunc::fprintf:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::fgetpos:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::getc:<br>
+  case LibFunc::getlogin_r:<br>
+  case LibFunc::getc_unlocked:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::getenv:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setOnlyReadsMemory(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::gets:<br>
+  case LibFunc::getchar:<br>
+    Changed |= setDoesNotThrow(F);<br>
+    return Changed;<br>
+  case LibFunc::getitimer:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::getpwnam:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::ungetc:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::uname:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::unlink:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::unsetenv:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::utime:<br>
+  case LibFunc::utimes:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::putc:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::puts:<br>
+  case LibFunc::printf:<br>
+  case LibFunc::perror:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::pread:<br>
+    if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "pread" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::pwrite:<br>
+    if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "pwrite" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::putchar:<br>
+    Changed |= setDoesNotThrow(F);<br>
+    return Changed;<br>
+  case LibFunc::popen:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::pclose:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::vscanf:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::vsscanf:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||<br>
+        !FTy->getParamType(2)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::vfscanf:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||<br>
+        !FTy->getParamType(2)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::valloc:<br>
+    if (!FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    return Changed;<br>
+  case LibFunc::vprintf:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::vfprintf:<br>
+  case LibFunc::vsprintf:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::vsnprintf:<br>
+    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(2)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 3);<br>
+    Changed |= setOnlyReadsMemory(F, 3);<br>
+    return Changed;<br>
+  case LibFunc::open:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "open" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::opendir:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::tmpfile:<br>
+    if (!FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    return Changed;<br>
+  case LibFunc::times:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::htonl:<br>
+  case LibFunc::htons:<br>
+  case LibFunc::ntohl:<br>
+  case LibFunc::ntohs:<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAccessMemory(F);<br>
+    return Changed;<br>
+  case LibFunc::lstat:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::lchown:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::qsort:<br>
+    if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy())<br>
+      return false;<br>
+    // May throw; places call through function pointer.<br>
+    Changed |= setDoesNotCapture(F, 4);<br>
+    return Changed;<br>
+  case LibFunc::dunder_strdup:<br>
+  case LibFunc::dunder_strndup:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::dunder_strtok_r:<br>
+    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::under_IO_getc:<br>
+    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::under_IO_putc:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::dunder_isoc99_scanf:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::stat64:<br>
+  case LibFunc::lstat64:<br>
+  case LibFunc::statvfs64:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::dunder_isoc99_sscanf:<br>
+    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::fopen64:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||<br>
+        !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::fseeko64:<br>
+  case LibFunc::ftello64:<br>
+    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::tmpfile64:<br>
+    if (!FTy->getReturnType()->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotAlias(F, 0);<br>
+    return Changed;<br>
+  case LibFunc::fstat64:<br>
+  case LibFunc::fstatvfs64:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+  case LibFunc::open64:<br>
+    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())<br>
+      return false;<br>
+    // May throw; "open" is a valid pthread cancellation point.<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setOnlyReadsMemory(F, 1);<br>
+    return Changed;<br>
+  case LibFunc::gettimeofday:<br>
+    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||<br>
+        !FTy->getParamType(1)->isPointerTy())<br>
+      return false;<br>
+    // Currently some platforms have the restrict keyword on the arguments to<br>
+    // gettimeofday. To be conservative, do not add noalias to gettimeofday's<br>
+    // arguments.<br>
+    Changed |= setDoesNotThrow(F);<br>
+    Changed |= setDoesNotCapture(F, 1);<br>
+    Changed |= setDoesNotCapture(F, 2);<br>
+    return Changed;<br>
+<br>
+  default:<br>
+    // FIXME: It'd be really nice to cover all the library functions we're<br>
+    // aware of here.<br>
+    return false;<br>
+  }<br>
+}<br>
+<br>
+static bool inferAllPrototypeAttributes(Module &M,<br>
+                                        const TargetLibraryInfo &TLI) {<br>
+  bool Changed = false;<br>
+<br>
+  for (Function &F : M.functions())<br>
+    // We only infer things using the prototype if the definition isn't around<br>
+    // to analyze directly.<br>
+    if (F.isDeclaration())<br>
+      Changed |= inferPrototypeAttributes(F, TLI);<br>
+<br>
+  return Changed;<br>
+}<br>
+<br>
+PreservedAnalyses InferFunctionAttrsPass::run(Module &M,<br>
+                                              AnalysisManager<Module> *AM) {<br>
+  auto &TLI = AM->getResult<TargetLibraryAnalysis>(M);<br>
+<br>
+  if (!inferAllPrototypeAttributes(M, TLI))<br>
+    // If we didn't infer anything, preserve all analyses.<br>
+    return PreservedAnalyses::all();<br>
+<br>
+  // Otherwise, we may have changed fundamental function attributes, so clear<br>
+  // out all the passes.<br>
+  return PreservedAnalyses::none();<br>
+}<br>
+<br>
+namespace {<br>
+struct InferFunctionAttrsLegacyPass : public ModulePass {<br>
+  static char ID; // Pass identification, replacement for typeid<br>
+  InferFunctionAttrsLegacyPass() : ModulePass(ID) {<br>
+    initializeInferFunctionAttrsLegacyPassPass(<br>
+        *PassRegistry::getPassRegistry());<br>
+  }<br>
+<br>
+  void getAnalysisUsage(AnalysisUsage &AU) const override {<br>
+    AU.addRequired<TargetLibraryInfoWrapperPass>();<br>
+  }<br>
+<br>
+  bool runOnModule(Module &M) override {<br>
+    auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();<br>
+    return inferAllPrototypeAttributes(M, TLI);<br>
+  }<br>
+};<br>
+}<br>
+<br>
+char InferFunctionAttrsLegacyPass::ID = 0;<br>
+INITIALIZE_PASS_BEGIN(InferFunctionAttrsLegacyPass, "inferattrs",<br>
+                      "Infer set function attributes", false, false)<br>
+INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)<br>
+INITIALIZE_PASS_END(InferFunctionAttrsLegacyPass, "inferattrs",<br>
+                    "Infer set function attributes", false, false)<br>
+<br>
+Pass *llvm::createInferFunctionAttrsLegacyPass() {<br>
+  return new InferFunctionAttrsLegacyPass();<br>
+}<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp Sun Dec 27 02:41:34 2015<br>
@@ -12,26 +12,26 @@<br>
 //<br>
 //===----------------------------------------------------------------------===//<br>
<br>
-<br>
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"<br>
 #include "llvm-c/Transforms/PassManagerBuilder.h"<br>
 #include "llvm/ADT/SmallVector.h"<br>
-#include "llvm/Analysis/Passes.h"<br>
-#include "llvm/IR/DataLayout.h"<br>
-#include "llvm/IR/FunctionInfo.h"<br>
-#include "llvm/IR/Verifier.h"<br>
-#include "llvm/IR/LegacyPassManager.h"<br>
-#include "llvm/Support/CommandLine.h"<br>
-#include "llvm/Support/ManagedStatic.h"<br>
 #include "llvm/Analysis/BasicAliasAnalysis.h"<br>
 #include "llvm/Analysis/CFLAliasAnalysis.h"<br>
 #include "llvm/Analysis/GlobalsModRef.h"<br>
+#include "llvm/Analysis/Passes.h"<br>
 #include "llvm/Analysis/ScopedNoAliasAA.h"<br>
 #include "llvm/Analysis/TargetLibraryInfo.h"<br>
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"<br>
+#include "llvm/IR/DataLayout.h"<br>
+#include "llvm/IR/FunctionInfo.h"<br>
+#include "llvm/IR/LegacyPassManager.h"<br>
+#include "llvm/IR/Verifier.h"<br>
+#include "llvm/Support/CommandLine.h"<br>
+#include "llvm/Support/ManagedStatic.h"<br>
 #include "llvm/Target/TargetMachine.h"<br>
 #include "llvm/Transforms/IPO.h"<br>
 #include "llvm/Transforms/IPO/ForceFunctionAttrs.h"<br>
+#include "llvm/Transforms/IPO/InferFunctionAttrs.h"<br>
 #include "llvm/Transforms/Scalar.h"<br>
 #include "llvm/Transforms/Vectorize.h"<br>
<br>
@@ -220,6 +220,9 @@ void PassManagerBuilder::populateModuleP<br>
   addInitialAliasAnalysisPasses(MPM);<br>
<br>
   if (!DisableUnitAtATime) {<br>
+    // Infer attributes about declarations if possible.<br>
+    MPM.add(createInferFunctionAttrsLegacyPass());<br>
+<br>
     addExtensionsToPM(EP_ModuleOptimizerEarly, MPM);<br>
<br>
     MPM.add(createIPSCCPPass());              // IP SCCP<br>
@@ -490,6 +493,9 @@ void PassManagerBuilder::addLTOOptimizat<br>
   // Allow forcing function attributes as a debugging and tuning aid.<br>
   PM.add(createForceFunctionAttrsLegacyPass());<br>
<br>
+  // Infer attributes about declarations if possible.<br>
+  PM.add(createInferFunctionAttrsLegacyPass());<br>
+<br>
   // Propagate constants at call sites into the functions they call.  This<br>
   // opens opportunities for globalopt (and inlining) by substituting function<br>
   // pointers passed as arguments to direct uses of functions.<br>
<br>
Removed: llvm/trunk/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll?rev=256465&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll?rev=256465&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll (original)<br>
+++ llvm/trunk/test/Transforms/FunctionAttrs/2009-01-04-Annotate.ll (removed)<br>
@@ -1,21 +0,0 @@<br>
-; RUN: opt < %s -functionattrs -S | FileCheck %s<br>
-<br>
-; CHECK: declare noalias i8* @fopen(i8* nocapture readonly, i8* nocapture readonly) #0<br>
-declare i8* @fopen(i8*, i8*)<br>
-<br>
-; CHECK: declare i8 @strlen(i8* nocapture) #1<br>
-declare i8 @strlen(i8*)<br>
-<br>
-; CHECK: declare noalias i32* @realloc(i32* nocapture, i32) #0<br>
-declare i32* @realloc(i32*, i32)<br>
-<br>
-; Test deliberately wrong declaration<br>
-declare i32 @strcpy(...)<br>
-<br>
-; CHECK-NOT: strcpy{{.*}}noalias<br>
-; CHECK-NOT: strcpy{{.*}}nocapture<br>
-; CHECK-NOT: strcpy{{.*}}nounwind<br>
-; CHECK-NOT: strcpy{{.*}}readonly<br>
-<br>
-; CHECK: attributes #0 = { nounwind }<br>
-; CHECK: attributes #1 = { nounwind readonly }<br>
<br>
Removed: llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll?rev=256465&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll?rev=256465&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll (original)<br>
+++ llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll (removed)<br>
@@ -1,23 +0,0 @@<br>
-; RUN: opt < %s -functionattrs -S | FileCheck %s<br>
-; RUN: opt < %s -mtriple=x86_64-apple-macosx10.8.0 -functionattrs -S | FileCheck -check-prefix=CHECK-POSIX %s<br>
-<br>
-declare i8* @fopen(i8*, i8*)<br>
-; CHECK: declare noalias i8* @fopen(i8* nocapture readonly, i8* nocapture readonly) [[G0:#[0-9]]]<br>
-<br>
-declare i8 @strlen(i8*)<br>
-; CHECK: declare i8 @strlen(i8* nocapture) [[G1:#[0-9]]]<br>
-<br>
-declare i32* @realloc(i32*, i32)<br>
-; CHECK: declare noalias i32* @realloc(i32* nocapture, i32) [[G0]]<br>
-<br>
-; Test deliberately wrong declaration<br>
-<br>
-declare i32 @strcpy(...)<br>
-; CHECK: declare i32 @strcpy(...)<br>
-<br>
-declare i32 @gettimeofday(i8*, i8*)<br>
-; CHECK-POSIX: declare i32 @gettimeofday(i8* nocapture, i8* nocapture) [[G0:#[0-9]+]]<br>
-<br>
-; CHECK: attributes [[G0]] = { nounwind }<br>
-; CHECK: attributes [[G1]] = { nounwind readonly }<br>
-; CHECK-POSIX: attributes [[G0]] = { nounwind }<br>
<br>
Copied: llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll (from r256465, llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll)<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll?p2=llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll&p1=llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll&r1=256465&r2=256466&rev=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll?p2=llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll&p1=llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll&r1=256465&r2=256466&rev=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/FunctionAttrs/annotate-1.ll (original)<br>
+++ llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll Sun Dec 27 02:41:34 2015<br>
@@ -1,5 +1,6 @@<br>
-; RUN: opt < %s -functionattrs -S | FileCheck %s<br>
-; RUN: opt < %s -mtriple=x86_64-apple-macosx10.8.0 -functionattrs -S | FileCheck -check-prefix=CHECK-POSIX %s<br>
+; RUN: opt < %s -inferattrs -S | FileCheck %s<br>
+; RUN: opt < %s -passes=inferattrs -S | FileCheck %s<br>
+; RUN: opt < %s -mtriple=x86_64-apple-macosx10.8.0 -inferattrs -S | FileCheck -check-prefix=CHECK-POSIX %s<br>
<br>
 declare i8* @fopen(i8*, i8*)<br>
 ; CHECK: declare noalias i8* @fopen(i8* nocapture readonly, i8* nocapture readonly) [[G0:#[0-9]]]<br>
<br>
Modified: llvm/trunk/test/Transforms/InstCombine/strto-1.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strto-1.ll?rev=256466&r1=256465&r2=256466&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strto-1.ll?rev=256466&r1=256465&r2=256466&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/InstCombine/strto-1.ll (original)<br>
+++ llvm/trunk/test/Transforms/InstCombine/strto-1.ll Sun Dec 27 02:41:34 2015<br>
@@ -1,6 +1,6 @@<br>
 ; Test that the strto* library call simplifiers works correctly.<br>
 ;<br>
-; RUN: opt < %s -instcombine -functionattrs -S | FileCheck %s<br>
+; RUN: opt < %s -instcombine -inferattrs -S | FileCheck %s<br>
<br>
 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"<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>