[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