mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-13 22:24:07 +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:
@ -115,20 +115,6 @@ namespace llvm {
|
|||||||
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
||||||
Value *EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B,
|
Value *EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B,
|
||||||
const DataLayout *TD, const TargetLibraryInfo *TLI);
|
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
|
#endif
|
||||||
|
@ -27,11 +27,46 @@ class TargetLibraryInfo;
|
|||||||
class BasicBlock;
|
class BasicBlock;
|
||||||
class Function;
|
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
|
/// LibCallSimplifier - This class implements a collection of optimizations
|
||||||
/// that replace well formed calls to library functions with a more optimal
|
/// that replace well formed calls to library functions with a more optimal
|
||||||
/// form. For example, replacing 'printf("Hello!")' with 'puts("Hello!")'.
|
/// form. For example, replacing 'printf("Hello!")' with 'puts("Hello!")'.
|
||||||
class LibCallSimplifier {
|
class LibCallSimplifier {
|
||||||
private:
|
private:
|
||||||
|
FortifiedLibCallSimplifier FortifiedSimplifier;
|
||||||
const DataLayout *DL;
|
const DataLayout *DL;
|
||||||
const TargetLibraryInfo *TLI;
|
const TargetLibraryInfo *TLI;
|
||||||
bool UnsafeFPShrink;
|
bool UnsafeFPShrink;
|
||||||
@ -56,14 +91,6 @@ public:
|
|||||||
virtual void replaceAllUsesWith(Instruction *I, Value *With) const;
|
virtual void replaceAllUsesWith(Instruction *I, Value *With) const;
|
||||||
|
|
||||||
private:
|
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
|
// String and Memory Library Call Optimizations
|
||||||
Value *optimizeStrCat(CallInst *CI, IRBuilder<> &B);
|
Value *optimizeStrCat(CallInst *CI, IRBuilder<> &B);
|
||||||
Value *optimizeStrNCat(CallInst *CI, IRBuilder<> &B);
|
Value *optimizeStrNCat(CallInst *CI, IRBuilder<> &B);
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
||||||
#include "llvm/Transforms/Utils/BypassSlowDivision.h"
|
#include "llvm/Transforms/Utils/BypassSlowDivision.h"
|
||||||
#include "llvm/Transforms/Utils/Local.h"
|
#include "llvm/Transforms/Utils/Local.h"
|
||||||
|
#include "llvm/Transforms/Utils/SimplifyLibCalls.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::PatternMatch;
|
using namespace llvm::PatternMatch;
|
||||||
|
|
||||||
@ -847,22 +848,6 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,
|
|||||||
return MadeChange;
|
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
|
// ScalarizeMaskedLoad() translates masked load intrinsic, like
|
||||||
// <16 x i32 > @llvm.masked.load( <16 x i32>* %addr, i32 align,
|
// <16 x i32 > @llvm.masked.load( <16 x i32>* %addr, i32 align,
|
||||||
// <16 x i1> %mask, <16 x i32> %passthru)
|
// <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
|
// Lower all default uses of _chk calls. This is very similar
|
||||||
// to what InstCombineCalls does, but here we are only lowering calls
|
// to what InstCombineCalls does, but here we are only lowering calls
|
||||||
// that have the default "don't know" as the objectsize. Anything else
|
// to fortified library functions (e.g. __memcpy_chk) that have the default
|
||||||
// should be left alone.
|
// "don't know" as the objectsize. Anything else should be left alone.
|
||||||
CodeGenPrepareFortifiedLibCalls Simplifier;
|
FortifiedLibCallSimplifier Simplifier(TD, TLInfo, true);
|
||||||
return Simplifier.fold(CI, TD, TLInfo);
|
if (Value *V = Simplifier.optimizeCall(CI)) {
|
||||||
|
CI->replaceAllUsesWith(V);
|
||||||
|
CI->eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DupRetToEnableTailCallOpts - Look for opportunities to duplicate return
|
/// DupRetToEnableTailCallOpts - Look for opportunities to duplicate return
|
||||||
|
@ -486,135 +486,3 @@ Value *llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File,
|
|||||||
CI->setCallingConv(Fn->getCallingConv());
|
CI->setCallingConv(Fn->getCallingConv());
|
||||||
return CI;
|
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;
|
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
|
// 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.
|
// Then check for known library functions.
|
||||||
if (TLI->getLibFunc(FuncName, Func) && TLI->has(Func)) {
|
if (TLI->getLibFunc(FuncName, Func) && TLI->has(Func)) {
|
||||||
// We never change the calling convention.
|
// We never change the calling convention.
|
||||||
@ -2270,29 +2076,16 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
|
|||||||
if (hasFloatVersion(FuncName))
|
if (hasFloatVersion(FuncName))
|
||||||
return optimizeBinaryDoubleFP(CI, Builder);
|
return optimizeBinaryDoubleFP(CI, Builder);
|
||||||
return nullptr;
|
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:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
LibCallSimplifier::LibCallSimplifier(const DataLayout *DL,
|
LibCallSimplifier::LibCallSimplifier(const DataLayout *DL,
|
||||||
const TargetLibraryInfo *TLI) :
|
const TargetLibraryInfo *TLI) :
|
||||||
|
FortifiedSimplifier(DL, TLI),
|
||||||
DL(DL),
|
DL(DL),
|
||||||
TLI(TLI),
|
TLI(TLI),
|
||||||
UnsafeFPShrink(false) {
|
UnsafeFPShrink(false) {
|
||||||
@ -2350,3 +2143,184 @@ void LibCallSimplifier::replaceAllUsesWith(Instruction *I, Value *With) const {
|
|||||||
// * trunc(cnst) -> cnst'
|
// * 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) {
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user