[llvm-commits] CVS: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp

Reid Spencer reid at x10sys.com
Fri Apr 29 02:39:59 PDT 2005



Changes in directory llvm/lib/Transforms/IPO:

SimplifyLibCalls.cpp updated: 1.22 -> 1.23
---
Log message:

Implement the optimizations for "pow" and "fputs" library calls.


---
Diffs of the changes:  (+217 -17)

 SimplifyLibCalls.cpp |  234 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 217 insertions(+), 17 deletions(-)


Index: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp
diff -u llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.22 llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.23
--- llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.22	Thu Apr 28 22:05:44 2005
+++ llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp	Fri Apr 29 04:39:47 2005
@@ -69,7 +69,8 @@
     : 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 @@
   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 @@
   }
 
   /// @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 @@
   {
     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 @@
     // 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 @@
     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 @@
 
 } 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 @@
 //   * cos(-x)  -> cos(x)
 //
 // exp, expf, expl:
-//   * exp(int)     -> contant'
 //   * exp(log(x))  -> x
 //
 // ffs, ffsl, ffsll:
@@ -768,11 +979,6 @@
 //       (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 @@
 //      (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 @@
 //      (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)






More information about the llvm-commits mailing list