fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and pow(x,c)*x as pow(x...
authorRoger Sayle <roger@eyesopen.com>
Fri, 1 Aug 2003 00:36:53 +0000 (00:36 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Fri, 1 Aug 2003 00:36:53 +0000 (00:36 +0000)
* fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and
pow(x,c)*x as pow(x,c+1) for constant values c.  Optimize x*x
as pow(x,2.0) when the latter will be expanded back into x*x.
(fold <RDIV_EXPR>): Optimize pow(x,c)/x as pow(x,c-1).
* builtins.c (expand_builtin_pow): Ignore flag_errno_math as
pow can never set errno when used with an integer exponent.
Always use expand_powi when exponent is -1, 0, 1 or 2.
(fold_builtin): Don't rewrite pow(x,2.0) as x*x nor pow(x,-2.0)
as 1.0/(x*x).  This avoids unbounded recursion as we now prefer
the pow forms of these expressions.

* gcc.dg/builtins-27.c: New test case.

From-SVN: r70030

gcc/ChangeLog
gcc/builtins.c
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-27.c [new file with mode: 0644]

index 1323f30..7590ddd 100644 (file)
@@ -1,3 +1,16 @@
+2003-07-31  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and
+       pow(x,c)*x as pow(x,c+1) for constant values c.  Optimize x*x
+       as pow(x,2.0) when the latter will be expanded back into x*x.
+       (fold <RDIV_EXPR>): Optimize pow(x,c)/x as pow(x,c-1).
+       * builtins.c (expand_builtin_pow): Ignore flag_errno_math as
+       pow can never set errno when used with an integer exponent.
+       Always use expand_powi when exponent is -1, 0, 1 or 2.
+       (fold_builtin): Don't rewrite pow(x,2.0) as x*x nor pow(x,-2.0)
+       as 1.0/(x*x).  This avoids unbounded recursion as we now prefer
+       the pow forms of these expressions.
+
 2003-07-31  Geoffrey Keating  <geoffk@apple.com>
 
        * Makefile.in (libexecdir): New.
index a8c1d47..535b84c 100644 (file)
@@ -2170,10 +2170,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
   arg0 = TREE_VALUE (arglist);
   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
-  if (flag_unsafe_math_optimizations
-      && ! flag_errno_math
-      && ! optimize_size
-      && TREE_CODE (arg1) == REAL_CST
+  if (TREE_CODE (arg1) == REAL_CST
       && ! TREE_CONSTANT_OVERFLOW (arg1))
     {
       REAL_VALUE_TYPE cint;
@@ -2183,13 +2180,21 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
       c = TREE_REAL_CST (arg1);
       n = real_to_integer (&c);
       real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
-      if (real_identical (&c, &cint)
-         && powi_cost (n) <= POWI_MAX_MULTS)
+      if (real_identical (&c, &cint))
        {
-          enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-          rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
-          op = force_reg (mode, op);
-          return expand_powi (op, mode, n);
+         /* If the exponent is -1, 0, 1 or 2, then expand_powi is exact.
+            Otherwise, check the number of multiplications required.
+            Note that pow never sets errno for an integer exponent.  */
+         if ((n >= -1 && n <= 2)
+             || (flag_unsafe_math_optimizations
+                 && ! optimize_size
+                 && powi_cost (n) <= POWI_MAX_MULTS))
+           {
+             enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+             rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
+             op = force_reg (mode, op);
+             return expand_powi (op, mode, n);
+           }
        }
     }
   return expand_builtin_mathfn_2 (exp, target, NULL_RTX);
@@ -6245,28 +6250,6 @@ fold_builtin (tree exp)
                                    build_real (type, dconst1),
                                    arg0));
 
-             /* Optimize pow(x,2.0) = x*x.  */
-             if (REAL_VALUES_EQUAL (c, dconst2)
-                 && (*lang_hooks.decls.global_bindings_p) () == 0
-                 && ! CONTAINS_PLACEHOLDER_P (arg0))
-               {
-                 arg0 = save_expr (arg0);
-                 return fold (build (MULT_EXPR, type, arg0, arg0));
-               }
-
-             /* Optimize pow(x,-2.0) = 1.0/(x*x).  */
-             if (flag_unsafe_math_optimizations
-                 && REAL_VALUES_EQUAL (c, dconstm2)
-                 && (*lang_hooks.decls.global_bindings_p) () == 0
-                 && ! CONTAINS_PLACEHOLDER_P (arg0))
-               {
-                 arg0 = save_expr (arg0);
-                 return fold (build (RDIV_EXPR, type,
-                                     build_real (type, dconst1),
-                                     fold (build (MULT_EXPR, type,
-                                                  arg0, arg0))));
-               }
-
              /* Optimize pow(x,0.5) = sqrt(x).  */
              if (flag_unsafe_math_optimizations
                  && REAL_VALUES_EQUAL (c, dconsthalf))
index aea392f..c4faf07 100644 (file)
@@ -6071,6 +6071,80 @@ fold (tree expr)
                    return build_function_call_expr (sinfn,
                                                     TREE_OPERAND (arg0, 1));
                }
