2008-05-01 06:25:24 +00:00
|
|
|
//===- SimplifyLibCalls.cpp - Optimize specific well-known library calls --===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements a simple pass that applies a variety of small
|
|
|
|
// optimizations for calls to specific well-known function calls (e.g. runtime
|
2009-09-03 05:19:59 +00:00
|
|
|
// library functions). Any optimization that takes the very simple form
|
|
|
|
// "replace call to library function with simpler code that provides the same
|
|
|
|
// result" belongs in this file.
|
2008-05-01 06:25:24 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "simplify-libcalls"
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
2012-06-29 12:38:19 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2008-05-01 06:25:24 +00:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2012-06-29 12:38:19 +00:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
2012-12-03 16:50:05 +00:00
|
|
|
#include "llvm/Config/config.h" // FIXME: Shouldn't depend on host!
|
|
|
|
#include "llvm/DataLayout.h"
|
|
|
|
#include "llvm/IRBuilder.h"
|
|
|
|
#include "llvm/LLVMContext.h"
|
|
|
|
#include "llvm/Module.h"
|
|
|
|
#include "llvm/Pass.h"
|
2012-08-22 17:22:33 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2008-05-01 06:39:12 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
2009-07-26 08:34:35 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-06-29 12:38:19 +00:00
|
|
|
#include "llvm/Target/TargetLibraryInfo.h"
|
2012-12-03 16:50:05 +00:00
|
|
|
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
2008-05-01 06:25:24 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2009-01-04 20:27:34 +00:00
|
|
|
STATISTIC(NumAnnotated, "Number of attributes added to library functions");
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Optimizer Base Class
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// This class is the abstract base class for the set of optimizations that
|
|
|
|
/// corresponds to one library call.
|
|
|
|
namespace {
|
2009-09-02 06:11:42 +00:00
|
|
|
class LibCallOptimization {
|
2008-05-01 06:25:24 +00:00
|
|
|
protected:
|
|
|
|
Function *Caller;
|
2012-10-08 16:38:25 +00:00
|
|
|
const DataLayout *TD;
|
2011-03-03 13:17:51 +00:00
|
|
|
const TargetLibraryInfo *TLI;
|
2009-07-03 19:42:02 +00:00
|
|
|
LLVMContext* Context;
|
2008-05-01 06:25:24 +00:00
|
|
|
public:
|
2010-03-24 20:19:04 +00:00
|
|
|
LibCallOptimization() { }
|
2008-05-01 06:25:24 +00:00
|
|
|
virtual ~LibCallOptimization() {}
|
|
|
|
|
|
|
|
/// CallOptimizer - This pure virtual method is implemented by base classes to
|
|
|
|
/// do various optimizations. If this returns null then no transformation was
|
|
|
|
/// performed. If it returns CI, then it transformed the call and CI is to be
|
|
|
|
/// deleted. If it returns something else, replace CI with the new value and
|
|
|
|
/// delete CI.
|
2009-10-07 21:14:25 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)
|
2008-08-08 19:39:37 +00:00
|
|
|
=0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2012-10-08 16:38:25 +00:00
|
|
|
Value *OptimizeCall(CallInst *CI, const DataLayout *TD,
|
2011-03-03 13:17:51 +00:00
|
|
|
const TargetLibraryInfo *TLI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Caller = CI->getParent()->getParent();
|
2009-08-18 00:48:13 +00:00
|
|
|
this->TD = TD;
|
2011-03-03 13:17:51 +00:00
|
|
|
this->TLI = TLI;
|
2009-07-03 19:42:02 +00:00
|
|
|
if (CI->getCalledFunction())
|
2009-07-22 00:24:57 +00:00
|
|
|
Context = &CI->getCalledFunction()->getContext();
|
2010-06-16 19:34:01 +00:00
|
|
|
|
|
|
|
// We never change the calling convention.
|
|
|
|
if (CI->getCallingConv() != llvm::CallingConv::C)
|
|
|
|
return NULL;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
return CallOptimizer(CI->getCalledFunction(), CI, B);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// SimplifyLibCalls Pass Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// This pass optimizes well known library functions from libc and libm.
|
|
|
|
///
|
2009-09-02 06:11:42 +00:00
|
|
|
class SimplifyLibCalls : public FunctionPass {
|
2011-02-24 07:16:14 +00:00
|
|
|
TargetLibraryInfo *TLI;
|
2012-07-24 10:51:42 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
StringMap<LibCallOptimization*> Optimizations;
|
2012-07-24 10:51:42 +00:00
|
|
|
|
2009-01-05 00:07:50 +00:00
|
|
|
bool Modified; // This is only used by doInitialization.
|
2008-05-01 06:25:24 +00:00
|
|
|
public:
|
|
|
|
static char ID; // Pass identification
|
2012-11-13 04:16:17 +00:00
|
|
|
SimplifyLibCalls() : FunctionPass(ID) {
|
2010-10-19 17:21:58 +00:00
|
|
|
initializeSimplifyLibCallsPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2011-11-17 01:27:36 +00:00
|
|
|
void AddOpt(LibFunc::Func F, LibCallOptimization* Opt);
|
2012-08-22 16:52:57 +00:00
|
|
|
void AddOpt(LibFunc::Func F1, LibFunc::Func F2, LibCallOptimization* Opt);
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
void InitOptimizations();
|
|
|
|
bool runOnFunction(Function &F);
|
|
|
|
|
2009-01-04 20:27:34 +00:00
|
|
|
void setDoesNotAccessMemory(Function &F);
|
|
|
|
void setOnlyReadsMemory(Function &F);
|
|
|
|
void setDoesNotThrow(Function &F);
|
|
|
|
void setDoesNotCapture(Function &F, unsigned n);
|
|
|
|
void setDoesNotAlias(Function &F, unsigned n);
|
2009-01-05 00:07:50 +00:00
|
|
|
bool doInitialization(Module &M);
|
2009-01-04 20:27:34 +00:00
|
|
|
|
2011-02-24 07:12:12 +00:00
|
|
|
void inferPrototypeAttributes(Function &F);
|
2008-05-01 06:25:24 +00:00
|
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
2011-02-24 07:16:14 +00:00
|
|
|
AU.addRequired<TargetLibraryInfo>();
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace.
|
|
|
|
|
2011-02-24 07:16:14 +00:00
|
|
|
char SimplifyLibCalls::ID = 0;
|
|
|
|
|
|
|
|
INITIALIZE_PASS_BEGIN(SimplifyLibCalls, "simplify-libcalls",
|
|
|
|
"Simplify well-known library calls", false, false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo)
|
|
|
|
INITIALIZE_PASS_END(SimplifyLibCalls, "simplify-libcalls",
|
|
|
|
"Simplify well-known library calls", false, false)
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
// Public interface to the Simplify LibCalls pass.
|
|
|
|
FunctionPass *llvm::createSimplifyLibCallsPass() {
|
2009-10-07 21:14:25 +00:00
|
|
|
return new SimplifyLibCalls();
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
2011-11-17 01:27:36 +00:00
|
|
|
void SimplifyLibCalls::AddOpt(LibFunc::Func F, LibCallOptimization* Opt) {
|
|
|
|
if (TLI->has(F))
|
|
|
|
Optimizations[TLI->getName(F)] = Opt;
|
|
|
|
}
|
|
|
|
|
2012-08-22 16:52:57 +00:00
|
|
|
void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
|
|
|
|
LibCallOptimization* Opt) {
|
|
|
|
if (TLI->has(F1) && TLI->has(F2))
|
|
|
|
Optimizations[TLI->getName(F1)] = Opt;
|
|
|
|
}
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// Optimizations - Populate the Optimizations map with all the optimizations
|
|
|
|
/// we know.
|
|
|
|
void SimplifyLibCalls::InitOptimizations() {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// runOnFunction - Top level algorithm.
|
|
|
|
///
|
|
|
|
bool SimplifyLibCalls::runOnFunction(Function &F) {
|
2011-02-24 07:16:14 +00:00
|
|
|
TLI = &getAnalysis<TargetLibraryInfo>();
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Optimizations.empty())
|
|
|
|
InitOptimizations();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2012-10-08 16:38:25 +00:00
|
|
|
const DataLayout *TD = getAnalysisIfAvailable<DataLayout>();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-07-22 00:24:57 +00:00
|
|
|
IRBuilder<> Builder(F.getContext());
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
bool Changed = false;
|
|
|
|
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
|
|
|
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
|
|
|
|
// Ignore non-calls.
|
|
|
|
CallInst *CI = dyn_cast<CallInst>(I++);
|
|
|
|
if (!CI) continue;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Ignore indirect calls and calls to non-external functions.
|
|
|
|
Function *Callee = CI->getCalledFunction();
|
|
|
|
if (Callee == 0 || !Callee->isDeclaration() ||
|
|
|
|
!(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage()))
|
|
|
|
continue;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Ignore unknown calls.
|
2009-07-26 08:34:35 +00:00
|
|
|
LibCallOptimization *LCO = Optimizations.lookup(Callee->getName());
|
|
|
|
if (!LCO) continue;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Set the builder to the instruction after the call.
|
|
|
|
Builder.SetInsertPoint(BB, I);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2011-03-09 21:27:52 +00:00
|
|
|
// Use debug location of CI for all new instructions.
|
|
|
|
Builder.SetCurrentDebugLocation(CI->getDebugLoc());
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Try to optimize this call.
|
2011-03-03 13:17:51 +00:00
|
|
|
Value *Result = LCO->OptimizeCall(CI, TD, TLI, Builder);
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Result == 0) continue;
|
|
|
|
|
2010-01-05 01:27:21 +00:00
|
|
|
DEBUG(dbgs() << "SimplifyLibCalls simplified: " << *CI;
|
|
|
|
dbgs() << " into: " << *Result << "\n");
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Something changed!
|
|
|
|
Changed = true;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Inspect the instruction after the call (which was potentially just
|
|
|
|
// added) next.
|
|
|
|
I = CI; ++I;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (CI != Result && !CI->use_empty()) {
|
|
|
|
CI->replaceAllUsesWith(Result);
|
|
|
|
if (!Result->hasName())
|
|
|
|
Result->takeName(CI);
|
|
|
|
}
|
|
|
|
CI->eraseFromParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
|
2009-01-05 00:07:50 +00:00
|
|
|
// Utility methods for doInitialization.
|
2009-01-04 20:27:34 +00:00
|
|
|
|
|
|
|
void SimplifyLibCalls::setDoesNotAccessMemory(Function &F) {
|
|
|
|
if (!F.doesNotAccessMemory()) {
|
|
|
|
F.setDoesNotAccessMemory();
|
|
|
|
++NumAnnotated;
|
|
|
|
Modified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void SimplifyLibCalls::setOnlyReadsMemory(Function &F) {
|
|
|
|
if (!F.onlyReadsMemory()) {
|
|
|
|
F.setOnlyReadsMemory();
|
|
|
|
++NumAnnotated;
|
|
|
|
Modified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void SimplifyLibCalls::setDoesNotThrow(Function &F) {
|
|
|
|
if (!F.doesNotThrow()) {
|
|
|
|
F.setDoesNotThrow();
|
|
|
|
++NumAnnotated;
|
|
|
|
Modified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void SimplifyLibCalls::setDoesNotCapture(Function &F, unsigned n) {
|
|
|
|
if (!F.doesNotCapture(n)) {
|
|
|
|
F.setDoesNotCapture(n);
|
|
|
|
++NumAnnotated;
|
|
|
|
Modified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void SimplifyLibCalls::setDoesNotAlias(Function &F, unsigned n) {
|
|
|
|
if (!F.doesNotAlias(n)) {
|
|
|
|
F.setDoesNotAlias(n);
|
|
|
|
++NumAnnotated;
|
|
|
|
Modified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-24 07:12:12 +00:00
|
|
|
|
|
|
|
void SimplifyLibCalls::inferPrototypeAttributes(Function &F) {
|
2011-07-18 04:54:35 +00:00
|
|
|
FunctionType *FTy = F.getFunctionType();
|
2012-07-24 10:51:42 +00:00
|
|
|
|
2011-02-24 07:12:12 +00:00
|
|
|
StringRef Name = F.getName();
|
|
|
|
switch (Name[0]) {
|
|
|
|
case 's':
|
|
|
|
if (Name == "strlen") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "strchr" ||
|
|
|
|
Name == "strrchr") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isIntegerTy())
|
|
|
|
return;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
} else if (Name == "strcpy" ||
|
|
|
|
Name == "stpcpy" ||
|
|
|
|
Name == "strcat" ||
|
|
|
|
Name == "strtol" ||
|
|
|
|
Name == "strtod" ||
|
|
|
|
Name == "strtof" ||
|
|
|
|
Name == "strtoul" ||
|
|
|
|
Name == "strtoll" ||
|
|
|
|
Name == "strtold" ||
|
|
|
|
Name == "strncat" ||
|
|
|
|
Name == "strncpy" ||
|
2012-05-15 11:46:21 +00:00
|
|
|
Name == "stpncpy" ||
|
2011-02-24 07:12:12 +00:00
|
|
|
Name == "strtoull") {
|
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "strxfrm") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "strcmp" ||
|
|
|
|
Name == "strspn" ||
|
|
|
|
Name == "strncmp" ||
|
|
|
|
Name == "strcspn" ||
|
|
|
|
Name == "strcoll" ||
|
|
|
|
Name == "strcasecmp" ||
|
|
|
|
Name == "strncasecmp") {
|
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "strstr" ||
|
|
|
|
Name == "strpbrk") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "strtok" ||
|
|
|
|
Name == "strtok_r") {
|
|
|
|
if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "scanf" ||
|
|
|
|
Name == "setbuf" ||
|
|
|
|
Name == "setvbuf") {
|
|
|
|
if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "strdup" ||
|
|
|
|
Name == "strndup") {
|
|
|
|
if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "stat" ||
|
|
|
|
Name == "sscanf" ||
|
|
|
|
Name == "sprintf" ||
|
|
|
|
Name == "statvfs") {
|
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "snprintf") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(2)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 3);
|
|
|
|
} else if (Name == "setitimer") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(2)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
setDoesNotCapture(F, 3);
|
|
|
|
} else if (Name == "system") {
|
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; "system" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
if (Name == "malloc") {
|
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "memcmp") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "memchr" ||
|
|
|
|
Name == "memrchr") {
|
|
|
|
if (FTy->getNumParams() != 3)
|
|
|
|
return;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
} else if (Name == "modf" ||
|
|
|
|
Name == "modff" ||
|
|
|
|
Name == "modfl" ||
|
|
|
|
Name == "memcpy" ||
|
|
|
|
Name == "memccpy" ||
|
|
|
|
Name == "memmove") {
|
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "memalign") {
|
|
|
|
if (!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "mkdir" ||
|
|
|
|
Name == "mktime") {
|
|
|
|
if (FTy->getNumParams() == 0 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
if (Name == "realloc") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
2012-06-25 23:26:10 +00:00
|
|
|
setDoesNotAlias(F, 0);
|
2011-02-24 07:12:12 +00:00
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "read") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; "read" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "rmdir" ||
|
|
|
|
Name == "rewind" ||
|
|
|
|
Name == "remove" ||
|
|
|
|
Name == "realpath") {
|
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "rename" ||
|
|
|
|
Name == "readlink") {
|
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
if (Name == "write") {
|
|
|
|
if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; "write" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
if (Name == "bcopy") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "bcmp") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "bzero") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (Name == "calloc") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "chmod" ||
|
|
|
|
Name == "chown" ||
|
|
|
|
Name == "ctermid" ||
|
|
|
|
Name == "clearerr" ||
|
|
|
|
Name == "closedir") {
|
|
|
|
if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
if (Name == "atoi" ||
|
|
|
|
Name == "atol" ||
|
|
|
|
Name == "atof" ||
|
|
|
|
Name == "atoll") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "access") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
if (Name == "fopen") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "fdopen") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "feof" ||
|
|
|
|
Name == "free" ||
|
|
|
|
Name == "fseek" ||
|
|
|
|
Name == "ftell" ||
|
|
|
|
Name == "fgetc" ||
|
|
|
|
Name == "fseeko" ||
|
|
|
|
Name == "ftello" ||
|
|
|
|
Name == "fileno" ||
|
|
|
|
Name == "fflush" ||
|
|
|
|
Name == "fclose" ||
|
|
|
|
Name == "fsetpos" ||
|
|
|
|
Name == "flockfile" ||
|
|
|
|
Name == "funlockfile" ||
|
|
|
|
Name == "ftrylockfile") {
|
|
|
|
if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "ferror") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
} else if (Name == "fputc" ||
|
|
|
|
Name == "fstat" ||
|
|
|
|
Name == "frexp" ||
|
|
|
|
Name == "frexpf" ||
|
|
|
|
Name == "frexpl" ||
|
|
|
|
Name == "fstatvfs") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "fgets") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(2)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 3);
|
|
|
|
} else if (Name == "fread" ||
|
|
|
|
Name == "fwrite") {
|
|
|
|
if (FTy->getNumParams() != 4 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(3)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 4);
|
|
|
|
} else if (Name == "fputs" ||
|
|
|
|
Name == "fscanf" ||
|
|
|
|
Name == "fprintf" ||
|
|
|
|
Name == "fgetpos") {
|
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
if (Name == "getc" ||
|
|
|
|
Name == "getlogin_r" ||
|
|
|
|
Name == "getc_unlocked") {
|
|
|
|
if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "getenv") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "gets" ||
|
|
|
|
Name == "getchar") {
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
} else if (Name == "getitimer") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "getpwnam") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
if (Name == "ungetc") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "uname" ||
|
|
|
|
Name == "unlink" ||
|
|
|
|
Name == "unsetenv") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "utime" ||
|
|
|
|
Name == "utimes") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
if (Name == "putc") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "puts" ||
|
|
|
|
Name == "printf" ||
|
|
|
|
Name == "perror") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "pread" ||
|
|
|
|
Name == "pwrite") {
|
|
|
|
if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; these are valid pthread cancellation points.
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "putchar") {
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
} else if (Name == "popen") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "pclose") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
if (Name == "vscanf") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "vsscanf" ||
|
|
|
|
Name == "vfscanf") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(2)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "valloc") {
|
|
|
|
if (!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "vprintf") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "vfprintf" ||
|
|
|
|
Name == "vsprintf") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "vsnprintf") {
|
|
|
|
if (FTy->getNumParams() != 4 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(2)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
if (Name == "open") {
|
|
|
|
if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; "open" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "opendir") {
|
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
if (Name == "tmpfile") {
|
|
|
|
if (!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "times") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
if (Name == "htonl" ||
|
|
|
|
Name == "htons") {
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAccessMemory(F);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
if (Name == "ntohl" ||
|
|
|
|
Name == "ntohs") {
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAccessMemory(F);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
if (Name == "lstat") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "lchown") {
|
|
|
|
if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
if (Name == "qsort") {
|
|
|
|
if (FTy->getNumParams() != 4 || !FTy->getParamType(3)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; places call through function pointer.
|
|
|
|
setDoesNotCapture(F, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '_':
|
|
|
|
if (Name == "__strdup" ||
|
|
|
|
Name == "__strndup") {
|
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "__strtok_r") {
|
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "_IO_getc") {
|
|
|
|
if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "_IO_putc") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (Name == "\1__isoc99_scanf") {
|
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "\1stat64" ||
|
|
|
|
Name == "\1lstat64" ||
|
|
|
|
Name == "\1statvfs64" ||
|
|
|
|
Name == "\1__isoc99_sscanf") {
|
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "\1fopen64") {
|
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!FTy->getReturnType()->isPointerTy() ||
|
|
|
|
!FTy->getParamType(0)->isPointerTy() ||
|
|
|
|
!FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "\1fseeko64" ||
|
|
|
|
Name == "\1ftello64") {
|
|
|
|
if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
} else if (Name == "\1tmpfile64") {
|
|
|
|
if (!FTy->getReturnType()->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "\1fstat64" ||
|
|
|
|
Name == "\1fstatvfs64") {
|
|
|
|
if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())
|
|
|
|
return;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
} else if (Name == "\1open64") {
|
|
|
|
if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy())
|
|
|
|
return;
|
|
|
|
// May throw; "open" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-05 00:07:50 +00:00
|
|
|
/// doInitialization - Add attributes to well-known functions.
|
2009-01-04 20:27:34 +00:00
|
|
|
///
|
2009-01-05 00:07:50 +00:00
|
|
|
bool SimplifyLibCalls::doInitialization(Module &M) {
|
2009-01-04 20:27:34 +00:00
|
|
|
Modified = false;
|
|
|
|
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
|
|
|
Function &F = *I;
|
2011-02-24 07:12:12 +00:00
|
|
|
if (F.isDeclaration() && F.hasName())
|
|
|
|
inferPrototypeAttributes(F);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
return Modified;
|
|
|
|
}
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// Additional cases that we need to add to this file:
|
|
|
|
//
|
|
|
|
// cbrt:
|
|
|
|
// * cbrt(expN(X)) -> expN(x/3)
|
|
|
|
// * cbrt(sqrt(x)) -> pow(x,1/6)
|
|
|
|
// * cbrt(sqrt(x)) -> pow(x,1/9)
|
|
|
|
//
|
|
|
|
// exp, expf, expl:
|
|
|
|
// * exp(log(x)) -> x
|
|
|
|
//
|
|
|
|
// log, logf, logl:
|
|
|
|
// * log(exp(x)) -> x
|
|
|
|
// * log(x**y) -> y*log(x)
|
|
|
|
// * log(exp(y)) -> y*log(e)
|
|
|
|
// * log(exp2(y)) -> y*log(2)
|
|
|
|
// * log(exp10(y)) -> y*log(10)
|
|
|
|
// * log(sqrt(x)) -> 0.5*log(x)
|
|
|
|
// * log(pow(x,y)) -> y*log(x)
|
|
|
|
//
|
|
|
|
// lround, lroundf, lroundl:
|
|
|
|
// * lround(cnst) -> cnst'
|
|
|
|
//
|
|
|
|
// pow, powf, powl:
|
|
|
|
// * pow(exp(x),y) -> exp(x*y)
|
|
|
|
// * pow(sqrt(x),y) -> pow(x,y*0.5)
|
|
|
|
// * pow(pow(x,y),z)-> pow(x,y*z)
|
|
|
|
//
|
|
|
|
// round, roundf, roundl:
|
|
|
|
// * round(cnst) -> cnst'
|
|
|
|
//
|
|
|
|
// signbit:
|
|
|
|
// * signbit(cnst) -> cnst'
|
|
|
|
// * signbit(nncst) -> 0 (if pstv is a non-negative constant)
|
|
|
|
//
|
|
|
|
// sqrt, sqrtf, sqrtl:
|
|
|
|
// * sqrt(expN(x)) -> expN(x*0.5)
|
|
|
|
// * sqrt(Nroot(x)) -> pow(x,1/(2*N))
|
|
|
|
// * sqrt(pow(x,y)) -> pow(|x|,y*0.5)
|
|
|
|
//
|
2012-02-05 02:29:43 +00:00
|
|
|
// strchr:
|
|
|
|
// * strchr(p, 0) -> strlen(p)
|
2008-05-01 06:25:24 +00:00
|
|
|
// tan, tanf, tanl:
|
|
|
|
// * tan(atan(x)) -> x
|
|
|
|
//
|
|
|
|
// trunc, truncf, truncl:
|
|
|
|
// * trunc(cnst) -> cnst'
|
|
|
|
//
|
|
|
|
//
|