diff options
| -rw-r--r-- | llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp | 443 | ||||
| -rw-r--r-- | llvm/test/Transforms/SimplifyLibCalls/2009-01-04-Annotate.ll | 12 | 
2 files changed, 455 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 87232084051..829d1344b11 100644 --- a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -34,6 +34,7 @@  using namespace llvm;  STATISTIC(NumSimplified, "Number of library calls simplified"); +STATISTIC(NumAnnotated, "Number of attributes added to library functions");  //===----------------------------------------------------------------------===//  // Optimizer Base Class @@ -1288,6 +1289,8 @@ namespace {      // Formatting and IO Optimizations      SPrintFOpt SPrintF; PrintFOpt PrintF;      FWriteOpt FWrite; FPutsOpt FPuts; FPrintFOpt FPrintF; + +    bool Modified;  // This is only used by doFinalization.    public:      static char ID; // Pass identification      SimplifyLibCalls() : FunctionPass(&ID) {} @@ -1295,6 +1298,13 @@ namespace {      void InitOptimizations();      bool runOnFunction(Function &F); +    void setDoesNotAccessMemory(Function &F); +    void setOnlyReadsMemory(Function &F); +    void setDoesNotThrow(Function &F); +    void setDoesNotCapture(Function &F, unsigned n); +    void setDoesNotAlias(Function &F, unsigned n); +    bool doFinalization(Module &M); +      virtual void getAnalysisUsage(AnalysisUsage &AU) const {        AU.addRequired<TargetData>();      } @@ -1440,6 +1450,439 @@ bool SimplifyLibCalls::runOnFunction(Function &F) {    return Changed;  } +// Utility methods for doFinalization. + +void SimplifyLibCalls::setDoesNotAccessMemory(Function &F) { +  if (!F.doesNotAccessMemory()) { +    F.setDoesNotAccessMemory(); +    ++NumAnnotated; +    Modified = true; +  } +} +void SimplifyLibCalls::setOnlyReadsMemory(Function &F) { +  if (!F.onlyReadsMemory()) { +    F.setOnlyReadsMemory(); +    ++NumAnnotated; +    Modified = true; +  } +} +void SimplifyLibCalls::setDoesNotThrow(Function &F) { +  if (!F.doesNotThrow()) { +    F.setDoesNotThrow(); +    ++NumAnnotated; +    Modified = true; +  } +} +void SimplifyLibCalls::setDoesNotCapture(Function &F, unsigned n) { +  if (!F.doesNotCapture(n)) { +    F.setDoesNotCapture(n); +    ++NumAnnotated; +    Modified = true; +  } +} +void SimplifyLibCalls::setDoesNotAlias(Function &F, unsigned n) { +  if (!F.doesNotAlias(n)) { +    F.setDoesNotAlias(n); +    ++NumAnnotated; +    Modified = true; +  } +} + +/// doFinalization - Add attributes to well-known functions. +/// +bool SimplifyLibCalls::doFinalization(Module &M) { +  Modified = false; +  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { +    Function &F = *I; +    if (!F.isDeclaration()) +      continue; + +    unsigned NameLen = F.getNameLen(); +    if (!NameLen) +      continue; + +    const FunctionType *FTy = F.getFunctionType(); + +    const char *NameStr = F.getNameStart(); +    switch (NameStr[0]) { +      case 's': +        if (NameLen == 6 && !strcmp(NameStr, "strlen")) { +          if (FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setOnlyReadsMemory(F); +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } else if ((NameLen == 6 && !strcmp(NameStr, "strcpy")) || +                   (NameLen == 6 && !strcmp(NameStr, "stpcpy")) || +                   (NameLen == 6 && !strcmp(NameStr, "strcat")) || +                   (NameLen == 7 && !strcmp(NameStr, "strncat")) || +                   (NameLen == 7 && !strcmp(NameStr, "strncpy"))) { +          if (FTy->getNumParams() < 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if (NameLen == 7 && !strcmp(NameStr, "strxfrm")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 6 && !strcmp(NameStr, "strcmp")) || +                   (NameLen == 6 && !strcmp(NameStr, "strspn")) || +                   (NameLen == 6 && !strcmp(NameStr, "strtol")) || +                   (NameLen == 6 && !strcmp(NameStr, "strtod")) || +                   (NameLen == 6 && !strcmp(NameStr, "strtof")) || +                   (NameLen == 7 && !strcmp(NameStr, "strtoul")) || +                   (NameLen == 7 && !strcmp(NameStr, "strtoll")) || +                   (NameLen == 7 && !strcmp(NameStr, "strtold")) || +                   (NameLen == 7 && !strcmp(NameStr, "strncmp")) || +                   (NameLen == 7 && !strcmp(NameStr, "strcspn")) || +                   (NameLen == 7 && !strcmp(NameStr, "strcoll")) || +                   (NameLen == 8 && !strcmp(NameStr, "strtoull")) || +                   (NameLen == 10 && !strcmp(NameStr, "strcasecmp")) || +                   (NameLen == 11 && !strcmp(NameStr, "strncasecmp"))) { +          if (FTy->getNumParams() < 2 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setOnlyReadsMemory(F); +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 6 && !strcmp(NameStr, "strstr")) || +                   (NameLen == 7 && !strcmp(NameStr, "strpbrk"))) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setOnlyReadsMemory(F); +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 6 && !strcmp(NameStr, "strtok")) || +                   (NameLen == 7 && !strcmp(NameStr, "strtok_r"))) { +          if (FTy->getNumParams() < 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 5 && !strcmp(NameStr, "scanf")) || +                   (NameLen == 6 && !strcmp(NameStr, "setbuf")) || +                   (NameLen == 7 && !strcmp(NameStr, "setvbuf"))) { +          if (FTy->getNumParams() < 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } else if (NameLen == 6 && !strcmp(NameStr, "sscanf")) { +          if (FTy->getNumParams() < 2 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } +        break; +      case 'm': +        if (NameLen == 6 && !strcmp(NameStr, "memcmp")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setOnlyReadsMemory(F); +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 6 && !strcmp(NameStr, "memchr")) || +                   (NameLen == 7 && !strcmp(NameStr, "memrchr"))) { +          if (FTy->getNumParams() != 3) +            continue; +          setOnlyReadsMemory(F); +          setDoesNotThrow(F); +        } else if ((NameLen == 6 && !strcmp(NameStr, "memcpy")) || +                   (NameLen == 7 && !strcmp(NameStr, "memccpy")) || +                   (NameLen == 7 && !strcmp(NameStr, "memmove"))) { +          if (FTy->getNumParams() < 3 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } +        break; +      case 'r': +        if (NameLen == 7 && !strcmp(NameStr, "realloc")) { +          if (FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getReturnType())) +            continue; +          setDoesNotThrow(F); +          setDoesNotAlias(F, 0); +          setDoesNotCapture(F, 1); +        } else if (NameLen == 4 && !strcmp(NameStr, "read")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 5 && !strcmp(NameStr, "rmdir")) || +                   (NameLen == 6 && !strcmp(NameStr, "rewind")) || +                   (NameLen == 6 && !strcmp(NameStr, "remove"))) { +          if (FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } else if (NameLen == 6 && !strcmp(NameStr, "rename")) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } +        break; +      case 'w': +        if (NameLen == 5 && !strcmp(NameStr, "write")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } +        break; +      case 'b': +        if (NameLen == 5 && !strcmp(NameStr, "bcopy")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } else if (NameLen == 4 && !strcmp(NameStr, "bcmp")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setOnlyReadsMemory(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } else if (NameLen == 5 && !strcmp(NameStr, "bzero")) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } +        break; +      case 'c': +        if (NameLen == 6 && !strcmp(NameStr, "calloc")) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getReturnType())) +            continue; +          setDoesNotThrow(F); +          setDoesNotAlias(F, 0); +        } else if ((NameLen == 5 && !strcmp(NameStr, "chown")) || +                   (NameLen == 8 && !strcmp(NameStr, "clearerr")) || +                   (NameLen == 8 && !strcmp(NameStr, "closedir"))) { +          if (FTy->getNumParams() == 0 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } +        break; +      case 'a': +        if ((NameLen == 4 && !strcmp(NameStr, "atoi")) || +            (NameLen == 4 && !strcmp(NameStr, "atol")) || +            (NameLen == 4 && !strcmp(NameStr, "atof")) || +            (NameLen == 5 && !strcmp(NameStr, "atoll"))) { +          if (FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setOnlyReadsMemory(F); +          setDoesNotCapture(F, 1); +        } else if (NameLen == 6 && !strcmp(NameStr, "access")) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } +        break; +      case 'f': +        if ((NameLen == 5 && !strcmp(NameStr, "fopen")) || +            (NameLen == 6 && !strcmp(NameStr, "fdopen"))) { +          if (!isa<PointerType>(FTy->getReturnType())) +            continue; +          setDoesNotThrow(F); +          setDoesNotAlias(F, 0); +        } else if ((NameLen == 4 && !strcmp(NameStr, "feof")) || +                   (NameLen == 4 && !strcmp(NameStr, "free")) || +                   (NameLen == 5 && !strcmp(NameStr, "fseek")) || +                   (NameLen == 5 && !strcmp(NameStr, "ftell")) || +                   (NameLen == 5 && !strcmp(NameStr, "fgetc")) || +                   (NameLen == 6 && !strcmp(NameStr, "fseeko")) || +                   (NameLen == 6 && !strcmp(NameStr, "ftello")) || +                   (NameLen == 6 && !strcmp(NameStr, "ferror")) || +                   (NameLen == 6 && !strcmp(NameStr, "fileno")) || +                   (NameLen == 6 && !strcmp(NameStr, "fflush")) || +                   (NameLen == 6 && !strcmp(NameStr, "fclose"))) { +          if (FTy->getNumParams() == 0 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } else if ((NameLen == 5 && !strcmp(NameStr, "fputc")) || +                   (NameLen == 5 && !strcmp(NameStr, "fputs"))) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if (NameLen == 5 && !strcmp(NameStr, "fgets")) { +          if (FTy->getNumParams() != 3 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(2))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 3); +        } else if ((NameLen == 5 && !strcmp(NameStr, "fread")) || +                   (NameLen == 6 && !strcmp(NameStr, "fwrite"))) { +          if (FTy->getNumParams() != 4 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(3))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 4); +        } else if ((NameLen == 7 && !strcmp(NameStr, "fgetpos")) || +                   (NameLen == 7 && !strcmp(NameStr, "fsetpos"))) { +          if (FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } else if (NameLen == 6 && !strcmp(NameStr, "fscanf")) { +          if (FTy->getNumParams() < 2 || +              !isa<PointerType>(FTy->getParamType(0)) || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } +        break; +      case 'g': +        if ((NameLen == 4 && !strcmp(NameStr, "getc")) || +            (NameLen == 10 && !strcmp(NameStr, "getlogin_r"))) { +          if (FTy->getNumParams() == 0 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } else if (NameLen == 6 && !strcmp(NameStr, "getenv")) { +          if (!FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setOnlyReadsMemory(F); +          setDoesNotCapture(F, 0); +        } +        break; +      case 'u': +        if (NameLen == 4 && !strcmp(NameStr, "ungetc")) { +          if (!FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if (NameLen == 6 && !strcmp(NameStr, "unlink")) { +          if (!FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } +        break; +      case 'p': +        if (NameLen == 4 && !strcmp(NameStr, "putc")) { +          if (!FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 2); +        } else if ((NameLen == 4 && !strcmp(NameStr, "puts")) || +                   (NameLen == 6 && !strcmp(NameStr, "perror"))) { +          if (!FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(0))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } +        break; +      case 'v': +        if (NameLen == 6 && !strcmp(NameStr, "vscanf")) { +          if (!FTy->getNumParams() != 2 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +        } else if ((NameLen == 7 && !strcmp(NameStr, "vsscanf")) || +                   (NameLen == 7 && !strcmp(NameStr, "vfscanf"))) { +          if (!FTy->getNumParams() != 4 || +              !isa<PointerType>(FTy->getParamType(1)) || +              !isa<PointerType>(FTy->getParamType(2))) +            continue; +          setDoesNotThrow(F); +          setDoesNotCapture(F, 1); +          setDoesNotCapture(F, 2); +        } +        break; +      case 'o': +        if (NameLen == 7 && !strcmp(NameStr, "opendir")) { +          // The description of fdopendir sounds like opening the same fd +          // twice might result in the same DIR* ! +          if (FTy->getNumParams() != 1 || +              !isa<PointerType>(FTy->getParamType(1))) +            continue; +          setDoesNotThrow(F); +          setDoesNotAlias(F, 0); +        } +        break; +      case 't': +        if (NameLen == 7 && !strcmp(NameStr, "tmpfile")) { +          if (!isa<PointerType>(FTy->getReturnType())) +            continue; +          setDoesNotThrow(F); +          setDoesNotAlias(F, 0); +        } +      case 'h': +        if ((NameLen == 5 && !strcmp(NameStr, "htonl")) || +            (NameLen == 5 && !strcmp(NameStr, "htons"))) { +          setDoesNotThrow(F); +          setDoesNotAccessMemory(F); +        } +        break; +      case 'n': +        if ((NameLen == 5 && !strcmp(NameStr, "ntohl")) || +            (NameLen == 5 && !strcmp(NameStr, "ntohs"))) { +          setDoesNotThrow(F); +          setDoesNotAccessMemory(F); +        } +        break; +    } +  } +  return Modified; +}  // TODO:  //   Additional cases that we need to add to this file: diff --git a/llvm/test/Transforms/SimplifyLibCalls/2009-01-04-Annotate.ll b/llvm/test/Transforms/SimplifyLibCalls/2009-01-04-Annotate.ll new file mode 100644 index 00000000000..ac2c89dd7f7 --- /dev/null +++ b/llvm/test/Transforms/SimplifyLibCalls/2009-01-04-Annotate.ll @@ -0,0 +1,12 @@ +; RUN: llvm-as < %s | opt -simplify-libcalls | llvm-dis > %t +; RUN: grep noalias %t | count 2 +; RUN: grep nocapture %t | count 2 +; RUN: grep nounwind %t | count 3 +; RUN: grep readonly %t | count 1 + +declare i8* @fopen(i8*, i8*) +declare i8 @strlen(i8*) +declare i32* @realloc(i32*) + +; Test deliberately wrong declaration +declare i32 @strcpy(...)  | 

