mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-14 21:16:04 +00:00
290 lines
9.9 KiB
C++
290 lines
9.9 KiB
C++
![]() |
//===------ SimplifyLibCalls.cpp - Library calls simplifier ---------------===//
|
||
|
//
|
||
|
// The LLVM Compiler Infrastructure
|
||
|
//
|
||
|
// This file is distributed under the University of Illinois Open Source
|
||
|
// License. See LICENSE.TXT for details.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// This is a utility pass used for testing the InstructionSimplify analysis.
|
||
|
// The analysis is applied to every instruction, and if it simplifies then the
|
||
|
// instruction is replaced by the simplification. If you are looking for a pass
|
||
|
// that performs serious instruction folding, use the instcombine pass instead.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "llvm/Transforms/Utils/SimplifyLibCalls.h"
|
||
|
#include "llvm/DataLayout.h"
|
||
|
#include "llvm/ADT/StringMap.h"
|
||
|
#include "llvm/Analysis/ValueTracking.h"
|
||
|
#include "llvm/Function.h"
|
||
|
#include "llvm/IRBuilder.h"
|
||
|
#include "llvm/LLVMContext.h"
|
||
|
#include "llvm/Target/TargetLibraryInfo.h"
|
||
|
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
/// This class is the abstract base class for the set of optimizations that
|
||
|
/// corresponds to one library call.
|
||
|
namespace {
|
||
|
class LibCallOptimization {
|
||
|
protected:
|
||
|
Function *Caller;
|
||
|
const DataLayout *TD;
|
||
|
const TargetLibraryInfo *TLI;
|
||
|
LLVMContext* Context;
|
||
|
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.
|
||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B)
|
||
|
=0;
|
||
|
|
||
|
Value *optimizeCall(CallInst *CI, const DataLayout *TD,
|
||
|
const TargetLibraryInfo *TLI, IRBuilder<> &B) {
|
||
|
Caller = CI->getParent()->getParent();
|
||
|
this->TD = TD;
|
||
|
this->TLI = TLI;
|
||
|
if (CI->getCalledFunction())
|
||
|
Context = &CI->getCalledFunction()->getContext();
|
||
|
|
||
|
// We never change the calling convention.
|
||
|
if (CI->getCallingConv() != llvm::CallingConv::C)
|
||
|
return NULL;
|
||
|
|
||
|
return callOptimizer(CI->getCalledFunction(), CI, B);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Fortified Library Call Optimizations
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
struct FortifiedLibCallOptimization : public LibCallOptimization {
|
||
|
protected:
|
||
|
virtual bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp,
|
||
|
bool isString) const = 0;
|
||
|
};
|
||
|
|
||
|
struct InstFortifiedLibCallOptimization : public FortifiedLibCallOptimization {
|
||
|
CallInst *CI;
|
||
|
|
||
|
bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp, bool isString) const {
|
||
|
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;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct MemCpyChkOpt : public InstFortifiedLibCallOptimization {
|
||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||
|
this->CI = CI;
|
||
|
FunctionType *FT = Callee->getFunctionType();
|
||
|
LLVMContext &Context = CI->getParent()->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) != TD->getIntPtrType(Context) ||
|
||
|
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||
|
return 0;
|
||
|
|
||
|
if (isFoldable(3, 2, false)) {
|
||
|
B.CreateMemCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||
|
CI->getArgOperand(2), 1);
|
||
|
return CI->getArgOperand(0);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct MemMoveChkOpt : public InstFortifiedLibCallOptimization {
|
||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||
|
this->CI = CI;
|
||
|
FunctionType *FT = Callee->getFunctionType();
|
||
|
LLVMContext &Context = CI->getParent()->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) != TD->getIntPtrType(Context) ||
|
||
|
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||
|
return 0;
|
||
|
|
||
|
if (isFoldable(3, 2, false)) {
|
||
|
B.CreateMemMove(CI->getArgOperand(0), CI->getArgOperand(1),
|
||
|
CI->getArgOperand(2), 1);
|
||
|
return CI->getArgOperand(0);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct MemSetChkOpt : public InstFortifiedLibCallOptimization {
|
||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||
|
this->CI = CI;
|
||
|
FunctionType *FT = Callee->getFunctionType();
|
||
|
LLVMContext &Context = CI->getParent()->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) != TD->getIntPtrType(Context) ||
|
||
|
FT->getParamType(3) != TD->getIntPtrType(Context))
|
||
|
return 0;
|
||
|
|
||
|
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);
|
||
|
return CI->getArgOperand(0);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct StrCpyChkOpt : public InstFortifiedLibCallOptimization {
|
||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||
|
this->CI = CI;
|
||
|
StringRef Name = Callee->getName();
|
||
|
FunctionType *FT = Callee->getFunctionType();
|
||
|
LLVMContext &Context = CI->getParent()->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) != 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));
|
||
|
return Ret;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct StrNCpyChkOpt : public InstFortifiedLibCallOptimization {
|
||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||
|
this->CI = CI;
|
||
|
StringRef Name = Callee->getName();
|
||
|
FunctionType *FT = Callee->getFunctionType();
|
||
|
LLVMContext &Context = CI->getParent()->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) != TD->getIntPtrType(Context))
|
||
|
return 0;
|
||
|
|
||
|
if (isFoldable(3, 2, false)) {
|
||
|
Value *Ret = EmitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||
|
CI->getArgOperand(2), B, TD, TLI,
|
||
|
Name.substr(2, 7));
|
||
|
return Ret;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // End anonymous namespace.
|
||
|
|
||
|
namespace llvm {
|
||
|
|
||
|
class LibCallSimplifierImpl {
|
||
|
LibCallSimplifier *Simplifier;
|
||
|
const DataLayout *TD;
|
||
|
const TargetLibraryInfo *TLI;
|
||
|
StringMap<LibCallOptimization*> Optimizations;
|
||
|
|
||
|
// Fortified library call optimizations.
|
||
|
MemCpyChkOpt MemCpyChk;
|
||
|
MemMoveChkOpt MemMoveChk;
|
||
|
MemSetChkOpt MemSetChk;
|
||
|
StrCpyChkOpt StrCpyChk;
|
||
|
StrNCpyChkOpt StrNCpyChk;
|
||
|
|
||
|
void initOptimizations();
|
||
|
public:
|
||
|
LibCallSimplifierImpl(const DataLayout *TD, const TargetLibraryInfo *TLI) {
|
||
|
this->TD = TD;
|
||
|
this->TLI = TLI;
|
||
|
}
|
||
|
|
||
|
Value *optimizeCall(CallInst *CI);
|
||
|
};
|
||
|
|
||
|
void LibCallSimplifierImpl::initOptimizations() {
|
||
|
// Fortified library call optimizations.
|
||
|
Optimizations["__memcpy_chk"] = &MemCpyChk;
|
||
|
Optimizations["__memmove_chk"] = &MemMoveChk;
|
||
|
Optimizations["__memset_chk"] = &MemSetChk;
|
||
|
Optimizations["__strcpy_chk"] = &StrCpyChk;
|
||
|
Optimizations["__stpcpy_chk"] = &StrCpyChk;
|
||
|
Optimizations["__strncpy_chk"] = &StrNCpyChk;
|
||
|
Optimizations["__stpncpy_chk"] = &StrNCpyChk;
|
||
|
}
|
||
|
|
||
|
Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {
|
||
|
if (Optimizations.empty())
|
||
|
initOptimizations();
|
||
|
|
||
|
Function *Callee = CI->getCalledFunction();
|
||
|
LibCallOptimization *LCO = Optimizations.lookup(Callee->getName());
|
||
|
if (LCO) {
|
||
|
IRBuilder<> Builder(CI);
|
||
|
return LCO->optimizeCall(CI, TD, TLI, Builder);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LibCallSimplifier::LibCallSimplifier(const DataLayout *TD,
|
||
|
const TargetLibraryInfo *TLI) {
|
||
|
Impl = new LibCallSimplifierImpl(TD, TLI);
|
||
|
}
|
||
|
|
||
|
LibCallSimplifier::~LibCallSimplifier() {
|
||
|
delete Impl;
|
||
|
}
|
||
|
|
||
|
Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
|
||
|
return Impl->optimizeCall(CI);
|
||
|
}
|
||
|
|
||
|
}
|