many cleanups to the pow optimizer. Allow it to handle powf,
authorChris Lattner <sabre@nondot.org>
Wed, 9 Apr 2008 00:07:45 +0000 (00:07 +0000)
committerChris Lattner <sabre@nondot.org>
Wed, 9 Apr 2008 00:07:45 +0000 (00:07 +0000)
add support for  pow(x, 2.0) -> x*x.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@49411 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/SimplifyLibCalls.cpp
test/Transforms/SimplifyLibCalls/Pow.ll

index ed32daa3988226b028390fa91b6184e72d121d7c..24c56abde97052520afaac490b62fbe7cc8d996d 100644 (file)
@@ -1133,52 +1133,68 @@ LLVMMemSetOptimization MemSet64Optimizer("llvm.memset.i64");
 struct VISIBILITY_HIDDEN PowOptimization : public LibCallOptimization {
 public:
   /// @brief Default Constructor
-  PowOptimization() : LibCallOptimization("pow",
+  PowOptimization(const char *Name) : LibCallOptimization(Name,
       "Number of 'pow' calls simplified") {}
 
   /// @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);
+  virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
+    // Just make sure this has 2 arguments of the same FP type, which match the
+    // result type.
+    const FunctionType *FT = F->getFunctionType();
+    return FT->getNumParams() == 2 && 
+          FT->getParamType(0) == FT->getParamType(1) &&
+          FT->getParamType(0) == FT->getReturnType() &&
+          FT->getParamType(0)->isFloatingPoint();
   }
 
   /// @brief Perform the pow optimization.
-  virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
-    const Type *Ty = cast<Function>(ci->getOperand(0))->getReturnType();
-    if (Ty!=Type::FloatTy && Ty!=Type::DoubleTy)
+  virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
+    const Type *Ty = CI->getType();
+    if (Ty != Type::FloatTy && Ty != Type::DoubleTy)
       return false;   // FIXME long double not yet supported
-    Value* base = ci->getOperand(1);
-    Value* expn = ci->getOperand(2);
-    if (ConstantFP *Op1 = dyn_cast<ConstantFP>(base)) {
-      if (Op1->isExactlyValue(1.0)) // pow(1.0,x) -> 1.0
-        return ReplaceCallWith(ci, ConstantFP::get(Ty, 
+    
+    Value *Op1 = CI->getOperand(1);
+    Value *Op2 = CI->getOperand(2);
+    if (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
+      if (Op1C->isExactlyValue(1.0)) // pow(1.0, x) -> 1.0
+        return ReplaceCallWith(CI, Op1C);
+    }
+    
+    ConstantFP *Op2C = dyn_cast<ConstantFP>(Op2);
+    if (Op2C == 0) return false;
+    
+    if (Op2C->getValueAPF().isZero()) {
+      // pow(x, 0.0) -> 1.0
+      return ReplaceCallWith(CI, ConstantFP::get(Ty,
           Ty==Type::FloatTy ? APFloat(1.0f) : APFloat(1.0)));
-    }  else if (ConstantFP* Op2 = dyn_cast<ConstantFP>(expn)) {
-      if (Op2->getValueAPF().isZero()) {
-        // pow(x,0.0) -> 1.0
-        return ReplaceCallWith(ci, ConstantFP::get(Ty,
-            Ty==Type::FloatTy ? APFloat(1.0f) : APFloat(1.0)));
-      } else if (Op2->isExactlyValue(0.5)) {
-        // pow(x,0.5) -> sqrt(x)
-        CallInst* sqrt_inst = CallInst::Create(SLC.get_sqrt(), base,
-                                               ci->getName()+".pow",ci);
-        return ReplaceCallWith(ci, sqrt_inst);
-      } else if (Op2->isExactlyValue(1.0)) {
-        // pow(x,1.0) -> x
-        return ReplaceCallWith(ci, base);
-      } else if (Op2->isExactlyValue(-1.0)) {
-        // pow(x,-1.0)    -> 1.0/x
-        Value *div_inst = 
-          BinaryOperator::createFDiv(ConstantFP::get(Ty,
-            Ty==Type::FloatTy ? APFloat(1.0f) : APFloat(1.0)), 
-            base, ci->getName()+".pow", ci);
-        return ReplaceCallWith(ci, div_inst);
-      }
+    } else if (Op2C->isExactlyValue(0.5)) {
+      // pow(x, 0.5) -> sqrt(x)
+      Value *Sqrt = CallInst::Create(SLC.get_sqrt(), Op1, "sqrt", CI);
+      return ReplaceCallWith(CI, Sqrt);
+    } else if (Op2C->isExactlyValue(1.0)) {
+      // pow(x, 1.0) -> x
+      return ReplaceCallWith(CI, Op1);
+    } else if (Op2C->isExactlyValue(2.0)) {
+      // pow(x, 2.0) -> x*x
+      Value *Sq = BinaryOperator::createMul(Op1, Op1, "pow2", CI);
+      return ReplaceCallWith(CI, Sq);
+    } else if (Op2C->isExactlyValue(-1.0)) {
+      // pow(x, -1.0) -> 1.0/x
+      Value *div_inst = 
+        BinaryOperator::createFDiv(ConstantFP::get(Ty,
+          Ty==Type::FloatTy ? APFloat(1.0f) : APFloat(1.0)), 
+          Op1, CI->getName()+".pow", CI);
+      return ReplaceCallWith(CI, div_inst);
     }
     return false; // opt failed
   }
-} PowOptimizer;
+};
 
+PowOptimization PowFOptimizer("powf");
+PowOptimization PowOptimizer("pow");
+PowOptimization PowLOptimizer("powl");
+  
 /// This LibCallOptimization will simplify calls to the "printf" library
 /// function. It looks for cases where the result of printf is not used and the
 /// operation can be reduced to something simpler.
index fa638ef78014ed88209b819bdd44028d9c0b824d..c039d80a2c9043f2e73c44f3e8d5778a10242a5b 100644 (file)
@@ -1,11 +1,10 @@
 ; Testcase for calls to the standard C "pow" function
 ;
-; Equivalent to: http://gcc.gnu.org/ml/gcc-patches/2003-02/msg01786.html
-; RUN: llvm-as < %s | opt -simplify-libcalls | llvm-dis | \
-; RUN:   not grep {call double .pow}
-; END.
+; RUN: llvm-as < %s | opt -simplify-libcalls | llvm-dis | not grep {call .pow}
+
 
 declare double @pow(double, double)
+declare float @powf(float, float)
 
 define double @test1(double %X) {
        %Y = call double @pow( double %X, double 0.000000e+00 )         ; <double> [#uses=1]
@@ -22,3 +21,12 @@ define double @test3(double %X) {
        ret double %Y
 }
 
+define double @test4(double %X) {
+       %Y = call double @pow( double %X, double 2.0)
+       ret double %Y
+}
+
+define float @test4f(float %X) {
+       %Y = call float @powf( float %X, float 2.0)
+       ret float %Y
+}