diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-08-01 00:36:53 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-08-01 00:36:53 +0000 |
commit | 2598550fa6d3583ce066a9aaf5abfa4acd186077 (patch) | |
tree | a842e3f3e11953156cef321cf6510aeed77635b1 /gcc | |
parent | e3da5a9a50524344c9b80ee1b8f2a8639493dd46 (diff) | |
download | gcc-2598550fa6d3583ce066a9aaf5abfa4acd186077.zip gcc-2598550fa6d3583ce066a9aaf5abfa4acd186077.tar.gz gcc-2598550fa6d3583ce066a9aaf5abfa4acd186077.tar.bz2 |
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.
* 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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/builtins.c | 47 | ||||
-rw-r--r-- | gcc/fold-const.c | 98 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/builtins-27.c | 47 |
5 files changed, 177 insertions, 32 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1323f30..7590ddd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/builtins.c b/gcc/builtins.c index a8c1d47..535b84c 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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)) diff --git a/gcc/fold-const.c b/gcc/fold-const.c index aea392f..c4faf07 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9299dde..26e44a3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..69d8f99 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-27.c @@ -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; +} + |