+
+             /* Optimize x*pow(x,c) as pow(x,c+1).  */
+             if (fcode1 == BUILT_IN_POW
+                 || fcode1 == BUILT_IN_POWF
+                 || fcode1 == BUILT_IN_POWL)
+               {
+                 tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+                 tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
+                                                                    1)));
+                 if (TREE_CODE (arg11) == REAL_CST
+                     && ! TREE_CONSTANT_OVERFLOW (arg11)
+                     && operand_equal_p (arg0, arg10, 0))
+                   {
+                     tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+                     REAL_VALUE_TYPE c;
+                     tree arg, arglist;
+
+                     c = TREE_REAL_CST (arg11);
+                     real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+                     arg = build_real (type, c);
+                     arglist = build_tree_list (NULL_TREE, arg);
+                     arglist = tree_cons (NULL_TREE, arg0, arglist);
+                     return build_function_call_expr (powfn, arglist);
+                   }
+               }
+
+             /* Optimize pow(x,c)*x as pow(x,c+1).  */
+             if (fcode0 == BUILT_IN_POW
+                 || fcode0 == BUILT_IN_POWF
+                 || fcode0 == BUILT_IN_POWL)
+               {
+                 tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+                 tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
+                                                                    1)));
+                 if (TREE_CODE (arg01) == REAL_CST
+                     && ! TREE_CONSTANT_OVERFLOW (arg01)
+                     && operand_equal_p (arg1, arg00, 0))
+                   {
+                     tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                     REAL_VALUE_TYPE c;
+                     tree arg, arglist;
+
+                     c = TREE_REAL_CST (arg01);
+                     real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+                     arg = build_real (type, c);
+                     arglist = build_tree_list (NULL_TREE, arg);
+                     arglist = tree_cons (NULL_TREE, arg1, arglist);
+                     return build_function_call_expr (powfn, arglist);
+                   }
+               }
+
+             /* Optimize x*x as pow(x,2.0), which is expanded as x*x.  */
+             if (! optimize_size
+                 && operand_equal_p (arg0, arg1, 0))
+               {
+                 tree powfn;
+
+                 if (type == double_type_node)
+                   powfn = implicit_built_in_decls[BUILT_IN_POW];
+                 else if (type == float_type_node)
+                   powfn = implicit_built_in_decls[BUILT_IN_POWF];
+                 else if (type == long_double_type_node)
+                   powfn = implicit_built_in_decls[BUILT_IN_POWL];
+                 else
+                   powfn = NULL_TREE;
+
+                 if (powfn)
+                   {
+                     tree arg = build_real (type, dconst2);
+                     tree arglist = build_tree_list (NULL_TREE, arg);
+                     arglist = tree_cons (NULL_TREE, arg0, arglist);
+                     return build_function_call_expr (powfn, arglist);
+                   }
+               }
            }
        }
       goto associate;
@@ -6328,6 +6402,30 @@ fold (tree expr)
                                      tmp));
                }
            }
+
+         /* Optimize pow(x,c)/x as pow(x,c-1).  */
+         if (fcode0 == BUILT_IN_POW
+             || fcode0 == BUILT_IN_POWF
+             || fcode0 == BUILT_IN_POWL)
+           {
+             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+             tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
+             if (TREE_CODE (arg01) == REAL_CST
+                 && ! TREE_CONSTANT_OVERFLOW (arg01)
+                 && operand_equal_p (arg1, arg00, 0))
+               {
+                 tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                 REAL_VALUE_TYPE c;
+                 tree arg, arglist;
+
+                 c = TREE_REAL_CST (arg01);
+                 real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
+                 arg = build_real (type, c);
+                 arglist = build_tree_list (NULL_TREE, arg);
+                 arglist = tree_cons (NULL_TREE, arg1, arglist);
+                 return build_function_call_expr (powfn, arglist);
+               }
+           }
        }
       goto binary;
 
index 9299dde..26e44a3 100644 (file)
@@ -1,3 +1,7 @@
+2003-07-31  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/builtins-27.c: New test case.
+
 2003-07-31  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.dg/tls/opt-7.c: New test.
diff --git a/gcc/testsuite/gcc.dg/builtins-27.c b/gcc/testsuite/gcc.dg/builtins-27.c
new file mode 100644 (file)
index 0000000..69d8f99
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2003 Free Software Foundation.
+
+   Check that constant folding of built-in math functions doesn't
+   break anything and produces the expected results.
+
+   Written by Roger Sayle, 29th July 2003.  */
+
+/* { dg-do link } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern void link_error(void);
+
+extern double pow(double,double);
+
+void test(double x)
+{
+  if (pow(x,2.0) != x*x)
+    link_error ();
+
+  if (x*pow(x,2.0) != pow(x,3.0))
+    link_error ();
+
+  if (pow(x,2.0)*x != pow(x,3.0))
+    link_error ();
+
+  if (pow(x,3.0) != x*x*x)
+    link_error ();
+
+  if (pow(x,2.0)*x != x*x*x)
+    link_error ();
+
+  if (x*pow(x,2.0) != x*x*x)
+    link_error ();
+
+  if (pow(x,3.0)/x != pow(x,2.0))
+    link_error ();
+
+  if (pow(x,3.0)/x != x*x)
+    link_error ();
+}
+
+int main()
+{
+  test (2.0);
+  return 0;
+}
+