static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI,
                         const MachineRegisterInfo &MRI,
                         MachineDominatorTree &MDT, LiveIntervals &LIS,
                         const WebAssemblyTargetLowering &TLI,
                         const TargetLibraryInfo &LibInfo) {
  MachineOperand &Op1 = MI.getOperand(1);
  if (!Op1.isSymbol())
    return false;

  StringRef Name(Op1.getSymbolName());
  bool callReturnsInput = Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
                          Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
                          Name == TLI.getLibcallName(RTLIB::MEMSET);
  if (!callReturnsInput)
    return false;

  LibFunc Func;
  if (!LibInfo.getLibFunc(Name, Func))
    return false;

  unsigned FromReg = MI.getOperand(2).getReg();
  unsigned ToReg = MI.getOperand(0).getReg();
  if (MRI.getRegClass(FromReg) != MRI.getRegClass(ToReg))
    report_fatal_error("Store results: call to builtin function with wrong "
                       "signature, from/to mismatch");
  return ReplaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
}
bool PartiallyInlineLibCalls::runOnFunction(Function &F) {
  bool Changed = false;
  Function::iterator CurrBB;
  TargetLibraryInfo *TLI = &getAnalysis<TargetLibraryInfo>();
  const TargetTransformInfo *TTI = &getAnalysis<TargetTransformInfo>();
  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) {
    CurrBB = BB++;

    for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end();
         II != IE; ++II) {
      CallInst *Call = dyn_cast<CallInst>(&*II);
      Function *CalledFunc;

      if (!Call || !(CalledFunc = Call->getCalledFunction()))
        continue;

      // Skip if function either has local linkage or is not a known library
      // function.
      LibFunc::Func LibFunc;
      if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() ||
          !TLI->getLibFunc(CalledFunc->getName(), LibFunc))
        continue;

      switch (LibFunc) {
      case LibFunc::sqrtf:
      case LibFunc::sqrt:
        if (TTI->haveFastSqrt(Call->getType()) &&
            optimizeSQRT(Call, CalledFunc, *CurrBB, BB))
          break;
        continue;
      default:
        continue;
      }

      Changed = true;
      break;
    }
  }

  return Changed;
}
Exemple #3
0
bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
  LibFunc TheLibFunc;
  if (!(TLI.getLibFunc(F, TheLibFunc) && TLI.has(TheLibFunc)))
    return false;

  bool Changed = false;
  switch (TheLibFunc) {
  case LibFunc_strlen:
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_strchr:
  case LibFunc_strrchr:
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc_strtol:
  case LibFunc_strtod:
  case LibFunc_strtof:
  case LibFunc_strtoul:
  case LibFunc_strtoll:
  case LibFunc_strtold:
  case LibFunc_strtoull:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_strcpy:
  case LibFunc_stpcpy:
  case LibFunc_strcat:
  case LibFunc_strncat:
  case LibFunc_strncpy:
  case LibFunc_stpncpy:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_strxfrm:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_strcmp:      // 0,1
  case LibFunc_strspn:      // 0,1
  case LibFunc_strncmp:     // 0,1
  case LibFunc_strcspn:     // 0,1
  case LibFunc_strcoll:     // 0,1
  case LibFunc_strcasecmp:  // 0,1
  case LibFunc_strncasecmp: //
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_strstr:
  case LibFunc_strpbrk:
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_strtok:
  case LibFunc_strtok_r:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_scanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_setbuf:
  case LibFunc_setvbuf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_strdup:
  case LibFunc_strndup:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_stat:
  case LibFunc_statvfs:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_sscanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_sprintf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_snprintf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 3);
    Changed |= setOnlyReadsMemory(F, 3);
    return Changed;
  case LibFunc_setitimer:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setDoesNotCapture(F, 3);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_system:
    // May throw; "system" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_malloc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc_memcmp:
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_memchr:
  case LibFunc_memrchr:
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc_modf:
  case LibFunc_modff:
  case LibFunc_modfl:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_memcpy:
  case LibFunc_mempcpy:
  case LibFunc_memccpy:
  case LibFunc_memmove:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_memcpy_chk:
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc_memalign:
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc_mkdir:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_mktime:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_realloc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_read:
    // May throw; "read" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_rewind:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_rmdir:
  case LibFunc_remove:
  case LibFunc_realpath:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_rename:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_readlink:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_write:
    // May throw; "write" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_bcopy:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_bcmp:
    Changed |= setDoesNotThrow(F);
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_bzero:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_calloc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc_chmod:
  case LibFunc_chown:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_ctermid:
  case LibFunc_clearerr:
  case LibFunc_closedir:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_atoi:
  case LibFunc_atol:
  case LibFunc_atof:
  case LibFunc_atoll:
    Changed |= setDoesNotThrow(F);
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_access:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_fopen:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_fdopen:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_feof:
  case LibFunc_free:
  case LibFunc_fseek:
  case LibFunc_ftell:
  case LibFunc_fgetc:
  case LibFunc_fseeko:
  case LibFunc_ftello:
  case LibFunc_fileno:
  case LibFunc_fflush:
  case LibFunc_fclose:
  case LibFunc_fsetpos:
  case LibFunc_flockfile:
  case LibFunc_funlockfile:
  case LibFunc_ftrylockfile:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_ferror:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F);
    return Changed;
  case LibFunc_fputc:
  case LibFunc_fstat:
  case LibFunc_frexp:
  case LibFunc_frexpf:
  case LibFunc_frexpl:
  case LibFunc_fstatvfs:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_fgets:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 3);
    return Changed;
  case LibFunc_fread:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 4);
    return Changed;
  case LibFunc_fwrite:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 4);
    // FIXME: readonly #1?
    return Changed;
  case LibFunc_fputs:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_fscanf:
  case LibFunc_fprintf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_fgetpos:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_getc:
  case LibFunc_getlogin_r:
  case LibFunc_getc_unlocked:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_getenv:
    Changed |= setDoesNotThrow(F);
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_gets:
  case LibFunc_getchar:
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc_getitimer:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_getpwnam:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_ungetc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_uname:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_unlink:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_unsetenv:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_utime:
  case LibFunc_utimes:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_putc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_puts:
  case LibFunc_printf:
  case LibFunc_perror:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_pread:
    // May throw; "pread" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_pwrite:
    // May throw; "pwrite" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_putchar:
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc_popen:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_pclose:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_vscanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_vsscanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_vfscanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_valloc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc_vprintf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_vfprintf:
  case LibFunc_vsprintf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_vsnprintf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 3);
    Changed |= setOnlyReadsMemory(F, 3);
    return Changed;
  case LibFunc_open:
    // May throw; "open" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_opendir:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_tmpfile:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc_times:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_htonl:
  case LibFunc_htons:
  case LibFunc_ntohl:
  case LibFunc_ntohs:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAccessMemory(F);
    return Changed;
  case LibFunc_lstat:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_lchown:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_qsort:
    // May throw; places call through function pointer.
    Changed |= setDoesNotCapture(F, 4);
    return Changed;
  case LibFunc_dunder_strdup:
  case LibFunc_dunder_strndup:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_dunder_strtok_r:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_under_IO_getc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_under_IO_putc:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_dunder_isoc99_scanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_stat64:
  case LibFunc_lstat64:
  case LibFunc_statvfs64:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_dunder_isoc99_sscanf:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_fopen64:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc_fseeko64:
  case LibFunc_ftello64:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc_tmpfile64:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc_fstat64:
  case LibFunc_fstatvfs64:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_open64:
    // May throw; "open" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc_gettimeofday:
    // Currently some platforms have the restrict keyword on the arguments to
    // gettimeofday. To be conservative, do not add noalias to gettimeofday's
    // arguments.
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc_Znwj: // new(unsigned int)
  case LibFunc_Znwm: // new(unsigned long)
  case LibFunc_Znaj: // new[](unsigned int)
  case LibFunc_Znam: // new[](unsigned long)
  case LibFunc_msvc_new_int: // new(unsigned int)
  case LibFunc_msvc_new_longlong: // new(unsigned long long)
  case LibFunc_msvc_new_array_int: // new[](unsigned int)
  case LibFunc_msvc_new_array_longlong: // new[](unsigned long long)
    // Operator new always returns a nonnull noalias pointer
    Changed |= setNonNull(F, AttributeSet::ReturnIndex);
    Changed |= setDoesNotAlias(F, AttributeSet::ReturnIndex);
    return Changed;
  //TODO: add LibFunc entries for:
  //case LibFunc_memset_pattern4:
  //case LibFunc_memset_pattern8:
  case LibFunc_memset_pattern16:
    Changed |= setOnlyAccessesArgMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  // int __nvvm_reflect(const char *)
  case LibFunc_nvvm_reflect:
    Changed |= setDoesNotAccessMemory(F);
    Changed |= setDoesNotThrow(F);
    return Changed;

  default:
    // FIXME: It'd be really nice to cover all the library functions we're
    // aware of here.
    return false;
  }
}
Exemple #4
0
MemoryLocation MemoryLocation::getForArgument(ImmutableCallSite CS,
                                              unsigned ArgIdx,
                                              const TargetLibraryInfo &TLI) {
  AAMDNodes AATags;
  CS->getAAMetadata(AATags);
  const Value *Arg = CS.getArgument(ArgIdx);

  // We may be able to produce an exact size for known intrinsics.
  if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction())) {
    const DataLayout &DL = II->getModule()->getDataLayout();

    switch (II->getIntrinsicID()) {
    default:
      break;
    case Intrinsic::memset:
    case Intrinsic::memcpy:
    case Intrinsic::memmove:
      assert((ArgIdx == 0 || ArgIdx == 1) &&
             "Invalid argument index for memory intrinsic");
      if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getArgOperand(2)))
        return MemoryLocation(Arg, LenCI->getZExtValue(), AATags);
      break;

    case Intrinsic::lifetime_start:
    case Intrinsic::lifetime_end:
    case Intrinsic::invariant_start:
      assert(ArgIdx == 1 && "Invalid argument index");
      return MemoryLocation(
          Arg, cast<ConstantInt>(II->getArgOperand(0))->getZExtValue(), AATags);

    case Intrinsic::invariant_end:
      // The first argument to an invariant.end is a "descriptor" type (e.g. a
      // pointer to a empty struct) which is never actually dereferenced.
      if (ArgIdx == 0)
        return MemoryLocation(Arg, 0, AATags);
      assert(ArgIdx == 2 && "Invalid argument index");
      return MemoryLocation(
          Arg, cast<ConstantInt>(II->getArgOperand(1))->getZExtValue(), AATags);

    case Intrinsic::arm_neon_vld1:
      assert(ArgIdx == 0 && "Invalid argument index");
      // LLVM's vld1 and vst1 intrinsics currently only support a single
      // vector register.
      return MemoryLocation(Arg, DL.getTypeStoreSize(II->getType()), AATags);

    case Intrinsic::arm_neon_vst1:
      assert(ArgIdx == 0 && "Invalid argument index");
      return MemoryLocation(
          Arg, DL.getTypeStoreSize(II->getArgOperand(1)->getType()), AATags);
    }
  }

  // We can bound the aliasing properties of memset_pattern16 just as we can
  // for memcpy/memset.  This is particularly important because the
  // LoopIdiomRecognizer likes to turn loops into calls to memset_pattern16
  // whenever possible.
  LibFunc F;
  if (CS.getCalledFunction() && TLI.getLibFunc(*CS.getCalledFunction(), F) &&
      F == LibFunc_memset_pattern16 && TLI.has(F)) {
    assert((ArgIdx == 0 || ArgIdx == 1) &&
           "Invalid argument index for memset_pattern16");
    if (ArgIdx == 1)
      return MemoryLocation(Arg, 16, AATags);
    if (const ConstantInt *LenCI = dyn_cast<ConstantInt>(CS.getArgument(2)))
      return MemoryLocation(Arg, LenCI->getZExtValue(), AATags);
  }
  // FIXME: Handle memset_pattern4 and memset_pattern8 also.

  return MemoryLocation(CS.getArgument(ArgIdx), UnknownSize, AATags);
}
Exemple #5
0
/// Analyze the name and prototype of the given function and set any applicable
/// attributes.
///
/// Returns true if any attributes were set and false otherwise.
static bool inferPrototypeAttributes(Function &F,
                                     const TargetLibraryInfo &TLI) {
  if (F.hasFnAttribute(Attribute::OptimizeNone))
    return false;

  FunctionType *FTy = F.getFunctionType();
  LibFunc::Func TheLibFunc;
  if (!(TLI.getLibFunc(F.getName(), TheLibFunc) && TLI.has(TheLibFunc)))
    return false;

  bool Changed = false;
  switch (TheLibFunc) {
  case LibFunc::strlen:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::strchr:
  case LibFunc::strrchr:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isIntegerTy())
      return false;
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc::strtol:
  case LibFunc::strtod:
  case LibFunc::strtof:
  case LibFunc::strtoul:
  case LibFunc::strtoll:
  case LibFunc::strtold:
  case LibFunc::strtoull:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::strcpy:
  case LibFunc::stpcpy:
  case LibFunc::strcat:
  case LibFunc::strncat:
  case LibFunc::strncpy:
  case LibFunc::stpncpy:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::strxfrm:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::strcmp:      // 0,1
  case LibFunc::strspn:      // 0,1
  case LibFunc::strncmp:     // 0,1
  case LibFunc::strcspn:     // 0,1
  case LibFunc::strcoll:     // 0,1
  case LibFunc::strcasecmp:  // 0,1
  case LibFunc::strncasecmp: //
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::strstr:
  case LibFunc::strpbrk:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::strtok:
  case LibFunc::strtok_r:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::scanf:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::setbuf:
  case LibFunc::setvbuf:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::strdup:
  case LibFunc::strndup:
    if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::stat:
  case LibFunc::statvfs:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::sscanf:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::sprintf:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::snprintf:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(2)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 3);
    Changed |= setOnlyReadsMemory(F, 3);
    return Changed;
  case LibFunc::setitimer:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||
        !FTy->getParamType(2)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setDoesNotCapture(F, 3);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::system:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    // May throw; "system" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::malloc:
    if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc::memcmp:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::memchr:
  case LibFunc::memrchr:
    if (FTy->getNumParams() != 3)
      return false;
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc::modf:
  case LibFunc::modff:
  case LibFunc::modfl:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::memcpy:
  case LibFunc::memccpy:
  case LibFunc::memmove:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::memalign:
    if (!FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc::mkdir:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::mktime:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::realloc:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::read:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())
      return false;
    // May throw; "read" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::rewind:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::rmdir:
  case LibFunc::remove:
  case LibFunc::realpath:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::rename:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::readlink:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::write:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())
      return false;
    // May throw; "write" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::bcopy:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::bcmp:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::bzero:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::calloc:
    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc::chmod:
  case LibFunc::chown:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::ctermid:
  case LibFunc::clearerr:
  case LibFunc::closedir:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::atoi:
  case LibFunc::atol:
  case LibFunc::atof:
  case LibFunc::atoll:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::access:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::fopen:
    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::fdopen:
    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::feof:
  case LibFunc::free:
  case LibFunc::fseek:
  case LibFunc::ftell:
  case LibFunc::fgetc:
  case LibFunc::fseeko:
  case LibFunc::ftello:
  case LibFunc::fileno:
  case LibFunc::fflush:
  case LibFunc::fclose:
  case LibFunc::fsetpos:
  case LibFunc::flockfile:
  case LibFunc::funlockfile:
  case LibFunc::ftrylockfile:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::ferror:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F);
    return Changed;
  case LibFunc::fputc:
  case LibFunc::fstat:
  case LibFunc::frexp:
  case LibFunc::frexpf:
  case LibFunc::frexpl:
  case LibFunc::fstatvfs:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::fgets:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(2)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 3);
    return Changed;
  case LibFunc::fread:
    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(3)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 4);
    return Changed;
  case LibFunc::fwrite:
    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(3)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 4);
    return Changed;
  case LibFunc::fputs:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::fscanf:
  case LibFunc::fprintf:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::fgetpos:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::getc:
  case LibFunc::getlogin_r:
  case LibFunc::getc_unlocked:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::getenv:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setOnlyReadsMemory(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::gets:
  case LibFunc::getchar:
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc::getitimer:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::getpwnam:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::ungetc:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::uname:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::unlink:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::unsetenv:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::utime:
  case LibFunc::utimes:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::putc:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::puts:
  case LibFunc::printf:
  case LibFunc::perror:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::pread:
    if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())
      return false;
    // May throw; "pread" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::pwrite:
    if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())
      return false;
    // May throw; "pwrite" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::putchar:
    Changed |= setDoesNotThrow(F);
    return Changed;
  case LibFunc::popen:
    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::pclose:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::vscanf:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::vsscanf:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||
        !FTy->getParamType(2)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::vfscanf:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() ||
        !FTy->getParamType(2)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::valloc:
    if (!FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc::vprintf:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::vfprintf:
  case LibFunc::vsprintf:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::vsnprintf:
    if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(2)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 3);
    Changed |= setOnlyReadsMemory(F, 3);
    return Changed;
  case LibFunc::open:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())
      return false;
    // May throw; "open" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::opendir:
    if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::tmpfile:
    if (!FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc::times:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::htonl:
  case LibFunc::htons:
  case LibFunc::ntohl:
  case LibFunc::ntohs:
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAccessMemory(F);
    return Changed;
  case LibFunc::lstat:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::lchown:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::qsort:
    if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy())
      return false;
    // May throw; places call through function pointer.
    Changed |= setDoesNotCapture(F, 4);
    return Changed;
  case LibFunc::dunder_strdup:
  case LibFunc::dunder_strndup:
    if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::dunder_strtok_r:
    if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::under_IO_getc:
    if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::under_IO_putc:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::dunder_isoc99_scanf:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::stat64:
  case LibFunc::lstat64:
  case LibFunc::statvfs64:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::dunder_isoc99_sscanf:
    if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::fopen64:
    if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() ||
        !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    Changed |= setOnlyReadsMemory(F, 1);
    Changed |= setOnlyReadsMemory(F, 2);
    return Changed;
  case LibFunc::fseeko64:
  case LibFunc::ftello64:
    if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    return Changed;
  case LibFunc::tmpfile64:
    if (!FTy->getReturnType()->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotAlias(F, 0);
    return Changed;
  case LibFunc::fstat64:
  case LibFunc::fstatvfs64:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
      return false;
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;
  case LibFunc::open64:
    if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())
      return false;
    // May throw; "open" is a valid pthread cancellation point.
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setOnlyReadsMemory(F, 1);
    return Changed;
  case LibFunc::gettimeofday:
    if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() ||
        !FTy->getParamType(1)->isPointerTy())
      return false;
    // Currently some platforms have the restrict keyword on the arguments to
    // gettimeofday. To be conservative, do not add noalias to gettimeofday's
    // arguments.
    Changed |= setDoesNotThrow(F);
    Changed |= setDoesNotCapture(F, 1);
    Changed |= setDoesNotCapture(F, 2);
    return Changed;

  case LibFunc::Znwj: // new(unsigned int)
  case LibFunc::Znwm: // new(unsigned long)
  case LibFunc::Znaj: // new[](unsigned int)
  case LibFunc::Znam: // new[](unsigned long)
  case LibFunc::msvc_new_int: // new(unsigned int)
  case LibFunc::msvc_new_longlong: // new(unsigned long long)
  case LibFunc::msvc_new_array_int: // new[](unsigned int)
  case LibFunc::msvc_new_array_longlong: // new[](unsigned long long)
    if (FTy->getNumParams() != 1)
      return false;
    // Operator new always returns a nonnull noalias pointer
    Changed |= setNonNull(F, AttributeSet::ReturnIndex);
    Changed |= setDoesNotAlias(F, AttributeSet::ReturnIndex);
    return Changed;

  default:
    // FIXME: It'd be really nice to cover all the library functions we're
    // aware of here.
    return false;
  }
}