]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR fortran/25620 (Missed optimization with power)
authorRichard Guenther <rguenther@suse.de>
Mon, 27 Nov 2006 11:38:42 +0000 (11:38 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 27 Nov 2006 11:38:42 +0000 (11:38 +0000)
2006-11-27  Richard Guenther  <rguenther@suse.de>

PR middle-end/25620
* builtins.c (expand_builtin_pow): Optimize non integer valued
constant exponents using sqrt or cbrt if possible.  Always fall back
to expanding via optabs.

* gcc.target/i386/pow-1.c: New testcase.
* gcc.dg/builtins-58.c: Likewise.

From-SVN: r119248

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-58.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pow-1.c [new file with mode: 0644]

index 316ead1a4772587c03d8a1bca8a38ca42f3d2181..65451c705eda2941fd88b3f1fc1588704530dc70 100644 (file)
@@ -1,3 +1,10 @@
+2006-11-27  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/25620
+       * builtins.c (expand_builtin_pow): Optimize non integer valued
+       constant exponents using sqrt or cbrt if possible.  Always fall back
+       to expanding via optabs.
+
 2006-11-27  Ira Rosen  <irar@il.ibm.com>
 
        PR tree-optimization/22372
index b2964ded2966dfd6cb173e2a3dabb374b7860f27..d610198a637d537bba034d260ac0a371d309a731 100644 (file)
@@ -2601,8 +2601,13 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
 static rtx
 expand_builtin_pow (tree exp, rtx target, rtx subtarget)
 {
+  tree arg0, arg1, fn, narg0, narglist;
   tree arglist = TREE_OPERAND (exp, 1);
-  tree arg0, arg1;
+  tree type = TREE_TYPE (exp);
+  REAL_VALUE_TYPE cint, c, c2;
+  HOST_WIDE_INT n;
+  rtx op, op2;
+  enum machine_mode mode = TYPE_MODE (type);
 
   if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
     return 0;
@@ -2610,36 +2615,108 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
   arg0 = TREE_VALUE (arglist);
   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
-  if (TREE_CODE (arg1) == REAL_CST
-      && ! TREE_CONSTANT_OVERFLOW (arg1))
+  if (TREE_CODE (arg1) != REAL_CST
+      || TREE_CONSTANT_OVERFLOW (arg1))
+    return expand_builtin_mathfn_2 (exp, target, subtarget);
+
+  /* Handle constant exponents.  */
+
+  /* For integer valued exponents we can expand to an optimal multiplication
+     sequence using expand_powi.  */
+  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)
+      && ((n >= -1 && n <= 2)
+         || (flag_unsafe_math_optimizations
+             && !optimize_size
+             && powi_cost (n) <= POWI_MAX_MULTS)))
     {
-      REAL_VALUE_TYPE cint;
-      REAL_VALUE_TYPE c;
-      HOST_WIDE_INT n;
+      op = expand_expr (arg0, subtarget, VOIDmode, 0);
+      if (n != 1)
+       {
+         op = force_reg (mode, op);
+         op = expand_powi (op, mode, n);
+       }
+      return op;
+    }
 
-      c = TREE_REAL_CST (arg1);
-      n = real_to_integer (&c);
+  narg0 = builtin_save_expr (arg0);
+  narglist = build_tree_list (NULL_TREE, narg0);
+
+  /* If the exponent is not integer valued, check if it is half of an integer.
+     In this case we can expand to sqrt (x) * x**(n/2).  */
+  fn = mathfn_built_in (type, BUILT_IN_SQRT);
+  if (fn != NULL_TREE)
+    {
+      real_arithmetic (&c2, MULT_EXPR, &c, &dconst2);
+      n = real_to_integer (&c2);
       real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
-      if (real_identical (&c, &cint))
-       {
-         /* 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))
+      if (real_identical (&c2, &cint)
+         && ((flag_unsafe_math_optimizations
+              && !optimize_size
+              && powi_cost (n/2) <= POWI_MAX_MULTS)
+             || n == 1))
+       {
+         tree call_expr = build_function_call_expr (fn, narglist);
+         op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
+         if (n != 1)
            {
-             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);
+             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = force_reg (mode, op2);
+             op2 = expand_powi (op2, mode, abs (n / 2));
+             op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
+                                       0, OPTAB_LIB_WIDEN);
+             /* If the original exponent was negative, reciprocate the
+                result.  */
+             if (n < 0)
+               op = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
+                                  op, NULL_RTX, 0, OPTAB_LIB_WIDEN);
            }
