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"
|
|
|
|
#include "llvm/Intrinsics.h"
|
2009-07-03 19:42:02 +00:00
|
|
|
#include "llvm/LLVMContext.h"
|
2008-05-01 06:25:24 +00:00
|
|
|
#include "llvm/Module.h"
|
|
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "llvm/Support/IRBuilder.h"
|
2008-06-30 07:31:25 +00:00
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
2008-05-01 06:25:24 +00:00
|
|
|
#include "llvm/Target/TargetData.h"
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2009-07-29 22:00:43 +00:00
|
|
|
#include "llvm/ADT/STLExtras.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"
|
2008-05-01 06:25:24 +00:00
|
|
|
#include "llvm/Config/config.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
STATISTIC(NumSimplified, "Number of library calls simplified");
|
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;
|
|
|
|
const TargetData *TD;
|
2009-07-03 19:42:02 +00:00
|
|
|
LLVMContext* Context;
|
2008-05-01 06:25:24 +00:00
|
|
|
public:
|
|
|
|
LibCallOptimization() { }
|
|
|
|
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
|
|
|
|
2009-08-18 00:48:13 +00:00
|
|
|
Value *OptimizeCall(CallInst *CI, const TargetData *TD, 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;
|
2009-07-03 19:42:02 +00:00
|
|
|
if (CI->getCalledFunction())
|
2009-07-22 00:24:57 +00:00
|
|
|
Context = &CI->getCalledFunction()->getContext();
|
2008-05-01 06:25:24 +00:00
|
|
|
return CallOptimizer(CI->getCalledFunction(), CI, B);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
2008-08-08 19:39:37 +00:00
|
|
|
Value *CastToCStr(Value *V, IRBuilder<> &B);
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
/// EmitStrLen - Emit a call to the strlen function to the builder, for the
|
|
|
|
/// specified pointer. Ptr is required to be some pointer type, and the
|
|
|
|
/// return value has 'intptr_t' type.
|
2008-08-08 19:39:37 +00:00
|
|
|
Value *EmitStrLen(Value *Ptr, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-12-16 09:32:05 +00:00
|
|
|
/// EmitStrChr - Emit a call to the strchr function to the builder, for the
|
|
|
|
/// specified pointer and character. Ptr is required to be some pointer type,
|
|
|
|
/// and the return value has 'i8*' type.
|
|
|
|
Value *EmitStrChr(Value *Ptr, char C, IRBuilder<> &B);
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitMemCpy - Emit a call to the memcpy function to the builder. This
|
|
|
|
/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
|
2009-10-07 21:14:25 +00:00
|
|
|
Value *EmitMemCpy(Value *Dst, Value *Src, Value *Len,
|
2008-08-08 19:39:37 +00:00
|
|
|
unsigned Align, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-11-21 01:01:30 +00:00
|
|
|
/// EmitMemMove - Emit a call to the memmove function to the builder. This
|
|
|
|
/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
|
|
|
|
Value *EmitMemMove(Value *Dst, Value *Src, Value *Len,
|
|
|
|
unsigned Align, IRBuilder<> &B);
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is
|
|
|
|
/// a pointer, Val is an i32 value, and Len is an 'intptr_t' value.
|
2008-08-08 19:39:37 +00:00
|
|
|
Value *EmitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B);
|
2008-12-21 00:19:21 +00:00
|
|
|
|
|
|
|
/// EmitMemCmp - Emit a call to the memcmp function.
|
|
|
|
Value *EmitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B);
|
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
/// EmitMemSet - Emit a call to the memset function
|
|
|
|
Value *EmitMemSet(Value *Dst, Value *Val, Value *Len, IRBuilder<> &B);
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g.
|
|
|
|
/// 'floor'). This function is known to take a single of type matching 'Op'
|
|
|
|
/// and returns one value with the same type. If 'Op' is a long double, 'l'
|
|
|
|
/// is added as the suffix of name, if 'Op' is a float, we add a 'f' suffix.
|
2009-09-25 23:10:17 +00:00
|
|
|
Value *EmitUnaryFloatFnCall(Value *Op, const char *Name, IRBuilder<> &B,
|
|
|
|
const AttrListPtr &Attrs);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
|
|
|
|
/// is an integer.
|
2009-11-09 04:57:04 +00:00
|
|
|
Value *EmitPutChar(Value *Char, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitPutS - Emit a call to the puts function. This assumes that Str is
|
|
|
|
/// some pointer.
|
2008-08-08 19:39:37 +00:00
|
|
|
void EmitPutS(Value *Str, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitFPutC - Emit a call to the fputc function. This assumes that Char is
|
|
|
|
/// an i32, and File is a pointer to FILE.
|
2008-08-08 19:39:37 +00:00
|
|
|
void EmitFPutC(Value *Char, Value *File, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitFPutS - Emit a call to the puts function. Str is required to be a
|
|
|
|
/// pointer and File is a pointer to FILE.
|
2008-08-08 19:39:37 +00:00
|
|
|
void EmitFPutS(Value *Str, Value *File, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
|
|
|
|
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
2008-08-08 19:39:37 +00:00
|
|
|
void EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
|
|
|
|
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
2008-08-08 19:39:37 +00:00
|
|
|
Value *LibCallOptimization::CastToCStr(Value *V, IRBuilder<> &B) {
|
2009-12-02 06:05:42 +00:00
|
|
|
return B.CreateBitCast(V, Type::getInt8PtrTy(*Context), "cstr");
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitStrLen - Emit a call to the strlen function to the builder, for the
|
|
|
|
/// specified pointer. This always returns an integer value of size intptr_t.
|
2008-08-08 19:39:37 +00:00
|
|
|
Value *LibCallOptimization::EmitStrLen(Value *Ptr, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-01-05 00:07:50 +00:00
|
|
|
AttributeWithIndex AWI[2];
|
|
|
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
|
|
|
AWI[1] = AttributeWithIndex::get(~0u, Attribute::ReadOnly |
|
|
|
|
Attribute::NoUnwind);
|
|
|
|
|
|
|
|
Constant *StrLen =M->getOrInsertFunction("strlen", AttrListPtr::get(AWI, 2),
|
2009-08-13 21:58:54 +00:00
|
|
|
TD->getIntPtrType(*Context),
|
2009-10-07 21:14:25 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
2008-05-01 06:25:24 +00:00
|
|
|
NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall(StrLen, CastToCStr(Ptr, B), "strlen");
|
|
|
|
if (const Function *F = dyn_cast<Function>(StrLen->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
|
|
|
|
return CI;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
2009-12-16 09:32:05 +00:00
|
|
|
/// EmitStrChr - Emit a call to the strchr function to the builder, for the
|
|
|
|
/// specified pointer and character. Ptr is required to be some pointer type,
|
|
|
|
/// and the return value has 'i8*' type.
|
|
|
|
Value *LibCallOptimization::EmitStrChr(Value *Ptr, char C, IRBuilder<> &B) {
|
|
|
|
Module *M = Caller->getParent();
|
|
|
|
AttributeWithIndex AWI =
|
|
|
|
AttributeWithIndex::get(~0u, Attribute::ReadOnly | Attribute::NoUnwind);
|
|
|
|
|
|
|
|
const Type *I8Ptr = Type::getInt8PtrTy(*Context);
|
|
|
|
const Type *I32Ty = Type::getInt32Ty(*Context);
|
|
|
|
Constant *StrChr = M->getOrInsertFunction("strchr", AttrListPtr::get(&AWI, 1),
|
|
|
|
I8Ptr, I8Ptr, I32Ty, NULL);
|
|
|
|
CallInst *CI = B.CreateCall2(StrChr, CastToCStr(Ptr, B),
|
|
|
|
ConstantInt::get(I32Ty, C), "strchr");
|
|
|
|
if (const Function *F = dyn_cast<Function>(StrChr->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitMemCpy - Emit a call to the memcpy function to the builder. This always
|
|
|
|
/// expects that the size has type 'intptr_t' and Dst/Src are pointers.
|
|
|
|
Value *LibCallOptimization::EmitMemCpy(Value *Dst, Value *Src, Value *Len,
|
2008-08-08 19:39:37 +00:00
|
|
|
unsigned Align, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-12-02 06:05:42 +00:00
|
|
|
const Type *Ty = Len->getType();
|
|
|
|
Value *MemCpy = Intrinsic::getDeclaration(M, Intrinsic::memcpy, &Ty, 1);
|
|
|
|
Dst = CastToCStr(Dst, B);
|
|
|
|
Src = CastToCStr(Src, B);
|
|
|
|
return B.CreateCall4(MemCpy, Dst, Src, Len,
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(Type::getInt32Ty(*Context), Align));
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
2009-12-02 06:05:42 +00:00
|
|
|
/// EmitMemMove - Emit a call to the memmove function to the builder. This
|
2009-11-21 01:01:30 +00:00
|
|
|
/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
|
|
|
|
Value *LibCallOptimization::EmitMemMove(Value *Dst, Value *Src, Value *Len,
|
|
|
|
unsigned Align, IRBuilder<> &B) {
|
|
|
|
Module *M = Caller->getParent();
|
2009-12-02 06:05:42 +00:00
|
|
|
const Type *Ty = TD->getIntPtrType(*Context);
|
|
|
|
Value *MemMove = Intrinsic::getDeclaration(M, Intrinsic::memmove, &Ty, 1);
|
|
|
|
Dst = CastToCStr(Dst, B);
|
|
|
|
Src = CastToCStr(Src, B);
|
2009-11-21 01:01:30 +00:00
|
|
|
Value *A = ConstantInt::get(Type::getInt32Ty(*Context), Align);
|
2009-12-02 06:05:42 +00:00
|
|
|
return B.CreateCall4(MemMove, Dst, Src, Len, A);
|
2009-11-21 01:01:30 +00:00
|
|
|
}
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is
|
|
|
|
/// a pointer, Val is an i32 value, and Len is an 'intptr_t' value.
|
|
|
|
Value *LibCallOptimization::EmitMemChr(Value *Ptr, Value *Val,
|
2008-08-08 19:39:37 +00:00
|
|
|
Value *Len, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-01-05 00:07:50 +00:00
|
|
|
AttributeWithIndex AWI;
|
|
|
|
AWI = AttributeWithIndex::get(~0u, Attribute::ReadOnly | Attribute::NoUnwind);
|
|
|
|
|
|
|
|
Value *MemChr = M->getOrInsertFunction("memchr", AttrListPtr::get(&AWI, 1),
|
2009-10-07 21:14:25 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
|
|
|
Type::getInt8PtrTy(*Context),
|
|
|
|
Type::getInt32Ty(*Context),
|
|
|
|
TD->getIntPtrType(*Context),
|
2008-05-01 06:25:24 +00:00
|
|
|
NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall3(MemChr, CastToCStr(Ptr, B), Val, Len, "memchr");
|
|
|
|
|
|
|
|
if (const Function *F = dyn_cast<Function>(MemChr->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
|
|
|
|
return CI;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
2008-12-21 00:19:21 +00:00
|
|
|
/// EmitMemCmp - Emit a call to the memcmp function.
|
|
|
|
Value *LibCallOptimization::EmitMemCmp(Value *Ptr1, Value *Ptr2,
|
|
|
|
Value *Len, IRBuilder<> &B) {
|
|
|
|
Module *M = Caller->getParent();
|
2009-01-05 00:07:50 +00:00
|
|
|
AttributeWithIndex AWI[3];
|
|
|
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
|
|
|
AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture);
|
|
|
|
AWI[2] = AttributeWithIndex::get(~0u, Attribute::ReadOnly |
|
|
|
|
Attribute::NoUnwind);
|
|
|
|
|
|
|
|
Value *MemCmp = M->getOrInsertFunction("memcmp", AttrListPtr::get(AWI, 3),
|
2009-08-13 21:58:54 +00:00
|
|
|
Type::getInt32Ty(*Context),
|
2009-10-06 15:40:36 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
|
|
|
Type::getInt8PtrTy(*Context),
|
2009-08-13 21:58:54 +00:00
|
|
|
TD->getIntPtrType(*Context), NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall3(MemCmp, CastToCStr(Ptr1, B), CastToCStr(Ptr2, B),
|
|
|
|
Len, "memcmp");
|
|
|
|
|
|
|
|
if (const Function *F = dyn_cast<Function>(MemCmp->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
|
|
|
|
return CI;
|
2008-12-21 00:19:21 +00:00
|
|
|
}
|
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
/// EmitMemSet - Emit a call to the memset function
|
|
|
|
Value *LibCallOptimization::EmitMemSet(Value *Dst, Value *Val,
|
|
|
|
Value *Len, IRBuilder<> &B) {
|
|
|
|
Module *M = Caller->getParent();
|
|
|
|
Intrinsic::ID IID = Intrinsic::memset;
|
|
|
|
const Type *Tys[1];
|
|
|
|
Tys[0] = Len->getType();
|
|
|
|
Value *MemSet = Intrinsic::getDeclaration(M, IID, Tys, 1);
|
2009-08-13 21:58:54 +00:00
|
|
|
Value *Align = ConstantInt::get(Type::getInt32Ty(*Context), 1);
|
2009-04-12 05:06:39 +00:00
|
|
|
return B.CreateCall4(MemSet, CastToCStr(Dst, B), Val, Len, Align);
|
|
|
|
}
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
/// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g.
|
|
|
|
/// 'floor'). This function is known to take a single of type matching 'Op' and
|
|
|
|
/// returns one value with the same type. If 'Op' is a long double, 'l' is
|
|
|
|
/// added as the suffix of name, if 'Op' is a float, we add a 'f' suffix.
|
|
|
|
Value *LibCallOptimization::EmitUnaryFloatFnCall(Value *Op, const char *Name,
|
2009-09-25 23:10:17 +00:00
|
|
|
IRBuilder<> &B,
|
|
|
|
const AttrListPtr &Attrs) {
|
2008-05-01 06:25:24 +00:00
|
|
|
char NameBuffer[20];
|
2009-10-05 05:54:46 +00:00
|
|
|
if (!Op->getType()->isDoubleTy()) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// If we need to add a suffix, copy into NameBuffer.
|
|
|
|
unsigned NameLen = strlen(Name);
|
|
|
|
assert(NameLen < sizeof(NameBuffer)-2);
|
|
|
|
memcpy(NameBuffer, Name, NameLen);
|
2009-10-05 05:54:46 +00:00
|
|
|
if (Op->getType()->isFloatTy())
|
2008-05-01 06:25:24 +00:00
|
|
|
NameBuffer[NameLen] = 'f'; // floorf
|
|
|
|
else
|
|
|
|
NameBuffer[NameLen] = 'l'; // floorl
|
|
|
|
NameBuffer[NameLen+1] = 0;
|
|
|
|
Name = NameBuffer;
|
|
|
|
}
|
2009-06-18 20:05:31 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-06-18 20:05:31 +00:00
|
|
|
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
|
2008-05-01 06:25:24 +00:00
|
|
|
Op->getType(), NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall(Callee, Op, Name);
|
2009-09-25 23:10:17 +00:00
|
|
|
CI->setAttributes(Attrs);
|
2009-06-18 20:05:31 +00:00
|
|
|
if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
|
|
|
|
return CI;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
|
|
|
|
/// is an integer.
|
2009-11-09 04:57:04 +00:00
|
|
|
Value *LibCallOptimization::EmitPutChar(Value *Char, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-08-13 21:58:54 +00:00
|
|
|
Value *PutChar = M->getOrInsertFunction("putchar", Type::getInt32Ty(*Context),
|
|
|
|
Type::getInt32Ty(*Context), NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall(PutChar,
|
2009-10-07 21:14:25 +00:00
|
|
|
B.CreateIntCast(Char,
|
|
|
|
Type::getInt32Ty(*Context),
|
2009-11-16 12:32:28 +00:00
|
|
|
/*isSigned*/true,
|
2009-10-07 21:14:25 +00:00
|
|
|
"chari"),
|
2009-06-18 20:05:31 +00:00
|
|
|
"putchar");
|
|
|
|
|
|
|
|
if (const Function *F = dyn_cast<Function>(PutChar->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
2009-11-09 04:57:04 +00:00
|
|
|
return CI;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitPutS - Emit a call to the puts function. This assumes that Str is
|
|
|
|
/// some pointer.
|
2008-08-08 19:39:37 +00:00
|
|
|
void LibCallOptimization::EmitPutS(Value *Str, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-01-05 00:07:50 +00:00
|
|
|
AttributeWithIndex AWI[2];
|
|
|
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
|
|
|
AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
|
|
|
|
2009-06-18 20:05:31 +00:00
|
|
|
Value *PutS = M->getOrInsertFunction("puts", AttrListPtr::get(AWI, 2),
|
2009-08-13 21:58:54 +00:00
|
|
|
Type::getInt32Ty(*Context),
|
2009-10-06 15:40:36 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
2009-06-18 20:05:31 +00:00
|
|
|
NULL);
|
|
|
|
CallInst *CI = B.CreateCall(PutS, CastToCStr(Str, B), "puts");
|
|
|
|
if (const Function *F = dyn_cast<Function>(PutS->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitFPutC - Emit a call to the fputc function. This assumes that Char is
|
|
|
|
/// an integer and File is a pointer to FILE.
|
2008-08-08 19:39:37 +00:00
|
|
|
void LibCallOptimization::EmitFPutC(Value *Char, Value *File, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-01-05 00:07:50 +00:00
|
|
|
AttributeWithIndex AWI[2];
|
|
|
|
AWI[0] = AttributeWithIndex::get(2, Attribute::NoCapture);
|
|
|
|
AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
|
|
|
Constant *F;
|
|
|
|
if (isa<PointerType>(File->getType()))
|
2009-10-07 21:14:25 +00:00
|
|
|
F = M->getOrInsertFunction("fputc", AttrListPtr::get(AWI, 2),
|
|
|
|
Type::getInt32Ty(*Context),
|
|
|
|
Type::getInt32Ty(*Context), File->getType(),
|
|
|
|
NULL);
|
2009-01-05 00:07:50 +00:00
|
|
|
else
|
2009-10-07 21:14:25 +00:00
|
|
|
F = M->getOrInsertFunction("fputc",
|
|
|
|
Type::getInt32Ty(*Context),
|
|
|
|
Type::getInt32Ty(*Context),
|
2009-01-05 00:07:50 +00:00
|
|
|
File->getType(), NULL);
|
2009-11-16 12:32:28 +00:00
|
|
|
Char = B.CreateIntCast(Char, Type::getInt32Ty(*Context), /*isSigned*/true,
|
|
|
|
"chari");
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall2(F, Char, File, "fputc");
|
|
|
|
|
|
|
|
if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(Fn->getCallingConv());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitFPutS - Emit a call to the puts function. Str is required to be a
|
|
|
|
/// pointer and File is a pointer to FILE.
|
2008-08-08 19:39:37 +00:00
|
|
|
void LibCallOptimization::EmitFPutS(Value *Str, Value *File, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-02-15 22:47:25 +00:00
|
|
|
AttributeWithIndex AWI[3];
|
|
|
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
|
|
|
AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture);
|
|
|
|
AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
2009-01-05 00:07:50 +00:00
|
|
|
Constant *F;
|
|
|
|
if (isa<PointerType>(File->getType()))
|
2009-10-07 21:14:25 +00:00
|
|
|
F = M->getOrInsertFunction("fputs", AttrListPtr::get(AWI, 3),
|
|
|
|
Type::getInt32Ty(*Context),
|
2009-10-06 15:40:36 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
2009-01-05 00:07:50 +00:00
|
|
|
File->getType(), NULL);
|
|
|
|
else
|
2009-08-13 21:58:54 +00:00
|
|
|
F = M->getOrInsertFunction("fputs", Type::getInt32Ty(*Context),
|
2009-10-06 15:40:36 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
2009-01-05 00:07:50 +00:00
|
|
|
File->getType(), NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall2(F, CastToCStr(Str, B), File, "fputs");
|
|
|
|
|
|
|
|
if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(Fn->getCallingConv());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
|
|
|
|
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
|
|
|
void LibCallOptimization::EmitFWrite(Value *Ptr, Value *Size, Value *File,
|
2008-08-08 19:39:37 +00:00
|
|
|
IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
Module *M = Caller->getParent();
|
2009-01-05 00:07:50 +00:00
|
|
|
AttributeWithIndex AWI[3];
|
|
|
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
|
|
|
AWI[1] = AttributeWithIndex::get(4, Attribute::NoCapture);
|
|
|
|
AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
|
|
|
Constant *F;
|
|
|
|
if (isa<PointerType>(File->getType()))
|
|
|
|
F = M->getOrInsertFunction("fwrite", AttrListPtr::get(AWI, 3),
|
2009-08-13 21:58:54 +00:00
|
|
|
TD->getIntPtrType(*Context),
|
2009-10-06 15:40:36 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
2009-10-07 21:14:25 +00:00
|
|
|
TD->getIntPtrType(*Context),
|
|
|
|
TD->getIntPtrType(*Context),
|
2009-01-05 00:07:50 +00:00
|
|
|
File->getType(), NULL);
|
|
|
|
else
|
2009-08-13 21:58:54 +00:00
|
|
|
F = M->getOrInsertFunction("fwrite", TD->getIntPtrType(*Context),
|
2009-10-06 15:40:36 +00:00
|
|
|
Type::getInt8PtrTy(*Context),
|
2009-10-07 21:14:25 +00:00
|
|
|
TD->getIntPtrType(*Context),
|
|
|
|
TD->getIntPtrType(*Context),
|
2009-01-05 00:07:50 +00:00
|
|
|
File->getType(), NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall4(F, CastToCStr(Ptr, B), Size,
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), 1), File);
|
2009-06-18 20:05:31 +00:00
|
|
|
|
|
|
|
if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(Fn->getCallingConv());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Helper Functions
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// GetStringLengthH - If we can compute the length of the string pointed to by
|
|
|
|
/// the specified pointer, return 'len+1'. If we can't, return 0.
|
|
|
|
static uint64_t GetStringLengthH(Value *V, SmallPtrSet<PHINode*, 32> &PHIs) {
|
|
|
|
// Look through noop bitcast instructions.
|
|
|
|
if (BitCastInst *BCI = dyn_cast<BitCastInst>(V))
|
|
|
|
return GetStringLengthH(BCI->getOperand(0), PHIs);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If this is a PHI node, there are two cases: either we have already seen it
|
|
|
|
// or we haven't.
|
|
|
|
if (PHINode *PN = dyn_cast<PHINode>(V)) {
|
|
|
|
if (!PHIs.insert(PN))
|
|
|
|
return ~0ULL; // already in the set.
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If it was new, see if all the input strings are the same length.
|
|
|
|
uint64_t LenSoFar = ~0ULL;
|
|
|
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
|
|
|
|
uint64_t Len = GetStringLengthH(PN->getIncomingValue(i), PHIs);
|
|
|
|
if (Len == 0) return 0; // Unknown length -> unknown.
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Len == ~0ULL) continue;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Len != LenSoFar && LenSoFar != ~0ULL)
|
|
|
|
return 0; // Disagree -> unknown.
|
|
|
|
LenSoFar = Len;
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Success, all agree.
|
|
|
|
return LenSoFar;
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// strlen(select(c,x,y)) -> strlen(x) ^ strlen(y)
|
|
|
|
if (SelectInst *SI = dyn_cast<SelectInst>(V)) {
|
|
|
|
uint64_t Len1 = GetStringLengthH(SI->getTrueValue(), PHIs);
|
|
|
|
if (Len1 == 0) return 0;
|
|
|
|
uint64_t Len2 = GetStringLengthH(SI->getFalseValue(), PHIs);
|
|
|
|
if (Len2 == 0) return 0;
|
|
|
|
if (Len1 == ~0ULL) return Len2;
|
|
|
|
if (Len2 == ~0ULL) return Len1;
|
|
|
|
if (Len1 != Len2) return 0;
|
|
|
|
return Len1;
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If the value is not a GEP instruction nor a constant expression with a
|
|
|
|
// GEP instruction, then return unknown.
|
|
|
|
User *GEP = 0;
|
|
|
|
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) {
|
|
|
|
GEP = GEPI;
|
|
|
|
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
|
|
|
|
if (CE->getOpcode() != Instruction::GetElementPtr)
|
|
|
|
return 0;
|
|
|
|
GEP = CE;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Make sure the GEP has exactly three arguments.
|
|
|
|
if (GEP->getNumOperands() != 3)
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Check to make sure that the first operand of the GEP is an integer and
|
|
|
|
// has value 0 so that we are sure we're indexing into the initializer.
|
|
|
|
if (ConstantInt *Idx = dyn_cast<ConstantInt>(GEP->getOperand(1))) {
|
|
|
|
if (!Idx->isZero())
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If the second index isn't a ConstantInt, then this is a variable index
|
|
|
|
// into the array. If this occurs, we can't say anything meaningful about
|
|
|
|
// the string.
|
|
|
|
uint64_t StartIdx = 0;
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(GEP->getOperand(2)))
|
|
|
|
StartIdx = CI->getZExtValue();
|
|
|
|
else
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// The GEP instruction, constant or instruction, must reference a global
|
|
|
|
// variable that is a constant and is initialized. The referenced constant
|
|
|
|
// initializer is the array that we'll use for optimization.
|
|
|
|
GlobalVariable* GV = dyn_cast<GlobalVariable>(GEP->getOperand(0));
|
2009-08-19 00:11:12 +00:00
|
|
|
if (!GV || !GV->isConstant() || !GV->hasInitializer() ||
|
|
|
|
GV->mayBeOverridden())
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
Constant *GlobalInit = GV->getInitializer();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Handle the ConstantAggregateZero case, which is a degenerate case. The
|
|
|
|
// initializer is constant zero so the length of the string must be zero.
|
|
|
|
if (isa<ConstantAggregateZero>(GlobalInit))
|
|
|
|
return 1; // Len = 0 offset by 1.
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Must be a Constant Array
|
|
|
|
ConstantArray *Array = dyn_cast<ConstantArray>(GlobalInit);
|
2009-08-13 21:58:54 +00:00
|
|
|
if (!Array ||
|
|
|
|
Array->getType()->getElementType() != Type::getInt8Ty(V->getContext()))
|
2008-05-01 06:25:24 +00:00
|
|
|
return false;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Get the number of elements in the array
|
|
|
|
uint64_t NumElts = Array->getType()->getNumElements();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Traverse the constant array from StartIdx (derived above) which is
|
|
|
|
// the place the GEP refers to in the array.
|
|
|
|
for (unsigned i = StartIdx; i != NumElts; ++i) {
|
|
|
|
Constant *Elt = Array->getOperand(i);
|
|
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(Elt);
|
|
|
|
if (!CI) // This array isn't suitable, non-int initializer.
|
|
|
|
return 0;
|
|
|
|
if (CI->isZero())
|
|
|
|
return i-StartIdx+1; // We found end of string, success!
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0; // The array isn't null terminated, conservatively return 'unknown'.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// GetStringLength - If we can compute the length of the string pointed to by
|
|
|
|
/// the specified pointer, return 'len+1'. If we can't, return 0.
|
|
|
|
static uint64_t GetStringLength(Value *V) {
|
|
|
|
if (!isa<PointerType>(V->getType())) return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
SmallPtrSet<PHINode*, 32> PHIs;
|
|
|
|
uint64_t Len = GetStringLengthH(V, PHIs);
|
|
|
|
// If Len is ~0ULL, we had an infinite phi cycle: this is dead code, so return
|
|
|
|
// an empty string as a length.
|
|
|
|
return Len == ~0ULL ? 1 : Len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// IsOnlyUsedInZeroEqualityComparison - Return true if it only matters that the
|
2009-10-07 21:14:25 +00:00
|
|
|
/// value is equal or not-equal to zero.
|
2008-05-01 06:25:24 +00:00
|
|
|
static bool IsOnlyUsedInZeroEqualityComparison(Value *V) {
|
|
|
|
for (Value::use_iterator UI = V->use_begin(), E = V->use_end();
|
|
|
|
UI != E; ++UI) {
|
|
|
|
if (ICmpInst *IC = dyn_cast<ICmpInst>(*UI))
|
|
|
|
if (IC->isEquality())
|
|
|
|
if (Constant *C = dyn_cast<Constant>(IC->getOperand(1)))
|
|
|
|
if (C->isNullValue())
|
|
|
|
continue;
|
|
|
|
// Unknown instruction.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// String and Memory LibCall Optimizations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strcat' Optimizations
|
2009-09-03 05:19:59 +00:00
|
|
|
namespace {
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrCatOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Verify the "strcat" function prototype.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getReturnType() != Type::getInt8PtrTy(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
FT->getParamType(0) != FT->getReturnType() ||
|
|
|
|
FT->getParamType(1) != FT->getReturnType())
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Extract some information from the instruction
|
|
|
|
Value *Dst = CI->getOperand(1);
|
|
|
|
Value *Src = CI->getOperand(2);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// See if we can get the length of the input string.
|
|
|
|
uint64_t Len = GetStringLength(Src);
|
2008-05-01 06:39:12 +00:00
|
|
|
if (Len == 0) return 0;
|
2008-05-01 06:25:24 +00:00
|
|
|
--Len; // Unbias length.
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Handle the simple, do-nothing case: strcat(x, "") -> x
|
|
|
|
if (Len == 0)
|
|
|
|
return Dst;
|
2009-08-18 00:48:13 +00:00
|
|
|
|
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
EmitStrLenMemCpy(Src, Dst, Len, B);
|
|
|
|
return Dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// We need to find the end of the destination string. That's where the
|
|
|
|
// memory is to be moved to. We just generate a call to strlen.
|
|
|
|
Value *DstLen = EmitStrLen(Dst, B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Now that we have the destination's length, we must index into the
|
|
|
|
// destination's pointer to get the actual memcpy destination (end of
|
|
|
|
// the string .. we're concatenating).
|
2009-04-06 13:06:48 +00:00
|
|
|
Value *CpyDst = B.CreateGEP(Dst, DstLen, "endptr");
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// We have enough information to now generate the memcpy call to do the
|
|
|
|
// concatenation for us. Make a memcpy to copy the nul byte with align = 1.
|
2009-07-03 19:42:02 +00:00
|
|
|
EmitMemCpy(CpyDst, Src,
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), Len+1), 1, B);
|
2009-04-12 05:06:39 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strncat' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrNCatOpt : public StrCatOpt {
|
2009-04-12 05:06:39 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
// Verify the "strncat" function prototype.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 3 ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getReturnType() != Type::getInt8PtrTy(*Context) ||
|
2009-04-12 05:06:39 +00:00
|
|
|
FT->getParamType(0) != FT->getReturnType() ||
|
|
|
|
FT->getParamType(1) != FT->getReturnType() ||
|
|
|
|
!isa<IntegerType>(FT->getParamType(2)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Extract some information from the instruction
|
|
|
|
Value *Dst = CI->getOperand(1);
|
|
|
|
Value *Src = CI->getOperand(2);
|
|
|
|
uint64_t Len;
|
|
|
|
|
|
|
|
// We don't do anything if length is not constant
|
|
|
|
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getOperand(3)))
|
|
|
|
Len = LengthArg->getZExtValue();
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// See if we can get the length of the input string.
|
|
|
|
uint64_t SrcLen = GetStringLength(Src);
|
|
|
|
if (SrcLen == 0) return 0;
|
|
|
|
--SrcLen; // Unbias length.
|
|
|
|
|
|
|
|
// Handle the simple, do-nothing cases:
|
|
|
|
// strncat(x, "", c) -> x
|
|
|
|
// strncat(x, c, 0) -> x
|
|
|
|
if (SrcLen == 0 || Len == 0) return Dst;
|
|
|
|
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
// We don't optimize this case
|
|
|
|
if (Len < SrcLen) return 0;
|
|
|
|
|
|
|
|
// strncat(x, s, c) -> strcat(x, s)
|
|
|
|
// s is constant so the strcat can be optimized further
|
2009-04-12 18:22:33 +00:00
|
|
|
EmitStrLenMemCpy(Src, Dst, SrcLen, B);
|
2008-05-01 06:25:24 +00:00
|
|
|
return Dst;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strchr' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrChrOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Verify the "strchr" function prototype.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getReturnType() != Type::getInt8PtrTy(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
FT->getParamType(0) != FT->getReturnType())
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *SrcStr = CI->getOperand(1);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If the second operand is non-constant, see if we can compute the length
|
|
|
|
// of the input string and turn this into memchr.
|
|
|
|
ConstantInt *CharC = dyn_cast<ConstantInt>(CI->getOperand(2));
|
|
|
|
if (CharC == 0) {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
uint64_t Len = GetStringLength(SrcStr);
|
2009-10-05 05:54:46 +00:00
|
|
|
if (Len == 0 ||
|
|
|
|
FT->getParamType(1) != Type::getInt32Ty(*Context)) // memchr needs i32.
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
return EmitMemChr(SrcStr, CI->getOperand(2), // include nul.
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), Len), B);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, the character is a constant, see if the first argument is
|
|
|
|
// a string literal. If so, we can constant fold.
|
2009-03-13 04:39:26 +00:00
|
|
|
std::string Str;
|
|
|
|
if (!GetConstantStringInfo(SrcStr, Str))
|
2008-05-01 06:39:12 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// strchr can find the nul character.
|
|
|
|
Str += '\0';
|
|
|
|
char CharValue = CharC->getSExtValue();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Compute the offset.
|
|
|
|
uint64_t i = 0;
|
|
|
|
while (1) {
|
|
|
|
if (i == Str.size()) // Didn't find the char. strchr returns null.
|
2009-07-31 20:28:14 +00:00
|
|
|
return Constant::getNullValue(CI->getType());
|
2008-05-01 06:25:24 +00:00
|
|
|
// Did we find our match?
|
|
|
|
if (Str[i] == CharValue)
|
|
|
|
break;
|
|
|
|
++i;
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// strchr(s+n,c) -> gep(s+n+i,c)
|
2009-08-13 21:58:54 +00:00
|
|
|
Value *Idx = ConstantInt::get(Type::getInt64Ty(*Context), i);
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateGEP(SrcStr, Idx, "strchr");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strcmp' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrCmpOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Verify the "strcmp" function prototype.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
2009-10-07 21:14:25 +00:00
|
|
|
if (FT->getNumParams() != 2 ||
|
|
|
|
FT->getReturnType() != Type::getInt32Ty(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
FT->getParamType(0) != FT->getParamType(1) ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getParamType(0) != Type::getInt8PtrTy(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *Str1P = CI->getOperand(1), *Str2P = CI->getOperand(2);
|
|
|
|
if (Str1P == Str2P) // strcmp(x,x) -> 0
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 0);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-03-13 04:39:26 +00:00
|
|
|
std::string Str1, Str2;
|
|
|
|
bool HasStr1 = GetConstantStringInfo(Str1P, Str1);
|
|
|
|
bool HasStr2 = GetConstantStringInfo(Str2P, Str2);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-03-13 04:39:26 +00:00
|
|
|
if (HasStr1 && Str1.empty()) // strcmp("", x) -> *x
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"), CI->getType());
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-03-13 04:39:26 +00:00
|
|
|
if (HasStr2 && Str2.empty()) // strcmp(x,"") -> *x
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// strcmp(x, y) -> cnst (if both x and y are constant strings)
|
2009-03-13 04:39:26 +00:00
|
|
|
if (HasStr1 && HasStr2)
|
2009-10-07 21:14:25 +00:00
|
|
|
return ConstantInt::get(CI->getType(),
|
2009-07-03 19:42:02 +00:00
|
|
|
strcmp(Str1.c_str(),Str2.c_str()));
|
2008-12-21 00:19:21 +00:00
|
|
|
|
|
|
|
// strcmp(P, "x") -> memcmp(P, "x", 2)
|
|
|
|
uint64_t Len1 = GetStringLength(Str1P);
|
|
|
|
uint64_t Len2 = GetStringLength(Str2P);
|
2009-06-19 04:17:36 +00:00
|
|
|
if (Len1 && Len2) {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-12-21 00:19:21 +00:00
|
|
|
return EmitMemCmp(Str1P, Str2P,
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context),
|
2009-06-19 04:17:36 +00:00
|
|
|
std::min(Len1, Len2)), B);
|
2008-12-21 00:19:21 +00:00
|
|
|
}
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strncmp' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrNCmpOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Verify the "strncmp" function prototype.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
2009-10-07 21:14:25 +00:00
|
|
|
if (FT->getNumParams() != 3 ||
|
|
|
|
FT->getReturnType() != Type::getInt32Ty(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
FT->getParamType(0) != FT->getParamType(1) ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getParamType(0) != Type::getInt8PtrTy(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(2)))
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *Str1P = CI->getOperand(1), *Str2P = CI->getOperand(2);
|
|
|
|
if (Str1P == Str2P) // strncmp(x,x,n) -> 0
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 0);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Get the length argument if it is constant.
|
|
|
|
uint64_t Length;
|
|
|
|
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getOperand(3)))
|
|
|
|
Length = LengthArg->getZExtValue();
|
|
|
|
else
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Length == 0) // strncmp(x,y,0) -> 0
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 0);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-03-13 04:39:26 +00:00
|
|
|
std::string Str1, Str2;
|
|
|
|
bool HasStr1 = GetConstantStringInfo(Str1P, Str1);
|
|
|
|
bool HasStr2 = GetConstantStringInfo(Str2P, Str2);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-03-13 04:39:26 +00:00
|
|
|
if (HasStr1 && Str1.empty()) // strncmp("", x, n) -> *x
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"), CI->getType());
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-03-13 04:39:26 +00:00
|
|
|
if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// strncmp(x, y) -> cnst (if both x and y are constant strings)
|
2009-03-13 04:39:26 +00:00
|
|
|
if (HasStr1 && HasStr2)
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(),
|
2009-03-13 04:39:26 +00:00
|
|
|
strncmp(Str1.c_str(), Str2.c_str(), Length));
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strcpy' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrCpyOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Verify the "strcpy" function prototype.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
FT->getParamType(0) != FT->getParamType(1) ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getParamType(0) != Type::getInt8PtrTy(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *Dst = CI->getOperand(1), *Src = CI->getOperand(2);
|
|
|
|
if (Dst == Src) // strcpy(x,x) -> x
|
|
|
|
return Src;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// See if we can get the length of the input string.
|
|
|
|
uint64_t Len = GetStringLength(Src);
|
2008-05-01 06:39:12 +00:00
|
|
|
if (Len == 0) return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// We have enough information to now generate the memcpy call to do the
|
|
|
|
// concatenation for us. Make a memcpy to copy the nul byte with align = 1.
|
2009-07-03 19:42:02 +00:00
|
|
|
EmitMemCpy(Dst, Src,
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), Len), 1, B);
|
2008-05-01 06:25:24 +00:00
|
|
|
return Dst;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strncpy' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrNCpyOpt : public LibCallOptimization {
|
2009-04-12 05:06:39 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
FT->getParamType(0) != FT->getParamType(1) ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getParamType(0) != Type::getInt8PtrTy(*Context) ||
|
2009-04-12 05:06:39 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(2)))
|
|
|
|
return 0;
|
2008-05-01 06:25:24 +00:00
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
Value *Dst = CI->getOperand(1);
|
|
|
|
Value *Src = CI->getOperand(2);
|
|
|
|
Value *LenOp = CI->getOperand(3);
|
|
|
|
|
|
|
|
// See if we can get the length of the input string.
|
|
|
|
uint64_t SrcLen = GetStringLength(Src);
|
|
|
|
if (SrcLen == 0) return 0;
|
|
|
|
--SrcLen;
|
|
|
|
|
|
|
|
if (SrcLen == 0) {
|
|
|
|
// strncpy(x, "", y) -> memset(x, '\0', y, 1)
|
2009-10-07 21:14:25 +00:00
|
|
|
EmitMemSet(Dst, ConstantInt::get(Type::getInt8Ty(*Context), '\0'), LenOp,
|
|
|
|
B);
|
2009-04-12 05:06:39 +00:00
|
|
|
return Dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t Len;
|
|
|
|
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(LenOp))
|
|
|
|
Len = LengthArg->getZExtValue();
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (Len == 0) return Dst; // strncpy(x, y, 0) -> x
|
|
|
|
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2009-04-12 05:06:39 +00:00
|
|
|
// Let strncpy handle the zero padding
|
|
|
|
if (Len > SrcLen+1) return 0;
|
|
|
|
|
|
|
|
// strncpy(x, s, c) -> memcpy(x, s, c, 1) [s and c are constant]
|
2009-07-03 19:42:02 +00:00
|
|
|
EmitMemCpy(Dst, Src,
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), Len), 1, B);
|
2009-04-12 05:06:39 +00:00
|
|
|
|
|
|
|
return Dst;
|
|
|
|
}
|
|
|
|
};
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strlen' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrLenOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 1 ||
|
2009-10-06 15:40:36 +00:00
|
|
|
FT->getParamType(0) != Type::getInt8PtrTy(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
!isa<IntegerType>(FT->getReturnType()))
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *Src = CI->getOperand(1);
|
|
|
|
|
|
|
|
// Constant folding: strlen("xyz") -> 3
|
|
|
|
if (uint64_t Len = GetStringLength(Src))
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), Len-1);
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
// strlen(x) != 0 --> *x != 0
|
|
|
|
// strlen(x) == 0 --> *x == 0
|
2009-12-23 23:24:51 +00:00
|
|
|
if (IsOnlyUsedInZeroEqualityComparison(CI))
|
|
|
|
return B.CreateZExt(B.CreateLoad(Src, "strlenfirst"), CI->getType());
|
|
|
|
return 0;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-02-13 15:31:46 +00:00
|
|
|
//===---------------------------------------===//
|
2009-12-16 09:32:05 +00:00
|
|
|
// 'strto*' Optimizations. This handles strtol, strtod, strtof, strtoul, etc.
|
2009-02-13 15:31:46 +00:00
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct StrToOpt : public LibCallOptimization {
|
2009-02-13 15:31:46 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if ((FT->getNumParams() != 2 && FT->getNumParams() != 3) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
Value *EndPtr = CI->getOperand(2);
|
2009-02-13 17:08:33 +00:00
|
|
|
if (isa<ConstantPointerNull>(EndPtr)) {
|
|
|
|
CI->setOnlyReadsMemory();
|
2009-02-13 15:31:46 +00:00
|
|
|
CI->addAttribute(1, Attribute::NoCapture);
|
2009-02-13 17:08:33 +00:00
|
|
|
}
|
2009-02-13 15:31:46 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-12-16 09:32:05 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'strstr' Optimizations
|
|
|
|
|
|
|
|
struct StrStrOpt : public LibCallOptimization {
|
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
|
|
|
!isa<PointerType>(FT->getReturnType()))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// fold strstr(x, x) -> x.
|
|
|
|
if (CI->getOperand(1) == CI->getOperand(2))
|
|
|
|
return B.CreateBitCast(CI->getOperand(1), CI->getType());
|
|
|
|
|
|
|
|
// See if either input string is a constant string.
|
|
|
|
std::string SearchStr, ToFindStr;
|
|
|
|
bool HasStr1 = GetConstantStringInfo(CI->getOperand(1), SearchStr);
|
|
|
|
bool HasStr2 = GetConstantStringInfo(CI->getOperand(2), ToFindStr);
|
|
|
|
|
|
|
|
// fold strstr(x, "") -> x.
|
|
|
|
if (HasStr2 && ToFindStr.empty())
|
|
|
|
return B.CreateBitCast(CI->getOperand(1), CI->getType());
|
|
|
|
|
|
|
|
// If both strings are known, constant fold it.
|
|
|
|
if (HasStr1 && HasStr2) {
|
|
|
|
std::string::size_type Offset = SearchStr.find(ToFindStr);
|
|
|
|
|
|
|
|
if (Offset == std::string::npos) // strstr("foo", "bar") -> null
|
|
|
|
return Constant::getNullValue(CI->getType());
|
|
|
|
|
|
|
|
// strstr("abcd", "bc") -> gep((char*)"abcd", 1)
|
|
|
|
Value *Result = CastToCStr(CI->getOperand(1), B);
|
|
|
|
Result = B.CreateConstInBoundsGEP1_64(Result, Offset, "strstr");
|
|
|
|
return B.CreateBitCast(Result, CI->getType());
|
|
|
|
}
|
|
|
|
|
|
|
|
// fold strstr(x, "y") -> strchr(x, 'y').
|
|
|
|
if (HasStr2 && ToFindStr.size() == 1)
|
|
|
|
return B.CreateBitCast(EmitStrChr(CI->getOperand(1), ToFindStr[0], B),
|
|
|
|
CI->getType());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-02-13 15:31:46 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memcmp' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct MemCmpOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 3 || !isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getReturnType() != Type::getInt32Ty(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2008-05-19 09:27:24 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *LHS = CI->getOperand(1), *RHS = CI->getOperand(2);
|
2008-05-19 09:27:24 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (LHS == RHS) // memcmp(s,s,x) -> 0
|
2009-07-31 20:28:14 +00:00
|
|
|
return Constant::getNullValue(CI->getType());
|
2008-05-19 09:27:24 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Make sure we have a constant length.
|
|
|
|
ConstantInt *LenC = dyn_cast<ConstantInt>(CI->getOperand(3));
|
2008-05-01 06:39:12 +00:00
|
|
|
if (!LenC) return 0;
|
2008-05-01 06:25:24 +00:00
|
|
|
uint64_t Len = LenC->getZExtValue();
|
2008-05-19 09:27:24 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Len == 0) // memcmp(s1,s2,0) -> 0
|
2009-07-31 20:28:14 +00:00
|
|
|
return Constant::getNullValue(CI->getType());
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
if (Len == 1) { // memcmp(S1,S2,1) -> *LHS - *RHS
|
|
|
|
Value *LHSV = B.CreateLoad(CastToCStr(LHS, B), "lhsv");
|
|
|
|
Value *RHSV = B.CreateLoad(CastToCStr(RHS, B), "rhsv");
|
2009-05-30 18:43:04 +00:00
|
|
|
return B.CreateSExt(B.CreateSub(LHSV, RHSV, "chardiff"), CI->getType());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2008-05-19 09:27:24 +00:00
|
|
|
|
2009-11-05 17:44:22 +00:00
|
|
|
// Constant folding: memcmp(x, y, l) -> cnst (all arguments are constant)
|
|
|
|
std::string LHSStr, RHSStr;
|
|
|
|
if (GetConstantStringInfo(LHS, LHSStr) &&
|
|
|
|
GetConstantStringInfo(RHS, RHSStr)) {
|
|
|
|
// Make sure we're not reading out-of-bounds memory.
|
|
|
|
if (Len > LHSStr.length() || Len > RHSStr.length())
|
|
|
|
return 0;
|
|
|
|
uint64_t Ret = memcmp(LHSStr.data(), RHSStr.data(), Len);
|
|
|
|
return ConstantInt::get(CI->getType(), Ret);
|
|
|
|
}
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memcpy' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct MemCpyOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getParamType(2) != TD->getIntPtrType(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// memcpy(x, y, n) -> llvm.memcpy(x, y, n, 1)
|
|
|
|
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), 1, B);
|
|
|
|
return CI->getOperand(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-11-30 08:32:11 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memmove' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct MemMoveOpt : public LibCallOptimization {
|
2008-11-30 08:32:11 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-11-30 08:32:11 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getParamType(2) != TD->getIntPtrType(*Context))
|
2008-11-30 08:32:11 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// memmove(x, y, n) -> llvm.memmove(x, y, n, 1)
|
2009-11-21 01:01:30 +00:00
|
|
|
EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), 1, B);
|
2008-11-30 08:32:11 +00:00
|
|
|
return CI->getOperand(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memset' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct MemSetOpt : public LibCallOptimization {
|
2008-11-30 08:32:11 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-11-30 08:32:11 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
2009-07-18 08:34:51 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(1)) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getParamType(2) != TD->getIntPtrType(*Context))
|
2008-11-30 08:32:11 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// memset(p, v, n) -> llvm.memset(p, v, n, 1)
|
2009-10-07 21:14:25 +00:00
|
|
|
Value *Val = B.CreateIntCast(CI->getOperand(2), Type::getInt8Ty(*Context),
|
|
|
|
false);
|
2009-04-12 05:06:39 +00:00
|
|
|
EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B);
|
2008-11-30 08:32:11 +00:00
|
|
|
return CI->getOperand(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-11-21 01:01:30 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Object Size Checking Optimizations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'object size'
|
|
|
|
namespace {
|
|
|
|
struct SizeOpt : public LibCallOptimization {
|
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
// TODO: We can do more with this, but delaying to here should be no change
|
|
|
|
// in behavior.
|
|
|
|
ConstantInt *Const = dyn_cast<ConstantInt>(CI->getOperand(2));
|
|
|
|
|
|
|
|
if (!Const) return 0;
|
|
|
|
|
|
|
|
const Type *Ty = Callee->getFunctionType()->getReturnType();
|
|
|
|
|
2009-12-23 02:51:48 +00:00
|
|
|
if (Const->getZExtValue() == 0)
|
2009-11-21 01:01:30 +00:00
|
|
|
return Constant::getAllOnesValue(Ty);
|
|
|
|
else
|
|
|
|
return ConstantInt::get(Ty, 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memcpy_chk' Optimizations
|
|
|
|
|
|
|
|
struct MemCpyChkOpt : public LibCallOptimization {
|
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
2009-12-22 01:23:51 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(3)) ||
|
|
|
|
FT->getParamType(2) != TD->getIntPtrType(*Context))
|
2009-11-21 01:01:30 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
|
|
|
|
if (!SizeCI)
|
|
|
|
return 0;
|
|
|
|
if (SizeCI->isAllOnesValue()) {
|
|
|
|
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), 1, B);
|
|
|
|
return CI->getOperand(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memset_chk' Optimizations
|
|
|
|
|
|
|
|
struct MemSetChkOpt : public LibCallOptimization {
|
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<IntegerType>(FT->getParamType(1)) ||
|
2009-12-22 01:23:51 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(3)) ||
|
2009-11-21 01:01:30 +00:00
|
|
|
FT->getParamType(2) != TD->getIntPtrType(*Context))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
|
|
|
|
if (!SizeCI)
|
|
|
|
return 0;
|
|
|
|
if (SizeCI->isAllOnesValue()) {
|
|
|
|
Value *Val = B.CreateIntCast(CI->getOperand(2), Type::getInt8Ty(*Context),
|
|
|
|
false);
|
|
|
|
EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B);
|
|
|
|
return CI->getOperand(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'memmove_chk' Optimizations
|
|
|
|
|
|
|
|
struct MemMoveChkOpt : public LibCallOptimization {
|
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
2009-12-22 01:23:51 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(3)) ||
|
2009-11-21 01:01:30 +00:00
|
|
|
FT->getParamType(2) != TD->getIntPtrType(*Context))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
|
|
|
|
if (!SizeCI)
|
|
|
|
return 0;
|
|
|
|
if (SizeCI->isAllOnesValue()) {
|
|
|
|
EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
|
|
|
|
1, B);
|
|
|
|
return CI->getOperand(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Math Library Optimizations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'pow*' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct PowOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// Just make sure this has 2 arguments of the same FP type, which match the
|
|
|
|
// result type.
|
|
|
|
if (FT->getNumParams() != 2 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
FT->getParamType(0) != FT->getParamType(1) ||
|
|
|
|
!FT->getParamType(0)->isFloatingPoint())
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *Op1 = CI->getOperand(1), *Op2 = CI->getOperand(2);
|
|
|
|
if (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
|
|
|
|
if (Op1C->isExactlyValue(1.0)) // pow(1.0, x) -> 1.0
|
|
|
|
return Op1C;
|
|
|
|
if (Op1C->isExactlyValue(2.0)) // pow(2.0, x) -> exp2(x)
|
2009-09-26 18:10:13 +00:00
|
|
|
return EmitUnaryFloatFnCall(Op2, "exp2", B, Callee->getAttributes());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
ConstantFP *Op2C = dyn_cast<ConstantFP>(Op2);
|
|
|
|
if (Op2C == 0) return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Op2C->getValueAPF().isZero()) // pow(x, 0.0) -> 1.0
|
2009-07-27 20:59:43 +00:00
|
|
|
return ConstantFP::get(CI->getType(), 1.0);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Op2C->isExactlyValue(0.5)) {
|
2009-09-25 23:10:17 +00:00
|
|
|
// Expand pow(x, 0.5) to (x == -infinity ? +infinity : fabs(sqrt(x))).
|
|
|
|
// This is faster than calling pow, and still handles negative zero
|
|
|
|
// and negative infinite correctly.
|
|
|
|
// TODO: In fast-math mode, this could be just sqrt(x).
|
|
|
|
// TODO: In finite-only mode, this could be just fabs(sqrt(x)).
|
2009-09-25 23:40:21 +00:00
|
|
|
Value *Inf = ConstantFP::getInfinity(CI->getType());
|
|
|
|
Value *NegInf = ConstantFP::getInfinity(CI->getType(), true);
|
2009-09-26 18:10:13 +00:00
|
|
|
Value *Sqrt = EmitUnaryFloatFnCall(Op1, "sqrt", B,
|
|
|
|
Callee->getAttributes());
|
|
|
|
Value *FAbs = EmitUnaryFloatFnCall(Sqrt, "fabs", B,
|
|
|
|
Callee->getAttributes());
|
2009-09-25 23:10:17 +00:00
|
|
|
Value *FCmp = B.CreateFCmpOEQ(Op1, NegInf, "tmp");
|
|
|
|
Value *Sel = B.CreateSelect(FCmp, Inf, FAbs, "tmp");
|
|
|
|
return Sel;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Op2C->isExactlyValue(1.0)) // pow(x, 1.0) -> x
|
|
|
|
return Op1;
|
|
|
|
if (Op2C->isExactlyValue(2.0)) // pow(x, 2.0) -> x*x
|
2009-06-04 22:49:04 +00:00
|
|
|
return B.CreateFMul(Op1, Op1, "pow2");
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Op2C->isExactlyValue(-1.0)) // pow(x, -1.0) -> 1.0/x
|
2009-07-27 20:59:43 +00:00
|
|
|
return B.CreateFDiv(ConstantFP::get(CI->getType(), 1.0),
|
2009-07-03 19:42:02 +00:00
|
|
|
Op1, "powrecip");
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-05-02 18:43:35 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'exp2' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct Exp2Opt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-02 18:43:35 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// Just make sure this has 1 argument of FP type, which matches the
|
|
|
|
// result type.
|
|
|
|
if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) ||
|
|
|
|
!FT->getParamType(0)->isFloatingPoint())
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-02 18:43:35 +00:00
|
|
|
Value *Op = CI->getOperand(1);
|
|
|
|
// Turn exp2(sitofp(x)) -> ldexp(1.0, sext(x)) if sizeof(x) <= 32
|
|
|
|
// Turn exp2(uitofp(x)) -> ldexp(1.0, zext(x)) if sizeof(x) < 32
|
|
|
|
Value *LdExpArg = 0;
|
|
|
|
if (SIToFPInst *OpC = dyn_cast<SIToFPInst>(Op)) {
|
|
|
|
if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() <= 32)
|
2009-10-07 21:14:25 +00:00
|
|
|
LdExpArg = B.CreateSExt(OpC->getOperand(0),
|
|
|
|
Type::getInt32Ty(*Context), "tmp");
|
2008-05-02 18:43:35 +00:00
|
|
|
} else if (UIToFPInst *OpC = dyn_cast<UIToFPInst>(Op)) {
|
|
|
|
if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() < 32)
|
2009-10-07 21:14:25 +00:00
|
|
|
LdExpArg = B.CreateZExt(OpC->getOperand(0),
|
|
|
|
Type::getInt32Ty(*Context), "tmp");
|
2008-05-02 18:43:35 +00:00
|
|
|
}
|
2009-06-18 20:05:31 +00:00
|
|
|
|
2008-05-02 18:43:35 +00:00
|
|
|
if (LdExpArg) {
|
|
|
|
const char *Name;
|
2009-10-05 05:54:46 +00:00
|
|
|
if (Op->getType()->isFloatTy())
|
2008-05-02 18:43:35 +00:00
|
|
|
Name = "ldexpf";
|
2009-10-05 05:54:46 +00:00
|
|
|
else if (Op->getType()->isDoubleTy())
|
2008-05-02 18:43:35 +00:00
|
|
|
Name = "ldexp";
|
|
|
|
else
|
|
|
|
Name = "ldexpl";
|
|
|
|
|
2009-07-27 20:59:43 +00:00
|
|
|
Constant *One = ConstantFP::get(*Context, APFloat(1.0f));
|
2009-10-05 05:54:46 +00:00
|
|
|
if (!Op->getType()->isFloatTy())
|
2009-07-29 18:55:55 +00:00
|
|
|
One = ConstantExpr::getFPExtend(One, Op->getType());
|
2008-05-02 18:43:35 +00:00
|
|
|
|
|
|
|
Module *M = Caller->getParent();
|
|
|
|
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
|
2009-10-07 21:14:25 +00:00
|
|
|
Op->getType(),
|
|
|
|
Type::getInt32Ty(*Context),NULL);
|
2009-06-18 20:05:31 +00:00
|
|
|
CallInst *CI = B.CreateCall2(Callee, One, LdExpArg);
|
|
|
|
if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
|
|
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
|
|
|
|
return CI;
|
2008-05-02 18:43:35 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// Double -> Float Shrinking Optimizations for Unary Functions like 'floor'
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct UnaryDoubleFPOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
2009-10-05 05:54:46 +00:00
|
|
|
if (FT->getNumParams() != 1 || !FT->getReturnType()->isDoubleTy() ||
|
|
|
|
!FT->getParamType(0)->isDoubleTy())
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-06-18 20:05:31 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If this is something like 'floor((double)floatval)', convert to floorf.
|
|
|
|
FPExtInst *Cast = dyn_cast<FPExtInst>(CI->getOperand(1));
|
2009-10-05 05:54:46 +00:00
|
|
|
if (Cast == 0 || !Cast->getOperand(0)->getType()->isFloatTy())
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// floor((double)floatval) -> (double)floorf(floatval)
|
|
|
|
Value *V = Cast->getOperand(0);
|
2009-09-26 18:10:13 +00:00
|
|
|
V = EmitUnaryFloatFnCall(V, Callee->getName().data(), B,
|
|
|
|
Callee->getAttributes());
|
2009-08-13 21:58:54 +00:00
|
|
|
return B.CreateFPExt(V, Type::getDoubleTy(*Context));
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Integer Optimizations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'ffs*' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct FFSOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// Just make sure this has 2 arguments of the same FP type, which match the
|
|
|
|
// result type.
|
2009-10-07 21:14:25 +00:00
|
|
|
if (FT->getNumParams() != 1 ||
|
|
|
|
FT->getReturnType() != Type::getInt32Ty(*Context) ||
|
2008-05-01 06:25:24 +00:00
|
|
|
!isa<IntegerType>(FT->getParamType(0)))
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
Value *Op = CI->getOperand(1);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Constant fold.
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
|
|
|
|
if (CI->getValue() == 0) // ffs(0) -> 0.
|
2009-07-31 20:28:14 +00:00
|
|
|
return Constant::getNullValue(CI->getType());
|
2009-08-13 21:58:54 +00:00
|
|
|
return ConstantInt::get(Type::getInt32Ty(*Context), // ffs(c) -> cttz(c)+1
|
2008-05-01 06:25:24 +00:00
|
|
|
CI->getValue().countTrailingZeros()+1);
|
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// ffs(x) -> x != 0 ? (i32)llvm.cttz(x)+1 : 0
|
|
|
|
const Type *ArgType = Op->getType();
|
|
|
|
Value *F = Intrinsic::getDeclaration(Callee->getParent(),
|
|
|
|
Intrinsic::cttz, &ArgType, 1);
|
|
|
|
Value *V = B.CreateCall(F, Op, "cttz");
|
2009-07-24 23:12:02 +00:00
|
|
|
V = B.CreateAdd(V, ConstantInt::get(V->getType(), 1), "tmp");
|
2009-08-13 21:58:54 +00:00
|
|
|
V = B.CreateIntCast(V, Type::getInt32Ty(*Context), false, "tmp");
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-07-31 20:28:14 +00:00
|
|
|
Value *Cond = B.CreateICmpNE(Op, Constant::getNullValue(ArgType), "tmp");
|
2009-10-07 21:14:25 +00:00
|
|
|
return B.CreateSelect(Cond, V,
|
|
|
|
ConstantInt::get(Type::getInt32Ty(*Context), 0));
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'isdigit' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct IsDigitOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// We require integer(i32)
|
|
|
|
if (FT->getNumParams() != 1 || !isa<IntegerType>(FT->getReturnType()) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getParamType(0) != Type::getInt32Ty(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// isdigit(c) -> (c-'0') <u 10
|
|
|
|
Value *Op = CI->getOperand(1);
|
2009-10-07 21:14:25 +00:00
|
|
|
Op = B.CreateSub(Op, ConstantInt::get(Type::getInt32Ty(*Context), '0'),
|
2009-07-03 19:42:02 +00:00
|
|
|
"isdigittmp");
|
2009-10-07 21:14:25 +00:00
|
|
|
Op = B.CreateICmpULT(Op, ConstantInt::get(Type::getInt32Ty(*Context), 10),
|
2009-07-03 19:42:02 +00:00
|
|
|
"isdigit");
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateZExt(Op, CI->getType());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'isascii' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct IsAsciiOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// We require integer(i32)
|
|
|
|
if (FT->getNumParams() != 1 || !isa<IntegerType>(FT->getReturnType()) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getParamType(0) != Type::getInt32Ty(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// isascii(c) -> c <u 128
|
|
|
|
Value *Op = CI->getOperand(1);
|
2009-08-13 21:58:54 +00:00
|
|
|
Op = B.CreateICmpULT(Op, ConstantInt::get(Type::getInt32Ty(*Context), 128),
|
2009-07-03 19:42:02 +00:00
|
|
|
"isascii");
|
2008-05-01 06:25:24 +00:00
|
|
|
return B.CreateZExt(Op, CI->getType());
|
|
|
|
}
|
|
|
|
};
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-06-09 08:26:51 +00:00
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'abs', 'labs', 'llabs' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct AbsOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-06-09 08:26:51 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// We require integer(integer) where the types agree.
|
|
|
|
if (FT->getNumParams() != 1 || !isa<IntegerType>(FT->getReturnType()) ||
|
|
|
|
FT->getParamType(0) != FT->getReturnType())
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-06-09 08:26:51 +00:00
|
|
|
// abs(x) -> x >s -1 ? x : -x
|
|
|
|
Value *Op = CI->getOperand(1);
|
2009-10-07 21:14:25 +00:00
|
|
|
Value *Pos = B.CreateICmpSGT(Op,
|
2009-07-31 20:28:14 +00:00
|
|
|
Constant::getAllOnesValue(Op->getType()),
|
2008-06-09 08:26:51 +00:00
|
|
|
"ispos");
|
|
|
|
Value *Neg = B.CreateNeg(Op, "neg");
|
|
|
|
return B.CreateSelect(Pos, Op, Neg);
|
|
|
|
}
|
|
|
|
};
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'toascii' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct ToAsciiOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
// We require i32(i32)
|
|
|
|
if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) ||
|
2009-08-13 21:58:54 +00:00
|
|
|
FT->getParamType(0) != Type::getInt32Ty(*Context))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// isascii(c) -> c & 0x7f
|
2009-07-03 19:42:02 +00:00
|
|
|
return B.CreateAnd(CI->getOperand(1),
|
2009-07-24 23:12:02 +00:00
|
|
|
ConstantInt::get(CI->getType(),0x7F));
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Formatting and IO Optimizations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'printf' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct PrintFOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Require one fixed pointer argument and an integer/void result.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() < 1 || !isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!(isa<IntegerType>(FT->getReturnType()) ||
|
2009-10-05 05:54:46 +00:00
|
|
|
FT->getReturnType()->isVoidTy()))
|
2008-05-01 06:25:24 +00:00
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Check for a fixed format string.
|
2009-03-13 04:39:26 +00:00
|
|
|
std::string FormatStr;
|
|
|
|
if (!GetConstantStringInfo(CI->getOperand(1), FormatStr))
|
|
|
|
return 0;
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
// Empty format string -> noop.
|
|
|
|
if (FormatStr.empty()) // Tolerate printf's declared void.
|
2009-10-07 21:14:25 +00:00
|
|
|
return CI->use_empty() ? (Value*)CI :
|
2009-07-24 23:12:02 +00:00
|
|
|
ConstantInt::get(CI->getType(), 0);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-11-09 04:57:04 +00:00
|
|
|
// printf("x") -> putchar('x'), even for '%'. Return the result of putchar
|
|
|
|
// in case there is an error writing to stdout.
|
2008-05-01 06:25:24 +00:00
|
|
|
if (FormatStr.size() == 1) {
|
2009-11-09 04:57:04 +00:00
|
|
|
Value *Res = EmitPutChar(ConstantInt::get(Type::getInt32Ty(*Context),
|
|
|
|
FormatStr[0]), B);
|
|
|
|
if (CI->use_empty()) return CI;
|
|
|
|
return B.CreateIntCast(Res, CI->getType(), true);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// printf("foo\n") --> puts("foo")
|
|
|
|
if (FormatStr[FormatStr.size()-1] == '\n' &&
|
|
|
|
FormatStr.find('%') == std::string::npos) { // no format characters.
|
|
|
|
// Create a string literal with no \n on it. We expect the constant merge
|
|
|
|
// pass to be run after this pass, to merge duplicate strings.
|
|
|
|
FormatStr.erase(FormatStr.end()-1);
|
2009-08-13 21:58:54 +00:00
|
|
|
Constant *C = ConstantArray::get(*Context, FormatStr, true);
|
2009-07-08 19:03:57 +00:00
|
|
|
C = new GlobalVariable(*Callee->getParent(), C->getType(), true,
|
|
|
|
GlobalVariable::InternalLinkage, C, "str");
|
2008-05-01 06:25:24 +00:00
|
|
|
EmitPutS(C, B);
|
2009-10-07 21:14:25 +00:00
|
|
|
return CI->use_empty() ? (Value*)CI :
|
2009-07-24 23:12:02 +00:00
|
|
|
ConstantInt::get(CI->getType(), FormatStr.size()+1);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Optimize specific format strings.
|
|
|
|
// printf("%c", chr) --> putchar(*(i8*)dst)
|
|
|
|
if (FormatStr == "%c" && CI->getNumOperands() > 2 &&
|
|
|
|
isa<IntegerType>(CI->getOperand(2)->getType())) {
|
2009-11-09 04:57:04 +00:00
|
|
|
Value *Res = EmitPutChar(CI->getOperand(2), B);
|
2009-11-21 01:01:30 +00:00
|
|
|
|
2009-11-09 04:57:04 +00:00
|
|
|
if (CI->use_empty()) return CI;
|
|
|
|
return B.CreateIntCast(Res, CI->getType(), true);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// printf("%s\n", str) --> puts(str)
|
|
|
|
if (FormatStr == "%s\n" && CI->getNumOperands() > 2 &&
|
|
|
|
isa<PointerType>(CI->getOperand(2)->getType()) &&
|
|
|
|
CI->use_empty()) {
|
|
|
|
EmitPutS(CI->getOperand(2), B);
|
|
|
|
return CI;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'sprintf' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct SPrintFOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Require two fixed pointer arguments and an integer result.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 || !isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
|
|
|
!isa<IntegerType>(FT->getReturnType()))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Check for a fixed format string.
|
2009-03-13 04:39:26 +00:00
|
|
|
std::string FormatStr;
|
|
|
|
if (!GetConstantStringInfo(CI->getOperand(2), FormatStr))
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If we just have a format string (nothing else crazy) transform it.
|
|
|
|
if (CI->getNumOperands() == 3) {
|
|
|
|
// Make sure there's no % in the constant array. We could try to handle
|
|
|
|
// %% -> % in the future if we cared.
|
|
|
|
for (unsigned i = 0, e = FormatStr.size(); i != e; ++i)
|
|
|
|
if (FormatStr[i] == '%')
|
|
|
|
return 0; // we found a format specifier, bail out.
|
2009-08-18 00:48:13 +00:00
|
|
|
|
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// sprintf(str, fmt) -> llvm.memcpy(str, fmt, strlen(fmt)+1, 1)
|
|
|
|
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), // Copy the nul byte.
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), FormatStr.size()+1),1,B);
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), FormatStr.size());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// The remaining optimizations require the format string to be "%s" or "%c"
|
|
|
|
// and have an extra operand.
|
|
|
|
if (FormatStr.size() != 2 || FormatStr[0] != '%' || CI->getNumOperands() <4)
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Decode the second character of the format string.
|
|
|
|
if (FormatStr[1] == 'c') {
|
2008-05-01 06:39:12 +00:00
|
|
|
// sprintf(dst, "%c", chr) --> *(i8*)dst = chr; *((i8*)dst+1) = 0
|
2008-05-01 06:25:24 +00:00
|
|
|
if (!isa<IntegerType>(CI->getOperand(3)->getType())) return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
Value *V = B.CreateTrunc(CI->getOperand(3),
|
|
|
|
Type::getInt8Ty(*Context), "char");
|
2008-05-01 06:39:12 +00:00
|
|
|
Value *Ptr = CastToCStr(CI->getOperand(1), B);
|
|
|
|
B.CreateStore(V, Ptr);
|
2009-10-07 21:14:25 +00:00
|
|
|
Ptr = B.CreateGEP(Ptr, ConstantInt::get(Type::getInt32Ty(*Context), 1),
|
|
|
|
"nul");
|
2009-08-13 21:58:54 +00:00
|
|
|
B.CreateStore(Constant::getNullValue(Type::getInt8Ty(*Context)), Ptr);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 1);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (FormatStr[1] == 's') {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// sprintf(dest, "%s", str) -> llvm.memcpy(dest, str, strlen(str)+1, 1)
|
|
|
|
if (!isa<PointerType>(CI->getOperand(3)->getType())) return 0;
|
|
|
|
|
|
|
|
Value *Len = EmitStrLen(CI->getOperand(3), B);
|
2009-07-03 19:42:02 +00:00
|
|
|
Value *IncLen = B.CreateAdd(Len,
|
2009-07-24 23:12:02 +00:00
|
|
|
ConstantInt::get(Len->getType(), 1),
|
2008-05-01 06:25:24 +00:00
|
|
|
"leninc");
|
|
|
|
EmitMemCpy(CI->getOperand(1), CI->getOperand(3), IncLen, 1, B);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// The sprintf result is the unincremented number of bytes in the string.
|
|
|
|
return B.CreateIntCast(Len, CI->getType(), false);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'fwrite' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct FWriteOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Require a pointer, an integer, an integer, a pointer, returning integer.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 4 || !isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<IntegerType>(FT->getParamType(1)) ||
|
|
|
|
!isa<IntegerType>(FT->getParamType(2)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(3)) ||
|
|
|
|
!isa<IntegerType>(FT->getReturnType()))
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Get the element size and count.
|
|
|
|
ConstantInt *SizeC = dyn_cast<ConstantInt>(CI->getOperand(2));
|
|
|
|
ConstantInt *CountC = dyn_cast<ConstantInt>(CI->getOperand(3));
|
|
|
|
if (!SizeC || !CountC) return 0;
|
|
|
|
uint64_t Bytes = SizeC->getZExtValue()*CountC->getZExtValue();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If this is writing zero records, remove the call (it's a noop).
|
|
|
|
if (Bytes == 0)
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 0);
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// If this is writing one byte, turn it into fputc.
|
|
|
|
if (Bytes == 1) { // fwrite(S,1,1,F) -> fputc(S[0],F)
|
|
|
|
Value *Char = B.CreateLoad(CastToCStr(CI->getOperand(1), B), "char");
|
|
|
|
EmitFPutC(Char, CI->getOperand(4), B);
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 1);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'fputs' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct FPutsOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2009-08-18 00:48:13 +00:00
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Require two pointers. Also, we can't optimize if return value is used.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 || !isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
|
|
|
!CI->use_empty())
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// fputs(s,F) --> fwrite(s,1,strlen(s),F)
|
|
|
|
uint64_t Len = GetStringLength(CI->getOperand(1));
|
2008-05-01 06:39:12 +00:00
|
|
|
if (!Len) return 0;
|
2009-07-03 19:42:02 +00:00
|
|
|
EmitFWrite(CI->getOperand(1),
|
2009-08-13 21:58:54 +00:00
|
|
|
ConstantInt::get(TD->getIntPtrType(*Context), Len-1),
|
2008-05-01 06:25:24 +00:00
|
|
|
CI->getOperand(2), B);
|
|
|
|
return CI; // Known to have no uses (see above).
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===---------------------------------------===//
|
|
|
|
// 'fprintf' Optimizations
|
|
|
|
|
2009-09-02 06:11:42 +00:00
|
|
|
struct FPrintFOpt : public LibCallOptimization {
|
2008-08-08 19:39:37 +00:00
|
|
|
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
2008-05-01 06:25:24 +00:00
|
|
|
// Require two fixed paramters as pointers and integer result.
|
|
|
|
const FunctionType *FT = Callee->getFunctionType();
|
|
|
|
if (FT->getNumParams() != 2 || !isa<PointerType>(FT->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FT->getParamType(1)) ||
|
|
|
|
!isa<IntegerType>(FT->getReturnType()))
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// All the optimizations depend on the format string.
|
2009-03-13 04:39:26 +00:00
|
|
|
std::string FormatStr;
|
|
|
|
if (!GetConstantStringInfo(CI->getOperand(2), FormatStr))
|
|
|
|
return 0;
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
// fprintf(F, "foo") --> fwrite("foo", 3, 1, F)
|
|
|
|
if (CI->getNumOperands() == 3) {
|
|
|
|
for (unsigned i = 0, e = FormatStr.size(); i != e; ++i)
|
|
|
|
if (FormatStr[i] == '%') // Could handle %% -> % if we cared.
|
2008-05-01 06:39:12 +00:00
|
|
|
return 0; // We found a format specifier.
|
2009-08-18 00:48:13 +00:00
|
|
|
|
|
|
|
// These optimizations require TargetData.
|
|
|
|
if (!TD) return 0;
|
|
|
|
|
2009-08-13 21:58:54 +00:00
|
|
|
EmitFWrite(CI->getOperand(2), ConstantInt::get(TD->getIntPtrType(*Context),
|
2008-05-01 06:25:24 +00:00
|
|
|
FormatStr.size()),
|
|
|
|
CI->getOperand(1), B);
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), FormatStr.size());
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// The remaining optimizations require the format string to be "%s" or "%c"
|
|
|
|
// and have an extra operand.
|
|
|
|
if (FormatStr.size() != 2 || FormatStr[0] != '%' || CI->getNumOperands() <4)
|
|
|
|
return 0;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Decode the second character of the format string.
|
|
|
|
if (FormatStr[1] == 'c') {
|
|
|
|
// fprintf(F, "%c", chr) --> *(i8*)dst = chr
|
|
|
|
if (!isa<IntegerType>(CI->getOperand(3)->getType())) return 0;
|
|
|
|
EmitFPutC(CI->getOperand(3), CI->getOperand(1), B);
|
2009-07-24 23:12:02 +00:00
|
|
|
return ConstantInt::get(CI->getType(), 1);
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
if (FormatStr[1] == 's') {
|
|
|
|
// fprintf(F, "%s", str) -> fputs(str, F)
|
|
|
|
if (!isa<PointerType>(CI->getOperand(3)->getType()) || !CI->use_empty())
|
|
|
|
return 0;
|
|
|
|
EmitFPutS(CI->getOperand(3), CI->getOperand(1), B);
|
|
|
|
return CI;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-05-05 21:37:59 +00:00
|
|
|
} // end anonymous namespace.
|
2008-05-01 06:25:24 +00:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// 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 {
|
2008-05-01 06:25:24 +00:00
|
|
|
StringMap<LibCallOptimization*> Optimizations;
|
|
|
|
// String and Memory LibCall Optimizations
|
2009-04-12 05:06:39 +00:00
|
|
|
StrCatOpt StrCat; StrNCatOpt StrNCat; StrChrOpt StrChr; StrCmpOpt StrCmp;
|
|
|
|
StrNCmpOpt StrNCmp; StrCpyOpt StrCpy; StrNCpyOpt StrNCpy; StrLenOpt StrLen;
|
2009-12-16 09:32:05 +00:00
|
|
|
StrToOpt StrTo; StrStrOpt StrStr;
|
|
|
|
MemCmpOpt MemCmp; MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet;
|
2008-05-01 06:25:24 +00:00
|
|
|
// Math Library Optimizations
|
2008-05-02 18:43:35 +00:00
|
|
|
PowOpt Pow; Exp2Opt Exp2; UnaryDoubleFPOpt UnaryDoubleFP;
|
2008-05-01 06:25:24 +00:00
|
|
|
// Integer Optimizations
|
2008-06-09 08:26:51 +00:00
|
|
|
FFSOpt FFS; AbsOpt Abs; IsDigitOpt IsDigit; IsAsciiOpt IsAscii;
|
|
|
|
ToAsciiOpt ToAscii;
|
2008-05-01 06:25:24 +00:00
|
|
|
// Formatting and IO Optimizations
|
|
|
|
SPrintFOpt SPrintF; PrintFOpt PrintF;
|
|
|
|
FWriteOpt FWrite; FPutsOpt FPuts; FPrintFOpt FPrintF;
|
2009-11-21 01:01:30 +00:00
|
|
|
|
|
|
|
// Object Size Checking
|
2009-10-27 00:52:25 +00:00
|
|
|
SizeOpt ObjectSize;
|
2009-11-21 01:01:30 +00:00
|
|
|
MemCpyChkOpt MemCpyChk; MemSetChkOpt MemSetChk; MemMoveChkOpt MemMoveChk;
|
2009-01-04 20:27:34 +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
|
2008-09-04 17:05:41 +00:00
|
|
|
SimplifyLibCalls() : FunctionPass(&ID) {}
|
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
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char SimplifyLibCalls::ID = 0;
|
|
|
|
} // end anonymous namespace.
|
|
|
|
|
|
|
|
static RegisterPass<SimplifyLibCalls>
|
|
|
|
X("simplify-libcalls", "Simplify well-known library calls");
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
|
|
/// Optimizations - Populate the Optimizations map with all the optimizations
|
|
|
|
/// we know.
|
|
|
|
void SimplifyLibCalls::InitOptimizations() {
|
|
|
|
// String and Memory LibCall Optimizations
|
|
|
|
Optimizations["strcat"] = &StrCat;
|
2009-04-12 05:06:39 +00:00
|
|
|
Optimizations["strncat"] = &StrNCat;
|
2008-05-01 06:25:24 +00:00
|
|
|
Optimizations["strchr"] = &StrChr;
|
|
|
|
Optimizations["strcmp"] = &StrCmp;
|
|
|
|
Optimizations["strncmp"] = &StrNCmp;
|
|
|
|
Optimizations["strcpy"] = &StrCpy;
|
2009-04-12 05:06:39 +00:00
|
|
|
Optimizations["strncpy"] = &StrNCpy;
|
2008-05-01 06:25:24 +00:00
|
|
|
Optimizations["strlen"] = &StrLen;
|
2009-02-13 15:31:46 +00:00
|
|
|
Optimizations["strtol"] = &StrTo;
|
|
|
|
Optimizations["strtod"] = &StrTo;
|
|
|
|
Optimizations["strtof"] = &StrTo;
|
|
|
|
Optimizations["strtoul"] = &StrTo;
|
|
|
|
Optimizations["strtoll"] = &StrTo;
|
|
|
|
Optimizations["strtold"] = &StrTo;
|
|
|
|
Optimizations["strtoull"] = &StrTo;
|
2009-12-16 09:32:05 +00:00
|
|
|
Optimizations["strstr"] = &StrStr;
|
2008-05-01 06:25:24 +00:00
|
|
|
Optimizations["memcmp"] = &MemCmp;
|
|
|
|
Optimizations["memcpy"] = &MemCpy;
|
2008-11-30 08:32:11 +00:00
|
|
|
Optimizations["memmove"] = &MemMove;
|
|
|
|
Optimizations["memset"] = &MemSet;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Math Library Optimizations
|
|
|
|
Optimizations["powf"] = &Pow;
|
|
|
|
Optimizations["pow"] = &Pow;
|
|
|
|
Optimizations["powl"] = &Pow;
|
2008-09-04 18:30:46 +00:00
|
|
|
Optimizations["llvm.pow.f32"] = &Pow;
|
|
|
|
Optimizations["llvm.pow.f64"] = &Pow;
|
|
|
|
Optimizations["llvm.pow.f80"] = &Pow;
|
|
|
|
Optimizations["llvm.pow.f128"] = &Pow;
|
|
|
|
Optimizations["llvm.pow.ppcf128"] = &Pow;
|
2008-05-02 18:43:35 +00:00
|
|
|
Optimizations["exp2l"] = &Exp2;
|
|
|
|
Optimizations["exp2"] = &Exp2;
|
|
|
|
Optimizations["exp2f"] = &Exp2;
|
2008-09-04 18:30:46 +00:00
|
|
|
Optimizations["llvm.exp2.ppcf128"] = &Exp2;
|
|
|
|
Optimizations["llvm.exp2.f128"] = &Exp2;
|
|
|
|
Optimizations["llvm.exp2.f80"] = &Exp2;
|
|
|
|
Optimizations["llvm.exp2.f64"] = &Exp2;
|
|
|
|
Optimizations["llvm.exp2.f32"] = &Exp2;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
#ifdef HAVE_FLOORF
|
|
|
|
Optimizations["floor"] = &UnaryDoubleFP;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_CEILF
|
|
|
|
Optimizations["ceil"] = &UnaryDoubleFP;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ROUNDF
|
|
|
|
Optimizations["round"] = &UnaryDoubleFP;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_RINTF
|
|
|
|
Optimizations["rint"] = &UnaryDoubleFP;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NEARBYINTF
|
|
|
|
Optimizations["nearbyint"] = &UnaryDoubleFP;
|
|
|
|
#endif
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Integer Optimizations
|
|
|
|
Optimizations["ffs"] = &FFS;
|
|
|
|
Optimizations["ffsl"] = &FFS;
|
|
|
|
Optimizations["ffsll"] = &FFS;
|
2008-06-09 08:26:51 +00:00
|
|
|
Optimizations["abs"] = &Abs;
|
|
|
|
Optimizations["labs"] = &Abs;
|
|
|
|
Optimizations["llabs"] = &Abs;
|
2008-05-01 06:25:24 +00:00
|
|
|
Optimizations["isdigit"] = &IsDigit;
|
|
|
|
Optimizations["isascii"] = &IsAscii;
|
|
|
|
Optimizations["toascii"] = &ToAscii;
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Formatting and IO Optimizations
|
|
|
|
Optimizations["sprintf"] = &SPrintF;
|
|
|
|
Optimizations["printf"] = &PrintF;
|
|
|
|
Optimizations["fwrite"] = &FWrite;
|
|
|
|
Optimizations["fputs"] = &FPuts;
|
|
|
|
Optimizations["fprintf"] = &FPrintF;
|
2009-11-21 01:01:30 +00:00
|
|
|
|
|
|
|
// Object Size Checking
|
|
|
|
Optimizations["llvm.objectsize.i32"] = &ObjectSize;
|
|
|
|
Optimizations["llvm.objectsize.i64"] = &ObjectSize;
|
|
|
|
Optimizations["__memcpy_chk"] = &MemCpyChk;
|
|
|
|
Optimizations["__memset_chk"] = &MemSetChk;
|
|
|
|
Optimizations["__memmove_chk"] = &MemMoveChk;
|
2008-05-01 06:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// runOnFunction - Top level algorithm.
|
|
|
|
///
|
|
|
|
bool SimplifyLibCalls::runOnFunction(Function &F) {
|
|
|
|
if (Optimizations.empty())
|
|
|
|
InitOptimizations();
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2009-08-18 00:48:13 +00:00
|
|
|
const TargetData *TD = getAnalysisIfAvailable<TargetData>();
|
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
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Try to optimize this call.
|
2009-07-26 08:34:35 +00:00
|
|
|
Value *Result = LCO->OptimizeCall(CI, TD, Builder);
|
2008-05-01 06:25:24 +00:00
|
|
|
if (Result == 0) continue;
|
|
|
|
|
2009-07-26 08:34:35 +00:00
|
|
|
DEBUG(errs() << "SimplifyLibCalls simplified: " << *CI;
|
|
|
|
errs() << " into: " << *Result << "\n");
|
2009-10-07 21:14:25 +00:00
|
|
|
|
2008-05-01 06:25:24 +00:00
|
|
|
// Something changed!
|
|
|
|
Changed = true;
|
|
|
|
++NumSimplified;
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
if (!F.isDeclaration())
|
|
|
|
continue;
|
|
|
|
|
2009-07-26 07:49:05 +00:00
|
|
|
if (!F.hasName())
|
2009-01-04 20:27:34 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
const FunctionType *FTy = F.getFunctionType();
|
|
|
|
|
2009-07-26 07:49:05 +00:00
|
|
|
StringRef Name = F.getName();
|
|
|
|
switch (Name[0]) {
|
2009-01-04 20:27:34 +00:00
|
|
|
case 's':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "strlen") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "strcpy" ||
|
|
|
|
Name == "stpcpy" ||
|
|
|
|
Name == "strcat" ||
|
|
|
|
Name == "strtol" ||
|
|
|
|
Name == "strtod" ||
|
|
|
|
Name == "strtof" ||
|
|
|
|
Name == "strtoul" ||
|
|
|
|
Name == "strtoll" ||
|
|
|
|
Name == "strtold" ||
|
|
|
|
Name == "strncat" ||
|
|
|
|
Name == "strncpy" ||
|
|
|
|
Name == "strtoull") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "strxfrm") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "strcmp" ||
|
|
|
|
Name == "strspn" ||
|
|
|
|
Name == "strncmp" ||
|
|
|
|
Name ==" strcspn" ||
|
|
|
|
Name == "strcoll" ||
|
|
|
|
Name == "strcasecmp" ||
|
|
|
|
Name == "strncasecmp") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "strstr" ||
|
|
|
|
Name == "strpbrk") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "strtok" ||
|
|
|
|
Name == "strtok_r") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "scanf" ||
|
|
|
|
Name == "setbuf" ||
|
|
|
|
Name == "setvbuf") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "strdup" ||
|
|
|
|
Name == "strndup") {
|
2009-01-05 00:07:50 +00:00
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "stat" ||
|
|
|
|
Name == "sscanf" ||
|
|
|
|
Name == "sprintf" ||
|
|
|
|
Name == "statvfs") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "snprintf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(2)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 3);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "setitimer") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(2)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
setDoesNotCapture(F, 3);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "system") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
// May throw; "system" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'm':
|
2009-09-18 22:35:49 +00:00
|
|
|
if (Name == "malloc") {
|
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
} else if (Name == "memcmp") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "memchr" ||
|
|
|
|
Name == "memrchr") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3)
|
|
|
|
continue;
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotThrow(F);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "modf" ||
|
|
|
|
Name == "modff" ||
|
|
|
|
Name == "modfl" ||
|
|
|
|
Name == "memcpy" ||
|
|
|
|
Name == "memccpy" ||
|
|
|
|
Name == "memmove") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "memalign") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotAlias(F, 0);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "mkdir" ||
|
|
|
|
Name == "mktime") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() == 0 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "realloc") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "read") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
// May throw; "read" is a valid pthread cancellation point.
|
2009-01-04 20:27:34 +00:00
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "rmdir" ||
|
|
|
|
Name == "rewind" ||
|
|
|
|
Name == "remove" ||
|
|
|
|
Name == "realpath") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() < 1 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "rename" ||
|
|
|
|
Name == "readlink") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'w':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "write") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
// May throw; "write" is a valid pthread cancellation point.
|
2009-01-04 20:27:34 +00:00
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'b':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "bcopy") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "bcmp") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "bzero") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "calloc") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "chmod" ||
|
|
|
|
Name == "chown" ||
|
|
|
|
Name == "ctermid" ||
|
|
|
|
Name == "clearerr" ||
|
|
|
|
Name == "closedir") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() == 0 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "atoi" ||
|
|
|
|
Name == "atol" ||
|
|
|
|
Name == "atof" ||
|
|
|
|
Name == "atoll") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setOnlyReadsMemory(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "access") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "fopen") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
2009-01-04 20:27:34 +00:00
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "fdopen") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} 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") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() == 0 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "ferror") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setOnlyReadsMemory(F);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "fputc" ||
|
|
|
|
Name == "fstat" ||
|
|
|
|
Name == "frexp" ||
|
|
|
|
Name == "frexpf" ||
|
|
|
|
Name == "frexpl" ||
|
|
|
|
Name == "fstatvfs") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "fgets") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(2)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 3);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "fread" ||
|
|
|
|
Name == "fwrite") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() != 4 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(3)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 4);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "fputs" ||
|
|
|
|
Name == "fscanf" ||
|
|
|
|
Name == "fprintf" ||
|
|
|
|
Name == "fgetpos") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'g':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "getc" ||
|
|
|
|
Name == "getlogin_r" ||
|
|
|
|
Name == "getc_unlocked") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (FTy->getNumParams() == 0 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "getenv") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setOnlyReadsMemory(F);
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "gets" ||
|
|
|
|
Name == "getchar") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
setDoesNotThrow(F);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "getitimer") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "getpwnam") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'u':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "ungetc") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "uname" ||
|
|
|
|
Name == "unlink" ||
|
|
|
|
Name == "unsetenv") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "utime" ||
|
|
|
|
Name == "utimes") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'p':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "putc") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "puts" ||
|
|
|
|
Name == "printf" ||
|
|
|
|
Name == "perror") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "pread" ||
|
|
|
|
Name == "pwrite") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 4 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
// May throw; these are valid pthread cancellation points.
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "putchar") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
setDoesNotThrow(F);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "popen") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "pclose") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'v':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "vscanf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "vsscanf" ||
|
|
|
|
Name == "vfscanf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
2009-01-04 20:27:34 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(1)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(2)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "valloc") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "vprintf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "vfprintf" ||
|
|
|
|
Name == "vsprintf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "vsnprintf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 4 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(2)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 3);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'o':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "open") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
// May throw; "open" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "opendir") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
2009-01-04 20:27:34 +00:00
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
2009-02-15 22:47:25 +00:00
|
|
|
setDoesNotCapture(F, 1);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "tmpfile") {
|
2009-01-04 20:27:34 +00:00
|
|
|
if (!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "times") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-01-04 20:27:34 +00:00
|
|
|
}
|
2009-02-15 22:47:25 +00:00
|
|
|
break;
|
2009-01-04 20:27:34 +00:00
|
|
|
case 'h':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "htonl" ||
|
|
|
|
Name == "htons") {
|
2009-01-04 20:27:34 +00:00
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAccessMemory(F);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'n':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "ntohl" ||
|
|
|
|
Name == "ntohs") {
|
2009-01-04 20:27:34 +00:00
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAccessMemory(F);
|
|
|
|
}
|
2009-02-15 22:47:25 +00:00
|
|
|
break;
|
|
|
|
case 'l':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "lstat") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "lchown") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'q':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "qsort") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 4 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(3)))
|
|
|
|
continue;
|
|
|
|
// May throw; places call through function pointer.
|
|
|
|
setDoesNotCapture(F, 4);
|
|
|
|
}
|
|
|
|
break;
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
case '_':
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "__strdup" ||
|
|
|
|
Name == "__strndup") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "__strtok_r") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 3 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "_IO_getc") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "_IO_putc") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 2);
|
|
|
|
}
|
2009-02-15 22:47:25 +00:00
|
|
|
break;
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
case 1:
|
2009-07-26 07:49:05 +00:00
|
|
|
if (Name == "\1__isoc99_scanf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() < 1 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "\1stat64" ||
|
|
|
|
Name == "\1lstat64" ||
|
|
|
|
Name == "\1statvfs64" ||
|
|
|
|
Name == "\1__isoc99_sscanf") {
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
if (FTy->getNumParams() < 1 ||
|
2009-02-15 22:47:25 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "\1fopen64") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getReturnType()) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)) ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
|
|
|
setDoesNotCapture(F, 1);
|
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "\1fseeko64" ||
|
|
|
|
Name == "\1ftello64") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() == 0 ||
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotCapture(F, 1);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "\1tmpfile64") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (!isa<PointerType>(FTy->getReturnType()))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
|
|
|
setDoesNotAlias(F, 0);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "\1fstat64" ||
|
|
|
|
Name == "\1fstatvfs64") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() != 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(1)))
|
|
|
|
continue;
|
|
|
|
setDoesNotThrow(F);
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
setDoesNotCapture(F, 2);
|
2009-07-26 07:49:05 +00:00
|
|
|
} else if (Name == "\1open64") {
|
2009-02-15 22:47:25 +00:00
|
|
|
if (FTy->getNumParams() < 2 ||
|
|
|
|
!isa<PointerType>(FTy->getParamType(0)))
|
|
|
|
continue;
|
|
|
|
// May throw; "open" is a valid pthread cancellation point.
|
|
|
|
setDoesNotCapture(F, 1);
|
Fix copy and pasted typos that prevented strtok_r, realloc, getenv, ungetc,
putc, puts, perror, vscanf and vsscanf from getting annotations.
Add annotations for eight printf functions, memalign, pread and pwrite.
On Linux, llvm-gcc sometimes renames strdup, getc, putc, strtok_r, scanf and
sscanf. Match the alternate function names.
Fix a crash annotating opendir.
Don't mark fsetpos's second parameter as nocapture. It's supposed to be
captured.
Do mark fopen's path and mode strings as nocapture. Mark ferror as readonly,
but not fileno which may set errno.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62456 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-18 04:34:36 +00:00
|
|
|
}
|
2009-01-04 20:27:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
//
|
|
|
|
// cos, cosf, cosl:
|
|
|
|
// * cos(-x) -> cos(x)
|
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
// puts:
|
|
|
|
// * puts("") -> putchar("\n")
|
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
// stpcpy:
|
|
|
|
// * stpcpy(str, "literal") ->
|
|
|
|
// llvm.memcpy(str,"literal",strlen("literal")+1,1)
|
|
|
|
// strrchr:
|
|
|
|
// * strrchr(s,c) -> reverse_offset_of_in(c,s)
|
|
|
|
// (if c is a constant integer and s is a constant string)
|
|
|
|
// * strrchr(s1,0) -> strchr(s1,0)
|
|
|
|
//
|
|
|
|
// strpbrk:
|
|
|
|
// * strpbrk(s,a) -> offset_in_for(s,a)
|
|
|
|
// (if s and a are both constant strings)
|
|
|
|
// * strpbrk(s,"") -> 0
|
|
|
|
// * strpbrk(s,a) -> strchr(s,a[0]) (if a is constant string of length 1)
|
|
|
|
//
|
|
|
|
// strspn, strcspn:
|
|
|
|
// * strspn(s,a) -> const_int (if both args are constant)
|
|
|
|
// * strspn("",a) -> 0
|
|
|
|
// * strspn(s,"") -> 0
|
|
|
|
// * strcspn(s,a) -> const_int (if both args are constant)
|
|
|
|
// * strcspn("",a) -> 0
|
|
|
|
// * strcspn(s,"") -> strlen(a)
|
|
|
|
//
|
|
|
|
// tan, tanf, tanl:
|
|
|
|
// * tan(atan(x)) -> x
|
|
|
|
//
|
|
|
|
// trunc, truncf, truncl:
|
|
|
|
// * trunc(cnst) -> cnst'
|
|
|
|
//
|
|
|
|
//
|