builtins.c (fold_builtin_cbrt, [...]): Rearrange code.
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>
Wed, 9 Mar 2005 20:11:48 +0000 (20:11 +0000)
committerKaveh Ghazi <ghazi@gcc.gnu.org>
Wed, 9 Mar 2005 20:11:48 +0000 (20:11 +0000)
* builtins.c (fold_builtin_cbrt, fold_builtin_pow): Rearrange
code.  Add more cbrt transformations.

testsuite:
* gcc.dg/builtins-10.c: Reactivate disabled test.
* gcc.dg/torture/builtin-power-1.c: Likewise.  Also add tests for
new cbrt transformations.

From-SVN: r96206

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-10.c
gcc/testsuite/gcc.dg/torture/builtin-power-1.c

index e90219878e6a2a83acf487e7d962b9a7bcb5b447..dddd9abdd83f836ae5491d3e352246c82ad79309 100644 (file)
@@ -1,3 +1,8 @@
+2005-03-09  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * builtins.c (fold_builtin_cbrt, fold_builtin_pow): Rearrange
+       code.  Add more cbrt transformations.
+
 2005-03-09  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * fold-const.c (fold_unary_to_constant): Add FIX_ROUND_EXPR case.
index 5d9aa77f4e7121e8a54d5fe9f8f4a251dbc6834e..b113d9f770e6b62f5d3562d4586da180fa891023 100644 (file)
@@ -6311,40 +6311,82 @@ fold_builtin_cbrt (tree arglist, tree type)
   if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg))
     return arg;
 
-  /* Optimize cbrt(expN(x)) -> expN(x/3).  */
-  if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
-    {
-      tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
-      const REAL_VALUE_TYPE third_trunc =
-       real_value_truncate (TYPE_MODE (type), dconstthird);
-      arg = fold (build2 (MULT_EXPR, type,
-                         TREE_VALUE (TREE_OPERAND (arg, 1)),
-                         build_real (type, third_trunc)));
-      arglist = build_tree_list (NULL_TREE, arg);
-      return build_function_call_expr (expfn, arglist);
-    }
-
-  /* Optimize cbrt(sqrt(x)) -> pow(x,1/6).  */
-  /* We don't optimize cbrt(cbrt(x)) -> pow(x,1/9) because if
-     x is negative pow will error but cbrt won't.  */
-  if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
+  if (flag_unsafe_math_optimizations)
     {
-      tree powfn = mathfn_built_in (type, BUILT_IN_POW);
+      /* Optimize cbrt(expN(x)) -> expN(x/3).  */
+      if (BUILTIN_EXPONENT_P (fcode))
+        {
+         tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+         const REAL_VALUE_TYPE third_trunc =
+           real_value_truncate (TYPE_MODE (type), dconstthird);
+         arg = fold (build2 (MULT_EXPR, type,
+                             TREE_VALUE (TREE_OPERAND (arg, 1)),
+                             build_real (type, third_trunc)));
+         arglist = build_tree_list (NULL_TREE, arg);
+         return build_function_call_expr (expfn, arglist);
+       }
 
-      if (powfn)
-       {
-         tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
-         tree tree_root;
-         REAL_VALUE_TYPE dconstroot = dconstthird;
+      /* Optimize cbrt(sqrt(x)) -> pow(x,1/6).  */
+      if (BUILTIN_SQRT_P (fcode))
+        {
+         tree powfn = mathfn_built_in (type, BUILT_IN_POW);
 
-         SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
-         dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
-         tree_root = build_real (type, dconstroot);
-         arglist = tree_cons (NULL_TREE, arg0,
-                              build_tree_list (NULL_TREE, tree_root));
-         return build_function_call_expr (powfn, arglist);
+         if (powfn)
+           {
+             tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
+             tree tree_root;
+             REAL_VALUE_TYPE dconstroot = dconstthird;
+
+             SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
+             dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
+             tree_root = build_real (type, dconstroot);
+             arglist = tree_cons (NULL_TREE, arg0,
+                                  build_tree_list (NULL_TREE, tree_root));
+             return build_function_call_expr (powfn, arglist);
+           }
        }
 
+      /* Optimize cbrt(cbrt(x)) -> pow(x,1/9) iff x is nonnegative.  */
+      if (BUILTIN_CBRT_P (fcode))
+        {
+         tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
+         if (tree_expr_nonnegative_p (arg0))
+           {
+             tree powfn = mathfn_built_in (type, BUILT_IN_POW);
+
+             if (powfn)
+               {
+                 tree tree_root;
+                 REAL_VALUE_TYPE dconstroot;
+             
+                 real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird);
+                 dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
+                 tree_root = build_real (type, dconstroot);
+                 arglist = tree_cons (NULL_TREE, arg0,
+                                      build_tree_list (NULL_TREE, tree_root));
+                 return build_function_call_expr (powfn, arglist);
+               }
+           }
+       }
+      
+      /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative.  */
+      if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF
+         || fcode == BUILT_IN_POWL)
+        {
+         tree arg00 = TREE_VALUE (TREE_OPERAND (arg, 1));
+         tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
+         if (tree_expr_nonnegative_p (arg00))
+           {
+             tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+             const REAL_VALUE_TYPE dconstroot
+               = real_value_truncate (TYPE_MODE (type), dconstthird);
+             tree narg01 = fold (build2 (MULT_EXPR, type, arg01,
+                                         build_real (type, dconstroot)));
+             arglist = tree_cons (NULL_TREE, arg00,
+                                  build_tree_list (NULL_TREE, narg01));
+             return build_function_call_expr (powfn, arglist);
+           }
+       }
     }
   return NULL_TREE;
 }
