diff options
| author | Reid Spencer <rspencer@reidspencer.com> | 2005-04-29 09:39:47 +0000 | 
|---|---|---|
| committer | Reid Spencer <rspencer@reidspencer.com> | 2005-04-29 09:39:47 +0000 | 
| commit | ff5525daf30eeb70cb2331e9d94eef8caa61da11 (patch) | |
| tree | d46cb47ed07f6cf8421cd8f1ace507f9dd22acad | |
| parent | bb4cae7d696c17bd2a968df9eb4ec7afa6c6ee61 (diff) | |
Implement the optimizations for "pow" and "fputs" library calls.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21618 91177308-0d34-0410-b5e6-96231b3b80d8
| -rw-r--r-- | lib/Transforms/IPO/SimplifyLibCalls.cpp | 234 | 
1 files changed, 217 insertions, 17 deletions
| diff --git a/lib/Transforms/IPO/SimplifyLibCalls.cpp b/lib/Transforms/IPO/SimplifyLibCalls.cpp index 8cc8e124b8..985d885694 100644 --- a/lib/Transforms/IPO/SimplifyLibCalls.cpp +++ b/lib/Transforms/IPO/SimplifyLibCalls.cpp @@ -69,7 +69,8 @@ public:      : func_name(fname)  #ifndef NDEBUG      , stat_name(std::string("simplify-libcalls:")+fname) -    , occurrences(stat_name.c_str(),"Number of calls simplified")  +    , stat_desc(std::string("Number of ")+fname+"(...) calls simplified") +    , occurrences(stat_name.c_str(),stat_desc.c_str())  #endif    {      // Register this call optimizer in the optlist (a hash_map) @@ -118,6 +119,7 @@ private:    const char* func_name; ///< Name of the library call we optimize  #ifndef NDEBUG    std::string stat_name; ///< Holder for debug statistic name +  std::string stat_desc; ///< Holder for debug statistic description    Statistic<> occurrences; ///< debug statistic (-debug-only=simplify-libcalls)  #endif  }; @@ -203,10 +205,69 @@ public:    }    /// @brief Return the *current* module we're working on. -  Module* getModule() { return M; } +  Module* getModule() const { return M; }    /// @brief Return the *current* target data for the module we're working on. -  TargetData* getTargetData() { return TD; } +  TargetData* getTargetData() const { return TD; } + +  /// @brief Return the size_t type -- syntactic shortcut +  const Type* getIntPtrType() const { return TD->getIntPtrType(); } + +  /// @brief Return a Function* for the fputc libcall +  Function* get_fputc() +  { +    if (!fputc_func) +    { +      std::vector<const Type*> args; +      args.push_back(Type::IntTy); +      const Type* FILE_type = M->getTypeByName("struct._IO_FILE"); +      if (!FILE_type) +        FILE_type = M->getTypeByName("struct._FILE"); +      if (!FILE_type) +        return 0; +      args.push_back(PointerType::get(FILE_type)); +      FunctionType* fputc_type =  +        FunctionType::get(Type::IntTy, args, false); +      fputc_func = M->getOrInsertFunction("fputc",fputc_type); +    } +    return fputc_func; +  } + +  /// @brief Return a Function* for the fwrite libcall +  Function* get_fwrite() +  { +    if (!fwrite_func) +    { +      std::vector<const Type*> args; +      args.push_back(PointerType::get(Type::SByteTy)); +      args.push_back(TD->getIntPtrType()); +      args.push_back(TD->getIntPtrType()); +      const Type* FILE_type = M->getTypeByName("struct._IO_FILE"); +      if (!FILE_type) +        FILE_type = M->getTypeByName("struct._FILE"); +      if (!FILE_type) +        return 0; +      args.push_back(PointerType::get(FILE_type)); +      FunctionType* fwrite_type =  +        FunctionType::get(TD->getIntPtrType(), args, false); +      fwrite_func = M->getOrInsertFunction("fwrite",fwrite_type); +    } +    return fwrite_func; +  } + +  /// @brief Return a Function* for the sqrt libcall +  Function* get_sqrt() +  { +    if (!sqrt_func) +    { +      std::vector<const Type*> args; +      args.push_back(Type::DoubleTy); +      FunctionType* sqrt_type =  +        FunctionType::get(Type::DoubleTy, args, false); +      sqrt_func = M->getOrInsertFunction("sqrt",sqrt_type); +    } +    return sqrt_func; +  }    /// @brief Return a Function* for the strlen libcall    Function* get_strlen() @@ -245,12 +306,18 @@ private:    {      M = &mod;      TD = &getAnalysis<TargetData>(); +    fputc_func = 0; +    fwrite_func = 0;      memcpy_func = 0; +    sqrt_func   = 0;      strlen_func = 0;    }  private: +  Function* fputc_func;  ///< Cached fputc function +  Function* fwrite_func; ///< Cached fwrite function    Function* memcpy_func; ///< Cached llvm.memcpy function +  Function* sqrt_func;   ///< Cached sqrt function    Function* strlen_func; ///< Cached strlen function    Module* M;             ///< Cached Module    TargetData* TD;        ///< Cached TargetData @@ -399,7 +466,6 @@ public:      // terminator as well.      len++; -      // We need to find the end of the destination string.  That's where the       // memory is to be moved to. We just generate a call to strlen (further       // optimized in another pass).  Note that the SLC.get_strlen() call  @@ -609,7 +675,7 @@ public:      switch (len)      {        case 0: -        // The memcpy is a no-op so just dump its call. +        // memcpy(d,s,0,a) -> noop          ci->eraseFromParent();          return true;        case 1: castType = Type::SByteTy; break; @@ -643,6 +709,152 @@ struct MemMoveOptimization : public MemCpyOptimization  } MemMoveOptimizer; +/// This LibCallOptimization will simplify calls to the "pow" library  +/// function. It looks for cases where the result of pow is well known and  +/// substitutes the appropriate value. +/// @brief Simplify the pow library function. +struct PowOptimization : public LibCallOptimization +{ +public: +  /// @brief Default Constructor +  PowOptimization() : LibCallOptimization("pow") {} +  /// @brief Destructor +  virtual ~PowOptimization() {} + +  /// @brief Make sure that the "pow" function has the right prototype +  virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC) +  { +    // Just make sure this has 2 arguments +    return (f->arg_size() == 2); +  } + +  /// @brief Perform the pow optimization. +  virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) +  { +    const Type *Ty = cast<Function>(ci->getOperand(0))->getReturnType(); +    Value* base = ci->getOperand(1); +    Value* expn = ci->getOperand(2); +    if (ConstantFP *Op1 = dyn_cast<ConstantFP>(base)) { +      double Op1V = Op1->getValue(); +      if (Op1V == 1.0) +      { +        // pow(1.0,x) -> 1.0 +        ci->replaceAllUsesWith(ConstantFP::get(Ty,1.0)); +        ci->eraseFromParent(); +        return true; +      } +    }  +    else if (ConstantFP* Op2 = dyn_cast<ConstantFP>(expn))  +    { +      double Op2V = Op2->getValue(); +      if (Op2V == 0.0) +      { +        // pow(x,0.0) -> 1.0 +        ci->replaceAllUsesWith(ConstantFP::get(Ty,1.0)); +        ci->eraseFromParent(); +        return true; +      } +      else if (Op2V == 0.5) +      { +        // pow(x,0.5) -> sqrt(x) +        CallInst* sqrt_inst = new CallInst(SLC.get_sqrt(), base, +            ci->getName()+".pow",ci); +        ci->replaceAllUsesWith(sqrt_inst); +        ci->eraseFromParent(); +        return true; +      } +      else if (Op2V == 1.0) +      { +        // pow(x,1.0) -> x +        ci->replaceAllUsesWith(base); +        ci->eraseFromParent(); +        return true; +      } +      else if (Op2V == -1.0) +      { +        // pow(x,-1.0)    -> 1.0/x +        BinaryOperator* div_inst= BinaryOperator::create(Instruction::Div, +          ConstantFP::get(Ty,1.0), base, ci->getName()+".pow", ci); +        ci->replaceAllUsesWith(div_inst); +        ci->eraseFromParent(); +        return true; +      } +    } +    return false; // opt failed +  } +} PowOptimizer; + +/// This LibCallOptimization will simplify calls to the "fputs" library  +/// function. It looks for cases where the result of fputs is not used and the +/// operation can be reduced to something simpler. +/// @brief Simplify the pow library function. +struct PutsOptimization : public LibCallOptimization +{ +public: +  /// @brief Default Constructor +  PutsOptimization() : LibCallOptimization("fputs") {} + +  /// @brief Destructor +  virtual ~PutsOptimization() {} + +  /// @brief Make sure that the "fputs" function has the right prototype +  virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC) +  { +    // Just make sure this has 2 arguments +    return (f->arg_size() == 2); +  } + +  /// @brief Perform the fputs optimization. +  virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) +  { +    // If the result is used, none of these optimizations work +    if (!ci->hasNUses(0))  +      return false; + +    // All the optimizations depend on the length of the first argument and the +    // fact that it is a constant string array. Check that now +    uint64_t len = 0;  +    if (!getConstantStringLength(ci->getOperand(1), len)) +      return false; + +    switch (len) +    { +      case 0: +        // fputs("",F) -> noop +        break; +      case 1: +      { +        // fputs(s,F)  -> fputc(s[0],F)  (if s is constant and strlen(s) == 1) +        Function* fputc_func = SLC.get_fputc(); +        if (!fputc_func) +          return false; +        LoadInst* loadi = new LoadInst(ci->getOperand(1), +          ci->getOperand(1)->getName()+".byte",ci); +        CastInst* casti = new CastInst(loadi,Type::IntTy, +          loadi->getName()+".int",ci); +        new CallInst(fputc_func,casti,ci->getOperand(2),"",ci); +        break; +      } +      default: +      {   +        // fputs(s,F)  -> fwrite(s,1,len,F) (if s is constant and strlen(s) > 1) +        Function* fwrite_func = SLC.get_fwrite(); +        if (!fwrite_func) +          return false; +        std::vector<Value*> parms; +        parms.push_back(ci->getOperand(1)); +        parms.push_back(ConstantUInt::get(SLC.getIntPtrType(),len)); +        parms.push_back(ConstantUInt::get(SLC.getIntPtrType(),1)); +        parms.push_back(ci->getOperand(2)); +        new CallInst(fwrite_func,parms,"",ci); +        break; +      } +    } +    ci->eraseFromParent(); +    return true; // success +  } +} PutsOptimizer; +  /// A function to compute the length of a null-terminated constant array of  /// integers.  This function can't rely on the size of the constant array   /// because there could be a null terminator in the middle of the array.  @@ -755,7 +967,6 @@ bool getConstantStringLength(Value* V, uint64_t& len )  //   * cos(-x)  -> cos(x)  //  // exp, expf, expl: -//   * exp(int)     -> contant'  //   * exp(log(x))  -> x  //  // ffs, ffsl, ffsll: @@ -768,11 +979,6 @@ bool getConstantStringLength(Value* V, uint64_t& len )  //       (only if the fprintf result is not used)  //   * fprintf(file,"%c",chr) -> fputc(chr,file)  // -// fputs: (only if the result is not used) -//   * fputs("",F) -> noop -//   * fputs(s,F)  -> fputc(s[0],F)        (if s is constant and strlen(s) == 1) -//   * fputs(s,F)  -> fwrite(s, 1, len, F) (if s is constant and strlen(s) > 1) -//  // isascii:  //   * isascii(c)    -> ((c & ~0x7f) == 0)  //    @@ -798,9 +1004,6 @@ bool getConstantStringLength(Value* V, uint64_t& len )  //      (if all arguments are constant and strlen(x) <= l and strlen(y) <= l)  //   * memcpy(x,y,1)   -> *x - *y  // -// memcpy: -//   * memcpy(d,s,0,a) -> d -//  // memmove:  //   * memmove(d,s,l,a) -> memcpy(d,s,l,a)   //       (if s is a global constant array) @@ -811,9 +1014,6 @@ bool getConstantStringLength(Value* V, uint64_t& len )  //      (for n=1,2,4,8)  //  // pow, powf, powl: -//   * pow(x,-1.0)    -> 1.0/x -//   * pow(x,0.5)     -> sqrt(x) -//   * pow(cst1,cst2) -> const1**const2  //   * pow(exp(x),y)  -> exp(x*y)  //   * pow(sqrt(x),y) -> pow(x,y*0.5)  //   * pow(pow(x,y),z)-> pow(x,y*z) | 
