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