diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 20134695c3b..58700fba650 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2003-04-08 Roger Sayle + + * fold-const.c (fold): Use "fold" following build in more places. + Optimize sqrt(x)*sqrt(x) as x, pow(x,y)*pow(z,y) as pow(x*z,y), + pow(x,y)*pow(x,z) as pow(x,y+z) and x/pow(y,z) as x*pow(y,-z). + 2003-04-08 Roger Sayle * builtins.c (fold_builtin): Constant fold expressions as x*0.5 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 6e17e00340e..ebb87e27a5e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5849,7 +5849,7 @@ fold (expr) && ! contains_placeholder_p (arg0)) { tree arg = save_expr (arg0); - return build (PLUS_EXPR, type, arg, arg); + return fold (build (PLUS_EXPR, type, arg, arg)); } if (flag_unsafe_math_optimizations) @@ -5857,17 +5857,25 @@ fold (expr) enum built_in_function fcode0 = builtin_mathfn_code (arg0); enum built_in_function fcode1 = builtin_mathfn_code (arg1); - /* Optimize sqrt(x)*sqrt(y) as sqrt(x*y). */ + /* Optimizations of sqrt(...)*sqrt(...). */ if ((fcode0 == BUILT_IN_SQRT && fcode1 == BUILT_IN_SQRT) || (fcode0 == BUILT_IN_SQRTF && fcode1 == BUILT_IN_SQRTF) || (fcode0 == BUILT_IN_SQRTL && fcode1 == BUILT_IN_SQRTL)) { - tree sqrtfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); - tree arg = build (MULT_EXPR, type, - TREE_VALUE (TREE_OPERAND (arg0, 1)), - TREE_VALUE (TREE_OPERAND (arg1, 1))); - tree arglist = build_tree_list (NULL_TREE, arg); - return fold (build_function_call_expr (sqrtfn, arglist)); + tree sqrtfn, arg, arglist; + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + + /* Optimize sqrt(x)*sqrt(x) as x. */ + if (operand_equal_p (arg00, arg10, 0) + && ! HONOR_SNANS (TYPE_MODE (type))) + return arg00; + + /* Optimize sqrt(x)*sqrt(y) as sqrt(x*y). */ + sqrtfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + arg = fold (build (MULT_EXPR, type, arg00, arg10)); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (sqrtfn, arglist); } /* Optimize exp(x)*exp(y) as exp(x+y). */ @@ -5879,8 +5887,43 @@ fold (expr) tree arg = build (PLUS_EXPR, type, TREE_VALUE (TREE_OPERAND (arg0, 1)), TREE_VALUE (TREE_OPERAND (arg1, 1))); - tree arglist = build_tree_list (NULL_TREE, arg); - return fold (build_function_call_expr (expfn, arglist)); + tree arglist = build_tree_list (NULL_TREE, fold (arg)); + return build_function_call_expr (expfn, arglist); + } + + /* Optimizations of pow(...)*pow(...). */ + if ((fcode0 == BUILT_IN_POW && fcode1 == BUILT_IN_POW) + || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF) + || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL)) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, + 1))); + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, + 1))); + + /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y). */ + if (operand_equal_p (arg01, arg11, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = build (MULT_EXPR, type, arg00, arg10); + tree arglist = tree_cons (NULL_TREE, fold (arg), + build_tree_list (NULL_TREE, + arg01)); + return build_function_call_expr (powfn, arglist); + } + + /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z). */ + if (operand_equal_p (arg00, arg10, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = fold (build (PLUS_EXPR, type, arg01, arg11)); + tree arglist = tree_cons (NULL_TREE, arg00, + build_tree_list (NULL_TREE, + arg)); + return build_function_call_expr (powfn, arglist); + } } } } @@ -6052,10 +6095,10 @@ fold (expr) TREE_OPERAND (arg1, 1))); } - /* Optimize x/exp(y) into x*exp(-y). */ if (flag_unsafe_math_optimizations) { enum built_in_function fcode = builtin_mathfn_code (arg1); + /* Optimize x/exp(y) into x*exp(-y). */ if (fcode == BUILT_IN_EXP || fcode == BUILT_IN_EXPF || fcode == BUILT_IN_EXPL) @@ -6063,10 +6106,25 @@ fold (expr) tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0); tree arg = build1 (NEGATE_EXPR, type, TREE_VALUE (TREE_OPERAND (arg1, 1))); - tree arglist = build_tree_list (NULL_TREE, arg); + tree arglist = build_tree_list (NULL_TREE, fold (arg)); arg1 = build_function_call_expr (expfn, arglist); return fold (build (MULT_EXPR, type, arg0, arg1)); } + + /* Optimize x/pow(y,z) into x*pow(y,-z). */ + if (fcode == BUILT_IN_POW + || fcode == BUILT_IN_POWF + || fcode == BUILT_IN_POWL) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0); + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1))); + tree neg11 = fold (build1 (NEGATE_EXPR, type, arg11)); + tree arglist = tree_cons(NULL_TREE, arg10, + build_tree_list (NULL_TREE, neg11)); + arg1 = build_function_call_expr (powfn, arglist); + return fold (build (MULT_EXPR, type, arg0, arg1)); + } } goto binary; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 09890c71bea..857d1e54638 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-04-08 Roger Sayle + + * gcc.dg/builtins-11.c: New test case. + 2003-04-08 Roger Sayle * gcc.dg/builtins-9.c: New test case. diff --git a/gcc/testsuite/gcc.dg/builtins-11.c b/gcc/testsuite/gcc.dg/builtins-11.c new file mode 100644 index 00000000000..a2ff257b9ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-11.c @@ -0,0 +1,46 @@ +/* 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, 5th April 2003. */ + +/* { dg-do link } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern void link_error(void); + +extern double exp(double); +extern double sqrt(double); +extern double pow(double,double); + +void test(double x, double y, double z) +{ + if (sqrt(x)*sqrt(x) != x) + link_error (); + + if (sqrt(x)*sqrt(y) != sqrt(x*y)) + link_error (); + + if (exp(x)*exp(y) != exp(x+y)) + link_error (); + + if (pow(x,y)*pow(z,y) != pow(z*x,y)) + link_error (); + + if (pow(x,y)*pow(x,z) != pow(x,y+z)) + link_error (); + + if (x/exp(y) != x*exp(-y)) + link_error (); + + if (x/pow(y,z) != x*pow(y,-z)) + link_error (); +} + +int main() +{ + test (2.0, 3.0, 4.0); + return 0; +} +