@@ -6849,7 +6891,6 @@ fold_builtin_logarithm (tree exp, const REAL_VALUE_TYPE *value)
 static tree
 fold_builtin_pow (tree fndecl, tree arglist, tree type)
 {
-  enum built_in_function fcode;
   tree arg0 = TREE_VALUE (arglist);
   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
@@ -6928,42 +6969,61 @@ fold_builtin_pow (tree fndecl, tree arglist, tree type)
        }
     }
 
-  /* Optimize pow(expN(x),y) = expN(x*y).  */
-  fcode = builtin_mathfn_code (arg0);
-  if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
+  if (flag_unsafe_math_optimizations)
     {
-      tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-      tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
-      arg = fold (build2 (MULT_EXPR, type, arg, arg1));
-      arglist = build_tree_list (NULL_TREE, arg);
-      return build_function_call_expr (expfn, arglist);
-    }
+      const enum built_in_function fcode = builtin_mathfn_code (arg0);
 
-  /* Optimize pow(sqrt(x),y) = pow(x,y*0.5).  */
-  if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
-    {
-      tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-      tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
-                                build_real (type, dconsthalf)));
+      /* Optimize pow(expN(x),y) = expN(x*y).  */
+      if (BUILTIN_EXPONENT_P (fcode))
+        {
+         tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+         tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
+         arg = fold (build2 (MULT_EXPR, type, arg, arg1));
+         arglist = build_tree_list (NULL_TREE, arg);
+         return build_function_call_expr (expfn, arglist);
+       }
 
-      arglist = tree_cons (NULL_TREE, narg0,
-                          build_tree_list (NULL_TREE, narg1));
-      return build_function_call_expr (fndecl, arglist);
-    }
+      /* Optimize pow(sqrt(x),y) = pow(x,y*0.5).  */
+      if (BUILTIN_SQRT_P (fcode))
+        {
+         tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+         tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
+                                    build_real (type, dconsthalf)));
 
-  /* Optimize pow(pow(x,y),z) = pow(x,y*z).  */
-  if (flag_unsafe_math_optimizations
-      && (fcode == BUILT_IN_POW
-         || fcode == BUILT_IN_POWF
-         || fcode == BUILT_IN_POWL))
-    {
-      tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-      tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
-      tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1));
-      arglist = tree_cons (NULL_TREE, arg00,
-                          build_tree_list (NULL_TREE, narg1));
-      return build_function_call_expr (fndecl, arglist);
+         arglist = tree_cons (NULL_TREE, narg0,
+                              build_tree_list (NULL_TREE, narg1));
+         return build_function_call_expr (fndecl, arglist);
+       }
+
+      /* Optimize pow(cbrt(x),y) = pow(x,y/3) iff x is nonnegative.  */
+      if (BUILTIN_CBRT_P (fcode))
+        {
+         tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
+         if (tree_expr_nonnegative_p (arg))
+           {
+             const REAL_VALUE_TYPE dconstroot
+               = real_value_truncate (TYPE_MODE (type), dconstthird);
+             tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
+                                        build_real (type, dconstroot)));
+             arglist = tree_cons (NULL_TREE, arg,
+                                  build_tree_list (NULL_TREE, narg1));
+             return build_function_call_expr (fndecl, arglist);
+           }
+       }
+      
+      /* Optimize pow(pow(x,y),z) = pow(x,y*z).  */
+      if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF
+          || fcode == BUILT_IN_POWL)
+        {
+         tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+         tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
+         tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1));
+         arglist = tree_cons (NULL_TREE, arg00,
+                              build_tree_list (NULL_TREE, narg1));
+         return build_function_call_expr (fndecl, arglist);
+       }
     }
+
   return NULL_TREE;
 }
 
index fd38a0ef1c8a91af5ad42987e355c889ead8e95a..9d40f9112867f39066ea7a4885f90daa2940fdc0 100644 (file)
@@ -1,3 +1,9 @@
+2005-03-09  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.dg/builtins-10.c: Reactivate disabled test.
+       * gcc.dg/torture/builtin-power-1.c: Likewise.  Also add tests for
+       new cbrt transformations.
+
 2005-03-09  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/20208
