This moves sqrt simplification from GENERIC to patterns. The testcase adjustment shows one of the side-effects I mentioned in 1/n - simplification is delayed to SSA and for the testcase we have to trick CCP not folding everything to a constant before the expression simplification is done in forwprops folding of all statements.
Boostrap and regtest ongoing on x86_64-unknown-linux-gnu. Richard. 2014-12-03 Richard Biener <rguent...@suse.de> PR middle-end/14541 * builtins.c (fold_builtin_sqrt): Implement simplifications ... * match.pd: ... here as patterns. * gcc.dg/builtins-47.c: Adjust. Index: gcc/match.pd =================================================================== *** gcc/match.pd.orig 2014-12-03 12:50:07.645992434 +0100 --- gcc/match.pd 2014-12-03 13:01:55.332967931 +0100 *************** along with GCC; see the file COPYING3. *** 1005,1007 **** --- 1005,1034 ---- (logs (pows @0 @1)) (mult @1 (logs @0))))) + + /* fold_builtin_sqrt */ + (if (flag_unsafe_math_optimizations) + /* Optimize sqrt(expN(x)) = expN(x*0.5). */ + (for expfn (EXP10 POW10 EXP EXP2) + sqrtfn (SQRT) + (simplify + (sqrtfn (expfn @0)) + (expfn (mult @0 { build_real (type, dconsthalf); })))) + /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */ + (for rootfn (SQRT CBRT) + sqrtfn (SQRT) + powfn (POW) + (simplify + (sqrtfn (rootfn @0)) + (with + { REAL_VALUE_TYPE dconstroot; + if (BUILTIN_SQRT_P (rootfn)) dconstroot = dconsthalf; + else dconstroot = dconst_third (); + /* Adjust for the outer root. */ + SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); + dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); } + (powfn @0 { build_real (type, dconstroot); })))) + /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5). */ + (simplify + (SQRT (POW @0 @1)) + (POW (abs @0) (mult @1 { build_real (TREE_TYPE (@1), dconsthalf); })))) Index: gcc/builtins.c =================================================================== *** gcc/builtins.c.orig 2014-12-03 12:50:06.292992480 +0100 --- gcc/builtins.c 2014-12-03 13:01:55.335967931 +0100 *************** static bool integer_valued_real_p (tree) *** 164,170 **** static tree fold_trunc_transparent_mathfn (location_t, tree, tree); static rtx expand_builtin_fabs (tree, rtx, rtx); static rtx expand_builtin_signbit (tree, rtx); - static tree fold_builtin_sqrt (location_t, tree, tree); static tree fold_builtin_cbrt (location_t, tree, tree); static tree fold_builtin_pow (location_t, tree, tree, tree, tree); static tree fold_builtin_powi (location_t, tree, tree, tree, tree); --- 164,169 ---- *************** fold_builtin_cproj (location_t loc, tree *** 7725,7804 **** return NULL_TREE; } - /* Fold a builtin function call to sqrt, sqrtf, or sqrtl with argument ARG. - Return NULL_TREE if no simplification can be made. */ - - static tree - fold_builtin_sqrt (location_t loc, tree arg, tree type) - { - - enum built_in_function fcode; - tree res; - - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Calculate the result when the argument is a constant. */ - if ((res = do_mpfr_arg1 (arg, type, mpfr_sqrt, &dconst0, NULL, true))) - return res; - - /* Optimize sqrt(expN(x)) = expN(x*0.5). */ - fcode = builtin_mathfn_code (arg); - if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode)) - { - tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0); - arg = fold_build2_loc (loc, MULT_EXPR, type, - CALL_EXPR_ARG (arg, 0), - build_real (type, dconsthalf)); - return build_call_expr_loc (loc, expfn, 1, arg); - } - - /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */ - if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode)) - { - tree powfn = mathfn_built_in (type, BUILT_IN_POW); - - if (powfn) - { - tree arg0 = CALL_EXPR_ARG (arg, 0); - tree tree_root; - /* The inner root was either sqrt or cbrt. */ - /* This was a conditional expression but it triggered a bug - in Sun C 5.5. */ - REAL_VALUE_TYPE dconstroot; - if (BUILTIN_SQRT_P (fcode)) - dconstroot = dconsthalf; - else - dconstroot = dconst_third (); - - /* Adjust for the outer root. */ - SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); - dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); - tree_root = build_real (type, dconstroot); - return build_call_expr_loc (loc, powfn, 2, arg0, tree_root); - } - } - - /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5). */ - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_POW - || fcode == BUILT_IN_POWF - || fcode == BUILT_IN_POWL)) - { - tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0); - tree arg0 = CALL_EXPR_ARG (arg, 0); - tree arg1 = CALL_EXPR_ARG (arg, 1); - tree narg1; - if (!tree_expr_nonnegative_p (arg0)) - arg0 = build1 (ABS_EXPR, type, arg0); - narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg1, - build_real (type, dconsthalf)); - return build_call_expr_loc (loc, powfn, 2, arg0, narg1); - } - - return NULL_TREE; - } - /* Fold a builtin function call to cbrt, cbrtf, or cbrtl with argument ARG. Return NULL_TREE if no simplification can be made. */ --- 7724,7729 ---- *************** fold_builtin_1 (location_t loc, tree fnd *** 10035,10041 **** return fold_builtin_carg (loc, arg0, type); CASE_FLT_FN (BUILT_IN_SQRT): ! return fold_builtin_sqrt (loc, arg0, type); CASE_FLT_FN (BUILT_IN_CBRT): return fold_builtin_cbrt (loc, arg0, type); --- 9960,9968 ---- return fold_builtin_carg (loc, arg0, type); CASE_FLT_FN (BUILT_IN_SQRT): ! if (validate_arg (arg0, REAL_TYPE)) ! return do_mpfr_arg1 (arg0, type, mpfr_sqrt, &dconst0, NULL, true); ! break; CASE_FLT_FN (BUILT_IN_CBRT): return fold_builtin_cbrt (loc, arg0, type); Index: gcc/testsuite/gcc.dg/builtins-47.c =================================================================== *** gcc/testsuite/gcc.dg/builtins-47.c.orig 2011-10-10 16:22:07.000000000 +0200 --- gcc/testsuite/gcc.dg/builtins-47.c 2014-12-03 13:26:32.379916791 +0100 *************** *** 1,13 **** /* { dg-do run } */ ! /* { dg-options "-O -ffast-math -fdump-tree-gimple" } */ extern double sqrt (double); extern double pow (double, double); extern void abort (void); int main () { - double x = -1.0; if (sqrt (pow (x, 2)) != 1.0) abort(); if (sqrt (x*x) != 1.0) --- 1,14 ---- /* { dg-do run } */ ! /* { dg-options "-O -ffast-math -fdump-tree-cddce1" } */ extern double sqrt (double); extern double pow (double, double); extern void abort (void); + double x = -1.0; + int main () { if (sqrt (pow (x, 2)) != 1.0) abort(); if (sqrt (x*x) != 1.0) *************** int main () *** 15,20 **** return 0; } ! /* { dg-final { scan-tree-dump-times "sqrt" 0 "gimple" } } */ ! /* { dg-final { scan-tree-dump-times "pow" 0 "gimple" } } */ /* { dg-final { cleanup-tree-dump "gimple" } } */ --- 16,21 ---- return 0; } ! /* { dg-final { scan-tree-dump-times "sqrt" 0 "cddce1" } } */ ! /* { dg-final { scan-tree-dump-times "pow" 0 "cddce1" } } */ /* { dg-final { cleanup-tree-dump "gimple" } } */