mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-16 23:38:40 +00:00
[SimplifyLibCalls] Factor out fortified libcall handling.
This lets us remove CGP duplicate. Differential Revision: http://reviews.llvm.org/D6541 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225640 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
fe2d64e0f6
commit
2cec3e9c11
@ -115,20 +115,6 @@ namespace llvm {
|
||||
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
||||
Value *EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B,
|
||||
const DataLayout *TD, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// SimplifyFortifiedLibCalls - Helper class for folding checked library
|
||||
/// calls (e.g. __strcpy_chk) into their unchecked counterparts.
|
||||
class SimplifyFortifiedLibCalls {
|
||||
protected:
|
||||
CallInst *CI;
|
||||
virtual void replaceCall(Value *With) = 0;
|
||||
virtual bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp,
|
||||
bool isString) const = 0;
|
||||
|
||||
public:
|
||||
virtual ~SimplifyFortifiedLibCalls();
|
||||
bool fold(CallInst *CI, const DataLayout *TD, const TargetLibraryInfo *TLI);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -27,11 +27,46 @@ class TargetLibraryInfo;
|
||||
class BasicBlock;
|
||||
class Function;
|
||||
|
||||
/// \brief This class implements simplifications for calls to fortified library
|
||||
/// functions (__st*cpy_chk, __memcpy_chk, __memmove_chk, __memset_chk), to,
|
||||
/// when possible, replace them with their non-checking counterparts.
|
||||
/// Other optimizations can also be done, but it's possible to disable them and
|
||||
/// only simplify needless use of the checking versions (when the object size
|
||||
/// is unknown) by passing true for OnlyLowerUnknownSize.
|
||||
class FortifiedLibCallSimplifier {
|
||||
private:
|
||||
const DataLayout *DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
bool OnlyLowerUnknownSize;
|
||||
|
||||
public:
|
||||
FortifiedLibCallSimplifier(const DataLayout *DL, const TargetLibraryInfo *TLI,
|
||||
bool OnlyLowerUnknownSize = false);
|
||||
|
||||
/// \brief Take the given call instruction and return a more
|
||||
/// optimal value to replace the instruction with or 0 if a more
|
||||
/// optimal form can't be found.
|
||||
Value *optimizeCall(CallInst *CI);
|
||||
|
||||
private:
|
||||
Value *optimizeMemCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeMemMoveChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeMemSetChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeStrCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeStrNCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
|
||||
/// \brief Checks whether the call \p CI to a fortified libcall is foldable
|
||||
/// to the non-fortified version.
|
||||
bool isFortifiedCallFoldable(CallInst *CI, unsigned ObjSizeOp,
|
||||
unsigned SizeOp, bool isString);
|
||||
};
|
||||
|
||||
/// LibCallSimplifier - This class implements a collection of optimizations
|
||||
/// that replace well formed calls to library functions with a more optimal
|
||||
/// form. For example, replacing 'printf("Hello!")' with 'puts("Hello!")'.
|
||||
class LibCallSimplifier {
|
||||
private:
|
||||
FortifiedLibCallSimplifier FortifiedSimplifier;
|
||||
const DataLayout *DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
bool UnsafeFPShrink;
|
||||
@ -56,14 +91,6 @@ public:
|
||||
virtual void replaceAllUsesWith(Instruction *I, Value *With) const;
|
||||
|
||||
private:
|
||||
// Fortified Library Call Optimizations
|
||||
Value *optimizeMemCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeMemMoveChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeMemSetChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeStrCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeStpCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeStrNCpyChk(CallInst *CI, IRBuilder<> &B);
|
||||
|
||||
// String and Memory Library Call Optimizations
|
||||
Value *optimizeStrCat(CallInst *CI, IRBuilder<> &B);
|
||||
Value *optimizeStrNCat(CallInst *CI, IRBuilder<> &B);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
||||
#include "llvm/Transforms/Utils/BypassSlowDivision.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/SimplifyLibCalls.h"
|
||||
using namespace llvm;
|
||||
using namespace llvm::PatternMatch;
|
||||
|
||||
@ -847,22 +848,6 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class CodeGenPrepareFortifiedLibCalls : public SimplifyFortifiedLibCalls {
|
||||
protected:
|
||||
void replaceCall(Value *With) override {
|
||||
CI->replaceAllUsesWith(With);
|
||||
CI->eraseFromParent();
|
||||
}
|
||||
bool isFoldable(unsigned SizeCIOp, unsigned, bool) const override {
|
||||
if (ConstantInt *SizeCI =
|
||||
dyn_cast<ConstantInt>(CI->getArgOperand(SizeCIOp)))
|
||||
return SizeCI->isAllOnesValue();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// ScalarizeMaskedLoad() translates masked load intrinsic, like
|
||||
// <16 x i32 > @llvm.masked.load( <16 x i32>* %addr, i32 align,
|
||||
// <16 x i1> %mask, <16 x i32> %passthru)
|
||||
@ -1152,10 +1137,15 @@ bool CodeGenPrepare::OptimizeCallInst(CallInst *CI, bool& ModifiedDT) {
|
||||
|
||||
// Lower all default uses of _chk calls. This is very similar
|
||||
// to what InstCombineCalls does, but here we are only lowering calls
|
||||
// that have the default "don't know" as the objectsize. Anything else
|
||||
// should be left alone.
|
||||
CodeGenPrepareFortifiedLibCalls Simplifier;
|
||||
return Simplifier.fold(CI, TD, TLInfo);
|
||||
// to fortified library functions (e.g. __memcpy_chk) that have the default
|
||||
// "don't know" as the objectsize. Anything else should be left alone.
|
||||
FortifiedLibCallSimplifier Simplifier(TD, TLInfo, true);
|
||||
if (Value *V = Simplifier.optimizeCall(CI)) {
|
||||
CI->replaceAllUsesWith(V);
|
||||
CI->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// DupRetToEnableTailCallOpts - Look for opportunities to duplicate return
|
||||
|
@ -486,135 +486,3 @@ Value *llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File,
|
||||
CI->setCallingConv(Fn->getCallingConv());
|
||||
return CI;
|
||||
}
|
||||
|
||||
SimplifyFortifiedLibCalls::~SimplifyFortifiedLibCalls() { }
|
||||
|
||||
bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const DataLayout *TD,
|
||||
const TargetLibraryInfo *TLI) {
|
||||
// We really need DataLayout for later.
|
||||
if (!TD) return false;
|
||||
|
||||
this->CI = CI;
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef Name = Callee->getName();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getParent()->getContext();
|
||||
IRBuilder<> B(CI);
|
||||
|
||||
if (Name == "__memcpy_chk") {
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
!FT->getParamType(0)->isPointerTy() ||
|
||||
!FT->getParamType(1)->isPointerTy() ||
|
||||
FT->getParamType(2) != TD->getIntPtrType(Context) ||
|
||||
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||||
return false;
|
||||
|
||||
if (isFoldable(3, 2, false)) {
|
||||
B.CreateMemCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), 1);
|
||||
replaceCall(CI->getArgOperand(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Should be similar to memcpy.
|
||||
if (Name == "__mempcpy_chk") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Name == "__memmove_chk") {
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
!FT->getParamType(0)->isPointerTy() ||
|
||||
!FT->getParamType(1)->isPointerTy() ||
|
||||
FT->getParamType(2) != TD->getIntPtrType(Context) ||
|
||||
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||||
return false;
|
||||
|
||||
if (isFoldable(3, 2, false)) {
|
||||
B.CreateMemMove(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), 1);
|
||||
replaceCall(CI->getArgOperand(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Name == "__memset_chk") {
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
!FT->getParamType(0)->isPointerTy() ||
|
||||
!FT->getParamType(1)->isIntegerTy() ||
|
||||
FT->getParamType(2) != TD->getIntPtrType(Context) ||
|
||||
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||||
return false;
|
||||
|
||||
if (isFoldable(3, 2, false)) {
|
||||
Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(),
|
||||
false);
|
||||
B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), 1);
|
||||
replaceCall(CI->getArgOperand(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") {
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 3 ||
|
||||
FT->getReturnType() != FT->getParamType(0) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != Type::getInt8PtrTy(Context) ||
|
||||
FT->getParamType(2) != TD->getIntPtrType(Context))
|
||||
return 0;
|
||||
|
||||
|
||||
// If a) we don't have any length information, or b) we know this will
|
||||
// fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our
|
||||
// st[rp]cpy_chk call which may fail at runtime if the size is too long.
|
||||
// TODO: It might be nice to get a maximum length out of the possible
|
||||
// string lengths for varying.
|
||||
if (isFoldable(2, 1, true)) {
|
||||
Value *Ret = EmitStrCpy(CI->getArgOperand(0), CI->getArgOperand(1), B, TD,
|
||||
TLI, Name.substr(2, 6));
|
||||
if (!Ret)
|
||||
return false;
|
||||
replaceCall(Ret);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Name == "__strncpy_chk" || Name == "__stpncpy_chk") {
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != Type::getInt8PtrTy(Context) ||
|
||||
!FT->getParamType(2)->isIntegerTy() ||
|
||||
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||||
return false;
|
||||
|
||||
if (isFoldable(3, 2, false)) {
|
||||
Value *Ret = EmitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), B, TD, TLI,
|
||||
Name.substr(2, 7));
|
||||
if (!Ret)
|
||||
return false;
|
||||
replaceCall(Ret);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Name == "__strcat_chk") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Name == "__strncat_chk") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -180,209 +180,6 @@ static bool checkStringCopyLibFuncSignature(Function *F, LibFunc::Func Func,
|
||||
return true;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Fortified Library Call Optimizations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static bool isFortifiedCallFoldable(CallInst *CI, unsigned SizeCIOp, unsigned SizeArgOp,
|
||||
bool isString) {
|
||||
if (CI->getArgOperand(SizeCIOp) == CI->getArgOperand(SizeArgOp))
|
||||
return true;
|
||||
if (ConstantInt *SizeCI =
|
||||
dyn_cast<ConstantInt>(CI->getArgOperand(SizeCIOp))) {
|
||||
if (SizeCI->isAllOnesValue())
|
||||
return true;
|
||||
if (isString) {
|
||||
uint64_t Len = GetStringLength(CI->getArgOperand(SizeArgOp));
|
||||
// If the length is 0 we don't know how long it is and so we can't
|
||||
// remove the check.
|
||||
if (Len == 0)
|
||||
return false;
|
||||
return SizeCI->getZExtValue() >= Len;
|
||||
}
|
||||
if (ConstantInt *Arg = dyn_cast<ConstantInt>(CI->getArgOperand(SizeArgOp)))
|
||||
return SizeCI->getZExtValue() >= Arg->getZExtValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifier::optimizeMemCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getContext();
|
||||
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
!FT->getParamType(0)->isPointerTy() ||
|
||||
!FT->getParamType(1)->isPointerTy() ||
|
||||
FT->getParamType(2) != DL->getIntPtrType(Context) ||
|
||||
FT->getParamType(3) != DL->getIntPtrType(Context))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
B.CreateMemCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), 1);
|
||||
return CI->getArgOperand(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifier::optimizeMemMoveChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getContext();
|
||||
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
!FT->getParamType(0)->isPointerTy() ||
|
||||
!FT->getParamType(1)->isPointerTy() ||
|
||||
FT->getParamType(2) != DL->getIntPtrType(Context) ||
|
||||
FT->getParamType(3) != DL->getIntPtrType(Context))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
B.CreateMemMove(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), 1);
|
||||
return CI->getArgOperand(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifier::optimizeMemSetChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getContext();
|
||||
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
!FT->getParamType(0)->isPointerTy() ||
|
||||
!FT->getParamType(1)->isIntegerTy() ||
|
||||
FT->getParamType(2) != DL->getIntPtrType(Context) ||
|
||||
FT->getParamType(3) != DL->getIntPtrType(Context))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false);
|
||||
B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), 1);
|
||||
return CI->getArgOperand(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifier::optimizeStrCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef Name = Callee->getName();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getContext();
|
||||
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != Type::getInt8PtrTy(Context) ||
|
||||
FT->getParamType(2) != DL->getIntPtrType(Context))
|
||||
return nullptr;
|
||||
|
||||
Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1);
|
||||
if (Dst == Src) // __strcpy_chk(x,x) -> x
|
||||
return Src;
|
||||
|
||||
// If a) we don't have any length information, or b) we know this will
|
||||
// fit then just lower to a plain strcpy. Otherwise we'll keep our
|
||||
// strcpy_chk call which may fail at runtime if the size is too long.
|
||||
// TODO: It might be nice to get a maximum length out of the possible
|
||||
// string lengths for varying.
|
||||
if (isFortifiedCallFoldable(CI, 2, 1, true)) {
|
||||
Value *Ret = EmitStrCpy(Dst, Src, B, DL, TLI, Name.substr(2, 6));
|
||||
return Ret;
|
||||
} else {
|
||||
// Maybe we can stil fold __strcpy_chk to __memcpy_chk.
|
||||
uint64_t Len = GetStringLength(Src);
|
||||
if (Len == 0)
|
||||
return nullptr;
|
||||
|
||||
// This optimization require DataLayout.
|
||||
if (!DL)
|
||||
return nullptr;
|
||||
|
||||
Value *Ret = EmitMemCpyChk(
|
||||
Dst, Src, ConstantInt::get(DL->getIntPtrType(Context), Len),
|
||||
CI->getArgOperand(2), B, DL, TLI);
|
||||
return Ret;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifier::optimizeStpCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef Name = Callee->getName();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getContext();
|
||||
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != Type::getInt8PtrTy(Context) ||
|
||||
FT->getParamType(2) != DL->getIntPtrType(FT->getParamType(0)))
|
||||
return nullptr;
|
||||
|
||||
Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1);
|
||||
if (Dst == Src) { // stpcpy(x,x) -> x+strlen(x)
|
||||
Value *StrLen = EmitStrLen(Src, B, DL, TLI);
|
||||
return StrLen ? B.CreateInBoundsGEP(Dst, StrLen) : nullptr;
|
||||
}
|
||||
|
||||
// If a) we don't have any length information, or b) we know this will
|
||||
// fit then just lower to a plain stpcpy. Otherwise we'll keep our
|
||||
// stpcpy_chk call which may fail at runtime if the size is too long.
|
||||
// TODO: It might be nice to get a maximum length out of the possible
|
||||
// string lengths for varying.
|
||||
if (isFortifiedCallFoldable(CI, 2, 1, true)) {
|
||||
Value *Ret = EmitStrCpy(Dst, Src, B, DL, TLI, Name.substr(2, 6));
|
||||
return Ret;
|
||||
} else {
|
||||
// Maybe we can stil fold __stpcpy_chk to __memcpy_chk.
|
||||
uint64_t Len = GetStringLength(Src);
|
||||
if (Len == 0)
|
||||
return nullptr;
|
||||
|
||||
// This optimization require DataLayout.
|
||||
if (!DL)
|
||||
return nullptr;
|
||||
|
||||
Type *PT = FT->getParamType(0);
|
||||
Value *LenV = ConstantInt::get(DL->getIntPtrType(PT), Len);
|
||||
Value *DstEnd =
|
||||
B.CreateGEP(Dst, ConstantInt::get(DL->getIntPtrType(PT), Len - 1));
|
||||
if (!EmitMemCpyChk(Dst, Src, LenV, CI->getArgOperand(2), B, DL, TLI))
|
||||
return nullptr;
|
||||
return DstEnd;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifier::optimizeStrNCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef Name = Callee->getName();
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
LLVMContext &Context = CI->getContext();
|
||||
|
||||
// Check if this has the right signature.
|
||||
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != Type::getInt8PtrTy(Context) ||
|
||||
!FT->getParamType(2)->isIntegerTy() ||
|
||||
FT->getParamType(3) != DL->getIntPtrType(Context))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
Value *Ret =
|
||||
EmitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), B, DL, TLI, Name.substr(2, 7));
|
||||
return Ret;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String and Memory Library Call Optimizations
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -2166,6 +1963,15 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
|
||||
}
|
||||
}
|
||||
|
||||
// Also try to simplify calls to fortified library functions.
|
||||
if (Value *SimplifiedFortifiedCI = FortifiedSimplifier.optimizeCall(CI)) {
|
||||
// Try to further simplify the result.
|
||||
if (CallInst *SimplifiedCI = dyn_cast<CallInst>(SimplifiedFortifiedCI))
|
||||
if (Value *V = optimizeStringMemoryLibCall(SimplifiedCI, Builder))
|
||||
return V;
|
||||
return SimplifiedFortifiedCI;
|
||||
}
|
||||
|
||||
// Then check for known library functions.
|
||||
if (TLI->getLibFunc(FuncName, Func) && TLI->has(Func)) {
|
||||
// We never change the calling convention.
|
||||
@ -2270,29 +2076,16 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
|
||||
if (hasFloatVersion(FuncName))
|
||||
return optimizeBinaryDoubleFP(CI, Builder);
|
||||
return nullptr;
|
||||
case LibFunc::memcpy_chk:
|
||||
return optimizeMemCpyChk(CI, Builder);
|
||||
case LibFunc::memmove_chk:
|
||||
return optimizeMemMoveChk(CI, Builder);
|
||||
case LibFunc::memset_chk:
|
||||
return optimizeMemSetChk(CI, Builder);
|
||||
case LibFunc::strcpy_chk:
|
||||
return optimizeStrCpyChk(CI, Builder);
|
||||
case LibFunc::stpcpy_chk:
|
||||
return optimizeStpCpyChk(CI, Builder);
|
||||
case LibFunc::stpncpy_chk:
|
||||
case LibFunc::strncpy_chk:
|
||||
return optimizeStrNCpyChk(CI, Builder);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LibCallSimplifier::LibCallSimplifier(const DataLayout *DL,
|
||||
const TargetLibraryInfo *TLI) :
|
||||
FortifiedSimplifier(DL, TLI),
|
||||
DL(DL),
|
||||
TLI(TLI),
|
||||
UnsafeFPShrink(false) {
|
||||
@ -2350,3 +2143,184 @@ void LibCallSimplifier::replaceAllUsesWith(Instruction *I, Value *With) const {
|
||||
// * trunc(cnst) -> cnst'
|
||||
//
|
||||
//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Fortified Library Call Optimizations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool FortifiedLibCallSimplifier::isFortifiedCallFoldable(CallInst *CI,
|
||||
unsigned ObjSizeOp,
|
||||
unsigned SizeOp,
|
||||
bool isString) {
|
||||
if (CI->getArgOperand(ObjSizeOp) == CI->getArgOperand(SizeOp))
|
||||
return true;
|
||||
if (ConstantInt *ObjSizeCI =
|
||||
dyn_cast<ConstantInt>(CI->getArgOperand(ObjSizeOp))) {
|
||||
if (ObjSizeCI->isAllOnesValue())
|
||||
return true;
|
||||
// If the object size wasn't -1 (unknown), bail out if we were asked to.
|
||||
if (OnlyLowerUnknownSize)
|
||||
return false;
|
||||
if (isString) {
|
||||
uint64_t Len = GetStringLength(CI->getArgOperand(SizeOp));
|
||||
// If the length is 0 we don't know how long it is and so we can't
|
||||
// remove the check.
|
||||
if (Len == 0)
|
||||
return false;
|
||||
return ObjSizeCI->getZExtValue() >= Len;
|
||||
}
|
||||
if (ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getArgOperand(SizeOp)))
|
||||
return ObjSizeCI->getZExtValue() >= SizeCI->getZExtValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Value *FortifiedLibCallSimplifier::optimizeMemCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
|
||||
if (!checkStringCopyLibFuncSignature(Callee, LibFunc::memcpy_chk, DL))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
B.CreateMemCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), 1);
|
||||
return CI->getArgOperand(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *FortifiedLibCallSimplifier::optimizeMemMoveChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
|
||||
if (!checkStringCopyLibFuncSignature(Callee, LibFunc::memmove_chk, DL))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
B.CreateMemMove(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), 1);
|
||||
return CI->getArgOperand(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
|
||||
if (!checkStringCopyLibFuncSignature(Callee, LibFunc::memset_chk, DL))
|
||||
return nullptr;
|
||||
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false);
|
||||
B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), 1);
|
||||
return CI->getArgOperand(0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *FortifiedLibCallSimplifier::optimizeStrCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef Name = Callee->getName();
|
||||
LibFunc::Func Func =
|
||||
Name.startswith("str") ? LibFunc::strcpy_chk : LibFunc::stpcpy_chk;
|
||||
|
||||
if (!checkStringCopyLibFuncSignature(Callee, Func, DL))
|
||||
return nullptr;
|
||||
|
||||
Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1),
|
||||
*ObjSize = CI->getArgOperand(2);
|
||||
|
||||
// __stpcpy_chk(x,x,...) -> x+strlen(x)
|
||||
if (!OnlyLowerUnknownSize && Dst == Src) {
|
||||
Value *StrLen = EmitStrLen(Src, B, DL, TLI);
|
||||
return StrLen ? B.CreateInBoundsGEP(Dst, StrLen) : nullptr;
|
||||
}
|
||||
|
||||
// If a) we don't have any length information, or b) we know this will
|
||||
// fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our
|
||||
// st[rp]cpy_chk call which may fail at runtime if the size is too long.
|
||||
// TODO: It might be nice to get a maximum length out of the possible
|
||||
// string lengths for varying.
|
||||
if (isFortifiedCallFoldable(CI, 2, 1, true)) {
|
||||
Value *Ret = EmitStrCpy(Dst, Src, B, DL, TLI, Name.substr(2, 6));
|
||||
return Ret;
|
||||
} else if (!OnlyLowerUnknownSize) {
|
||||
// Maybe we can stil fold __st[rp]cpy_chk to __memcpy_chk.
|
||||
uint64_t Len = GetStringLength(Src);
|
||||
if (Len == 0)
|
||||
return nullptr;
|
||||
|
||||
// This optimization requires DataLayout.
|
||||
if (!DL)
|
||||
return nullptr;
|
||||
|
||||
Type *SizeTTy = DL->getIntPtrType(CI->getContext());
|
||||
Value *LenV = ConstantInt::get(SizeTTy, Len);
|
||||
Value *Ret = EmitMemCpyChk(Dst, Src, LenV, ObjSize, B, DL, TLI);
|
||||
// If the function was an __stpcpy_chk, and we were able to fold it into
|
||||
// a __memcpy_chk, we still need to return the correct end pointer.
|
||||
if (Ret && Func == LibFunc::stpcpy_chk)
|
||||
return B.CreateGEP(Dst, ConstantInt::get(SizeTTy, Len - 1));
|
||||
return Ret;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *FortifiedLibCallSimplifier::optimizeStrNCpyChk(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef Name = Callee->getName();
|
||||
LibFunc::Func Func =
|
||||
Name.startswith("str") ? LibFunc::strncpy_chk : LibFunc::stpncpy_chk;
|
||||
|
||||
if (!checkStringCopyLibFuncSignature(Callee, Func, DL))
|
||||
return nullptr;
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
Value *Ret =
|
||||
EmitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), B, DL, TLI, Name.substr(2, 7));
|
||||
return Ret;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *FortifiedLibCallSimplifier::optimizeCall(CallInst *CI) {
|
||||
if (CI->isNoBuiltin())
|
||||
return nullptr;
|
||||
|
||||
LibFunc::Func Func;
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
StringRef FuncName = Callee->getName();
|
||||
IRBuilder<> Builder(CI);
|
||||
bool isCallingConvC = CI->getCallingConv() == llvm::CallingConv::C;
|
||||
|
||||
// First, check that this is a known library functions.
|
||||
if (!TLI->getLibFunc(FuncName, Func) || !TLI->has(Func))
|
||||
return nullptr;
|
||||
|
||||
// We never change the calling convention.
|
||||
if (!ignoreCallingConv(Func) && !isCallingConvC)
|
||||
return nullptr;
|
||||
|
||||
switch (Func) {
|
||||
case LibFunc::memcpy_chk:
|
||||
return optimizeMemCpyChk(CI, Builder);
|
||||
case LibFunc::memmove_chk:
|
||||
return optimizeMemMoveChk(CI, Builder);
|
||||
case LibFunc::memset_chk:
|
||||
return optimizeMemSetChk(CI, Builder);
|
||||
case LibFunc::stpcpy_chk:
|
||||
case LibFunc::strcpy_chk:
|
||||
return optimizeStrCpyChk(CI, Builder);
|
||||
case LibFunc::stpncpy_chk:
|
||||
case LibFunc::strncpy_chk:
|
||||
return optimizeStrNCpyChk(CI, Builder);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FortifiedLibCallSimplifier::
|
||||
FortifiedLibCallSimplifier(const DataLayout *DL, const TargetLibraryInfo *TLI,
|
||||
bool OnlyLowerUnknownSize)
|
||||
: DL(DL), TLI(TLI), OnlyLowerUnknownSize(OnlyLowerUnknownSize) {
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user