+         return op;
        }
     }
 
-  if (! flag_unsafe_math_optimizations)
-    return NULL_RTX;
+  /* Try if the exponent is a third of an integer.  In this case
+     we can expand to x**(n/3) * cbrt(x)**(n%3).  */
+  fn = mathfn_built_in (type, BUILT_IN_CBRT);
+  if (fn != NULL_TREE)
+    {
+      real_arithmetic (&c2, MULT_EXPR, &c, &dconst3);
+      real_round (&c2, mode, &c2);
+      n = real_to_integer (&c2);
+      real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+      real_arithmetic (&c2, RDIV_EXPR, &cint, &dconst3);
+      real_convert (&c2, mode, &c2);
+      if (real_identical (&c2, &c)
+         && ((!optimize_size
+              && flag_unsafe_math_optimizations
+              && powi_cost (n/3) <= POWI_MAX_MULTS)
+             || n == 1))
+       {
+         tree call_expr = build_function_call_expr (fn, narglist);
+         op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
+         if (abs (n) % 3 == 2)
+           op = expand_simple_binop (mode, MULT, op, op, op,
+                                     0, OPTAB_LIB_WIDEN);
+         if (n != 1)
+           {
+             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = force_reg (mode, op2);
+             op2 = expand_powi (op2, mode, abs (n / 3));
+             op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
+                                       0, OPTAB_LIB_WIDEN);
+             /* If the original exponent was negative, reciprocate the
+                result.  */
+             if (n < 0)
+               op = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
+                                  op, NULL_RTX, 0, OPTAB_LIB_WIDEN);
+           }
+         return op;
+       }
+    }
+
+  /* Fall back to optab expansion.  */
   return expand_builtin_mathfn_2 (exp, target, subtarget);
 }
 
index f5cd43d3965e6e6ae1bcbc253cbab857d35db18f..14e8f12da2e702d501d3bd00f9cd47c87d81be30 100644 (file)
@@ -1,3 +1,9 @@
+2006-11-27  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/25620
+       * gcc.target/i386/pow-1.c: New testcase.
+       * gcc.dg/builtins-58.c: Likewise.
+
 2006-11-26  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/29886
diff --git a/gcc/testsuite/gcc.dg/builtins-58.c b/gcc/testsuite/gcc.dg/builtins-58.c
new file mode 100644 (file)
index 0000000..cf5a9c2
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O -ffast-math -std=c99" } */
+
+#include "builtins-config.h"
+
+#ifdef HAVE_C99_RUNTIME
+double test1 (double x)
+{
+  return __builtin_pow (x, 1./3.);
+}
+
+double test2 (double x)
+{
+  return __builtin_pow (x, 4./3.);
+}
+
+double test3a (double x)
+{
+  return __builtin_pow (x, 5./3.);
+}
+
+double test3b (double x)
+{
+  return __builtin_pow (x, -5./3.);
+}
+
+double test4 (double x)
+{
+  return __builtin_pow (x, 7./3.);
+}
+#endif
+
+/* { dg-final { scan-assembler-not "pow" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pow-1.c b/gcc/testsuite/gcc.target/i386/pow-1.c
new file mode 100644 (file)
index 0000000..3bb3fe0
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O -ffast-math" } */
+
+double test1 (double x)
+{
+  return __builtin_pow (x, 1./2.);
+}
+
+double test2 (double x)
+{
+  return __builtin_pow (x, 3./2.);
+}
+
+double test3 (double x)
+{
+  return __builtin_pow (x, 5./2.);
+}
+
+double test4 (double x)
+{
+  return __builtin_pow (x, -5./2.);
+}
+
+/* { dg-final { scan-assembler-not "call" } } */