This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR25620, pow() expansion missed-optimization, 2nd try
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Roger Sayle <roger at eyesopen dot com>
- Date: Sun, 12 Nov 2006 17:25:29 +0100 (CET)
- Subject: [PATCH] Fix PR25620, pow() expansion missed-optimization, 2nd try
This is the 2nd try as suggested by Roger. I have left out the
split out of common parts of pow/powi expansion - it doesn't really
work out. I have also left in the cbrt() variant, but I can easily
leave that out if required.
Bootstrapped and regtested on x86_64-unknown-linux-gnu. SPEC 2k
doesn't show a difference, Polyhedron has an improvement for air
(down from 21s to 16.5s runtime).
Ok for mainline?
Thanks,
Richard.
2006-11-11 Richard Guenther <rguenther@suse.de>
PR middle-end/25620
* builtins.c (expand_builtin_pow): Use sqrt or cbrt if that
makes the remaining exponent integer.
* gcc.target/i386/pow-1.c: New testcase.
* gcc.dg/builtins-58.c: Likewise.
Index: builtins.c
===================================================================
*** builtins.c (revision 118691)
--- builtins.c (working copy)
*************** expand_builtin_pow (tree exp, rtx target
*** 2609,2639 ****
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
if (TREE_CODE (arg1) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg1))
{
REAL_VALUE_TYPE cint;
! REAL_VALUE_TYPE c;
HOST_WIDE_INT n;
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))
! {
! /* 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);
}
}
}
--- 2609,2697 ----
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ /* Handle constant exponents. */
if (TREE_CODE (arg1) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg1))
{
REAL_VALUE_TYPE cint;
! REAL_VALUE_TYPE c, c2;
HOST_WIDE_INT n;
+ rtx op, op2;
+ tree fn;
+ tree type = TREE_TYPE (exp);
+ enum machine_mode mode = TYPE_MODE (type);
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)))
! {
! op = expand_expr (arg0, subtarget, VOIDmode, 0);
! if (n != 1)
{
op = force_reg (mode, op);
! op = expand_powi (op, mode, n);
! }
! return op;
! }
!
! if (!flag_unsafe_math_optimizations)
! return NULL_RTX;
!
! /* 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). */
! 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 (&c2, &cint)
! && (fn = mathfn_built_in (type, BUILT_IN_SQRT))
! && !optimize_size
! && powi_cost (n/2) <= POWI_MAX_MULTS)
! {
! tree arg = build_tree_list (NULL_TREE, arg0);
! tree call_expr = build_function_call_expr (fn, arg);
! op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
! if (n != 1)
! {
! op2 = expand_expr (arg0, subtarget, VOIDmode, 0);
! op2 = force_reg (mode, op2);
! op2 = expand_powi (op2, mode, n / 2);
! expand_simple_binop (mode, MULT, op, op2, op, 0, OPTAB_DIRECT);
! }
! return op;
! }
!
! /* Try if the exponent is a third of an integer. In this case
! we can expand to x**(n/3) * cbrt(x)**(n%3). */
! 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)
! && (fn = mathfn_built_in (type, BUILT_IN_CBRT))
! && !optimize_size
! && powi_cost (n/3) <= POWI_MAX_MULTS)
! {
! tree arg = build_tree_list (NULL_TREE, arg0);
! tree call_expr = build_function_call_expr (fn, arg);
! op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
! if (n % 3 == 2)
! expand_simple_binop (mode, MULT, op, op, op, 0, OPTAB_DIRECT);
! if (n != 1)
! {
! op2 = expand_expr (arg0, subtarget, VOIDmode, 0);
! op2 = force_reg (mode, op2);
! op2 = expand_powi (op2, mode, n / 3);
! expand_simple_binop (mode, MULT, op, op2, op, 0, OPTAB_DIRECT);
}
+ return op;
}
}
Index: testsuite/gcc.target/i386/pow-1.c
===================================================================
*** testsuite/gcc.target/i386/pow-1.c (revision 0)
--- testsuite/gcc.target/i386/pow-1.c (revision 0)
***************
*** 0 ****
--- 1,20 ----
+ /* { 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.);
+ }
+
+ /* { dg-final { scan-assembler-not "call" } } */
+
Index: testsuite/gcc.dg/builtins-58.c
===================================================================
*** testsuite/gcc.dg/builtins-58.c (revision 0)
--- testsuite/gcc.dg/builtins-58.c (revision 0)
***************
*** 0 ****
--- 1,20 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -ffast-math -std=c99" } */
+
+ double test1 (double x)
+ {
+ return __builtin_pow (x, 1./3.);
+ }
+
+ double test2 (double x)
+ {
+ return __builtin_pow (x, 4./3.);
+ }
+
+ double test3 (double x)
+ {
+ return __builtin_pow (x, 7./3.);
+ }
+
+ /* { dg-final { scan-assembler-times "cbrt" 3 } } */
+