index 53158a0f8523071a21ebcfab8182d3d517abe4c5..d90e61ab32633db67e2ed02c6c7b496ab4fa4006 100644 (file)
@@ -18,8 +18,8 @@ extern double fabs(double);
 
 void test(double x)
 {
-  /*if (sqrt(pow(x,4.0)) != x*x)
-    link_error (); */
+  if (sqrt(pow(x,4.0)) != x*x)
+    link_error ();
 
   if (pow(sqrt(x),4.0) != x*x)
     link_error ();
index 7cdc00c23fb0eb40db2dad89f7073037822013cc..7b890bb0816833ea9c7c9884190752ccfb84a27e 100644 (file)
@@ -22,6 +22,7 @@
   extern float FN##f(float, float); \
   extern long double FN##l(long double, long double);
 
+PROTOTYPE(fabs)
 PROTOTYPE(sqrt)
 PROTOTYPE(cbrt)
 PROTOTYPE2(pow)
@@ -32,39 +33,45 @@ void test(double d1, double d2, double d3,
 {
   /* Test N1root(N2root(x)) -> pow(x,1/(N1*N2)).  */
   /* E.g. sqrt(cbrt(x)) -> pow(x,1/6).  */
-#define ROOT_ROOT(FN1,N1,FN2,N2) \
+  /* The `ABS' argument is `fabs' when the transformation only works
+     for nonnegative arguments.  Otherwise it's blank.  */
+#define ROOT_ROOT(FN1,N1,FN2,N2,ABS) \
  extern void link_failure_##FN1##_##FN2(void); \
- if (FN1(FN2(d1)) != pow(d1,1.0/(N1*N2)) \
-     || C99CODE (FN1##f(FN2##f(f1)) != powf(f1,1.0F/(N1*N2))) \
-     || C99CODE (FN1##l(FN2##l(ld1)) != powl(ld1,1.0L/(N1*N2)))) \
+ if (FN1(FN2(ABS(d1))) != pow(ABS(d1),1.0/(N1*N2)) \
+     || C99CODE (FN1##f(FN2##f(ABS(f1))) != powf(ABS(f1),1.0F/(N1*N2))) \
+     || C99CODE (FN1##l(FN2##l(ABS(ld1))) != powl(ABS(ld1),1.0L/(N1*N2)))) \
     link_failure_##FN1##_##FN2()
 
-  ROOT_ROOT(sqrt,2,sqrt,2);
-  ROOT_ROOT(sqrt,2,cbrt,3);
-  ROOT_ROOT(cbrt,3,sqrt,2);
-  /*ROOT_ROOT(cbrt,3,cbrt,3); Intentionally not implemented.  */
+  ROOT_ROOT(sqrt,2,sqrt,2,);
+  ROOT_ROOT(sqrt,2,cbrt,3,);
+  ROOT_ROOT(cbrt,3,sqrt,2,);
+  ROOT_ROOT(cbrt,3,cbrt,3,fabs);
 
   /* Test pow(Nroot(x),y) -> pow(x,y/N).  */
-#define POW_ROOT(FN,N) \
+  /* The `ABS' argument is `fabs' when the transformation only works
+     for nonnegative arguments.  Otherwise it's blank.  */
+#define POW_ROOT(FN,N,ABS) \
  extern void link_failure_pow_##FN(void); \
- if (pow(FN(d1), d2) != pow(d1,d2/N) \
-     || powf(FN##f(f1),f2) != powf(f1,f2/N) \
-     || powl(FN##l(ld1),ld2) != powl(ld1,ld2/N)) \
+ if (pow(FN(ABS(d1)), d2) != pow(ABS(d1),d2/N) \
+     || powf(FN##f(ABS(f1)),f2) != powf(ABS(f1),f2/N) \
+     || powl(FN##l(ABS(ld1)),ld2) != powl(ABS(ld1),ld2/N)) \
     link_failure_pow_##FN()
 
-  POW_ROOT(sqrt,2);
-  /*POW_ROOT(cbrt,3); Intentionally not implemented.  */
+  POW_ROOT(sqrt,2,);
+  POW_ROOT(cbrt,3,fabs);
 
   /* Test Nroot(pow(x,y)) -> pow(x,y/N).  */
-#define ROOT_POW(FN,N) \
+  /* The `ABS' argument is `fabs' when the transformation only works
+     for nonnegative arguments.  Otherwise it's blank.  */
+#define ROOT_POW(FN,N,ABS) \
  extern void link_failure_##FN##_pow(void); \
- if (FN(pow(d1, d2)) != pow(d1,d2/N) \
-     || FN##f(powf(f1,f2)) != powf(f1,f2/N) \
-     || FN##l(powl(ld1,ld2)) != powl(ld1,ld2/N)) \
+ if (FN(pow(ABS(d1), d2)) != pow(ABS(d1),d2/N) \
+     || FN##f(powf(ABS(f1),f2)) != powf(ABS(f1),f2/N) \
+     || FN##l(powl(ABS(ld1),ld2)) != powl(ABS(ld1),ld2/N)) \
     link_failure_##FN##_pow()
 
-  /*ROOT_POW(sqrt,2); Invalid. */
-  /*ROOT_POW(cbrt,3); Intentionally not implemented.  */
+  ROOT_POW(sqrt,2,fabs);
+  ROOT_POW(cbrt,3,fabs);
 
   /* Test pow(pow(x,y),z) -> pow(x,y*z).  */
 #define POW_POW \