mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 19:31:58 +00:00
Implement new LibCallSimplifier class
This patch implements the new LibCallSimplifier class as outlined in [1]. In addition to providing the new base library simplification infrastructure, all the fortified library call simplifications were moved over to the new infrastructure. The rest of the library simplification optimizations will be moved over with follow up patches. NOTE: The original fortified library call simplifier located in the SimplifyFortifiedLibCalls class was not removed because it is still used by CodeGenPrepare. This class will eventually go away too. [1] http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-August/052283.html git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165873 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
af89690760
commit
5e8904576a
43
include/llvm/Transforms/Utils/SimplifyLibCalls.h
Normal file
43
include/llvm/Transforms/Utils/SimplifyLibCalls.h
Normal file
@ -0,0 +1,43 @@
|
||||
//===- SimplifyLibCalls.h - Library call simplifier -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file exposes an interface to build some C language libcalls for
|
||||
// optimization passes that need to call the various functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_SIMPLIFYLIBCALLS_H
|
||||
#define LLVM_TRANSFORMS_UTILS_SIMPLIFYLIBCALLS_H
|
||||
|
||||
namespace llvm {
|
||||
class Value;
|
||||
class CallInst;
|
||||
class DataLayout;
|
||||
class TargetLibraryInfo;
|
||||
class LibCallSimplifierImpl;
|
||||
|
||||
/// 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 {
|
||||
/// Impl - A pointer to the actual implementation of the library call
|
||||
/// simplifier.
|
||||
LibCallSimplifierImpl *Impl;
|
||||
public:
|
||||
LibCallSimplifier(const DataLayout *TD, const TargetLibraryInfo *TLI);
|
||||
virtual ~LibCallSimplifier();
|
||||
|
||||
/// optimizeCall - 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);
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Support/InstVisitor.h"
|
||||
#include "llvm/Support/TargetFolder.h"
|
||||
#include "llvm/Transforms/Utils/SimplifyLibCalls.h"
|
||||
|
||||
namespace llvm {
|
||||
class CallSite;
|
||||
@ -74,6 +75,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner
|
||||
DataLayout *TD;
|
||||
TargetLibraryInfo *TLI;
|
||||
bool MadeIRChange;
|
||||
LibCallSimplifier *Simplifier;
|
||||
public:
|
||||
/// Worklist - All of the instructions that need to be simplified.
|
||||
InstCombineWorklist Worklist;
|
||||
|
@ -778,39 +778,6 @@ static bool isSafeToEliminateVarargsCast(const CallSite CS,
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class InstCombineFortifiedLibCalls : public SimplifyFortifiedLibCalls {
|
||||
InstCombiner *IC;
|
||||
protected:
|
||||
void replaceCall(Value *With) {
|
||||
NewInstruction = IC->ReplaceInstUsesWith(*CI, With);
|
||||
}
|
||||
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;
|
||||
}
|
||||
public:
|
||||
InstCombineFortifiedLibCalls(InstCombiner *IC) : IC(IC), NewInstruction(0) { }
|
||||
Instruction *NewInstruction;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// Try to fold some different type of calls here.
|
||||
// Currently we're only working with the checking functions, memcpy_chk,
|
||||
// mempcpy_chk, memmove_chk, memset_chk, strcpy_chk, stpcpy_chk, strncpy_chk,
|
||||
@ -818,9 +785,10 @@ public:
|
||||
Instruction *InstCombiner::tryOptimizeCall(CallInst *CI, const DataLayout *TD) {
|
||||
if (CI->getCalledFunction() == 0) return 0;
|
||||
|
||||
InstCombineFortifiedLibCalls Simplifier(this);
|
||||
Simplifier.fold(CI, TD, TLI);
|
||||
return Simplifier.NewInstruction;
|
||||
if (Value *With = Simplifier->optimizeCall(CI))
|
||||
return ReplaceInstUsesWith(*CI, With);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static IntrinsicInst *FindInitTrampolineFromAlloca(Value *TrampMem) {
|
||||
|
@ -2130,6 +2130,9 @@ bool InstCombiner::runOnFunction(Function &F) {
|
||||
InstCombineIRInserter(Worklist));
|
||||
Builder = &TheBuilder;
|
||||
|
||||
LibCallSimplifier TheSimplifier(TD, TLI);
|
||||
Simplifier = &TheSimplifier;
|
||||
|
||||
bool EverMadeChange = false;
|
||||
|
||||
// Lower dbg.declare intrinsics otherwise their value may be clobbered
|
||||
|
@ -28,6 +28,7 @@ add_llvm_library(LLVMTransformUtils
|
||||
SimplifyCFG.cpp
|
||||
SimplifyIndVar.cpp
|
||||
SimplifyInstructions.cpp
|
||||
SimplifyLibCalls.cpp
|
||||
UnifyFunctionExitNodes.cpp
|
||||
Utils.cpp
|
||||
ValueMapper.cpp
|
||||
|
289
lib/Transforms/Utils/SimplifyLibCalls.cpp
Normal file
289
lib/Transforms/Utils/SimplifyLibCalls.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
//===------ 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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user