[llvm-commits] [PATCH 1/3] Implement new LibCallSimplifier class
Eric Christopher
echristo at gmail.com
Fri Oct 12 15:19:36 PDT 2012
LGTM.
One case of CallOptimizer->callOptimizer in a comment needed :)
-eric
On Mon, Oct 8, 2012 at 8:25 AM, Meador Inge <meadori at codesourcery.com> wrote:
> 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
> ---
> include/llvm/Transforms/Utils/SimplifyLibCalls.h | 43 +++
> lib/Transforms/InstCombine/InstCombine.h | 2 +
> lib/Transforms/InstCombine/InstCombineCalls.cpp | 40 +--
> .../InstCombine/InstructionCombining.cpp | 3 +
> lib/Transforms/Utils/CMakeLists.txt | 1 +
> lib/Transforms/Utils/SimplifyLibCalls.cpp | 289 ++++++++++++++++++++
> 6 files changed, 342 insertions(+), 36 deletions(-)
> create mode 100644 include/llvm/Transforms/Utils/SimplifyLibCalls.h
> create mode 100644 lib/Transforms/Utils/SimplifyLibCalls.cpp
>
> diff --git a/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/include/llvm/Transforms/Utils/SimplifyLibCalls.h
> new file mode 100644
> index 0000000..621aec5
> --- /dev/null
> +++ b/include/llvm/Transforms/Utils/SimplifyLibCalls.h
> @@ -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 TargetData;
> + 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 TargetData *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
> diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h
> index 0d5ef90..7fca1b7 100644
> --- a/lib/Transforms/InstCombine/InstCombine.h
> +++ b/lib/Transforms/InstCombine/InstCombine.h
> @@ -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
> TargetData *TD;
> TargetLibraryInfo *TLI;
> bool MadeIRChange;
> + LibCallSimplifier *Simplifier;
> public:
> /// Worklist - All of the instructions that need to be simplified.
> InstCombineWorklist Worklist;
> diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp
> index cf83756..2fdd54b 100644
> --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp
> +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp
> @@ -775,39 +775,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,
> @@ -815,9 +782,10 @@ public:
> Instruction *InstCombiner::tryOptimizeCall(CallInst *CI, const TargetData *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) {
> diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp
> index ff758c4..fd27cb2 100644
> --- a/lib/Transforms/InstCombine/InstructionCombining.cpp
> +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp
> @@ -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
> diff --git a/lib/Transforms/Utils/CMakeLists.txt b/lib/Transforms/Utils/CMakeLists.txt
> index c3f72b1..620209b 100644
> --- a/lib/Transforms/Utils/CMakeLists.txt
> +++ b/lib/Transforms/Utils/CMakeLists.txt
> @@ -28,6 +28,7 @@ add_llvm_library(LLVMTransformUtils
> SimplifyCFG.cpp
> SimplifyIndVar.cpp
> SimplifyInstructions.cpp
> + SimplifyLibCalls.cpp
> UnifyFunctionExitNodes.cpp
> Utils.cpp
> ValueMapper.cpp
> diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp
> new file mode 100644
> index 0000000..c45783d
> --- /dev/null
> +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp
> @@ -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/ADT/StringMap.h"
> +#include "llvm/Analysis/ValueTracking.h"
> +#include "llvm/Function.h"
> +#include "llvm/IRBuilder.h"
> +#include "llvm/LLVMContext.h"
> +#include "llvm/Target/TargetData.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 TargetData *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 TargetData *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 TargetData *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 TargetData *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 TargetData *TD,
> + const TargetLibraryInfo *TLI) {
> + Impl = new LibCallSimplifierImpl(TD, TLI);
> +}
> +
> +LibCallSimplifier::~LibCallSimplifier() {
> + delete Impl;
> +}
> +
> +Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
> + return Impl->optimizeCall(CI);
> +}
> +
> +}
> --
> 1.7.10.2 (Apple Git-33)
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list