From d86dc3036d4ecd0432daad6a66dee219110cba5a Mon Sep 17 00:00:00 2001 From: "Kaveh R. Ghazi" Date: Wed, 9 Mar 2005 20:11:48 +0000 Subject: [PATCH] builtins.c (fold_builtin_cbrt, [...]): Rearrange code. * builtins.c (fold_builtin_cbrt, fold_builtin_pow): Rearrange code. Add more cbrt transformations. testsuite: * gcc.dg/builtins-10.c: Reactivate disabled test. * gcc.dg/torture/builtin-power-1.c: Likewise. Also add tests for new cbrt transformations. From-SVN: r96206 --- gcc/ChangeLog | 5 + gcc/builtins.c | 182 ++++++++++++------ gcc/testsuite/ChangeLog | 6 + gcc/testsuite/gcc.dg/builtins-10.c | 4 +- .../gcc.dg/torture/builtin-power-1.c | 47 +++-- 5 files changed, 161 insertions(+), 83 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e90219878e6..dddd9abdd83 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2005-03-09 Kaveh R. Ghazi + + * builtins.c (fold_builtin_cbrt, fold_builtin_pow): Rearrange + code. Add more cbrt transformations. + 2005-03-09 Kaveh R. Ghazi * fold-const.c (fold_unary_to_constant): Add FIX_ROUND_EXPR case. diff --git a/gcc/builtins.c b/gcc/builtins.c index 5d9aa77f4e7..b113d9f770e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -6311,40 +6311,82 @@ fold_builtin_cbrt (tree arglist, tree type) if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg)) return arg; - /* Optimize cbrt(expN(x)) -> expN(x/3). */ - if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode)) - { - tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); - const REAL_VALUE_TYPE third_trunc = - real_value_truncate (TYPE_MODE (type), dconstthird); - arg = fold (build2 (MULT_EXPR, type, - TREE_VALUE (TREE_OPERAND (arg, 1)), - build_real (type, third_trunc))); - arglist = build_tree_list (NULL_TREE, arg); - return build_function_call_expr (expfn, arglist); - } - - /* Optimize cbrt(sqrt(x)) -> pow(x,1/6). */ - /* We don't optimize cbrt(cbrt(x)) -> pow(x,1/9) because if - x is negative pow will error but cbrt won't. */ - if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode)) + if (flag_unsafe_math_optimizations) { - tree powfn = mathfn_built_in (type, BUILT_IN_POW); + /* Optimize cbrt(expN(x)) -> expN(x/3). */ + if (BUILTIN_EXPONENT_P (fcode)) + { + tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); + const REAL_VALUE_TYPE third_trunc = + real_value_truncate (TYPE_MODE (type), dconstthird); + arg = fold (build2 (MULT_EXPR, type, + TREE_VALUE (TREE_OPERAND (arg, 1)), + build_real (type, third_trunc))); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (expfn, arglist); + } - if (powfn) - { - tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); - tree tree_root; - REAL_VALUE_TYPE dconstroot = dconstthird; + /* Optimize cbrt(sqrt(x)) -> pow(x,1/6). */ + if (BUILTIN_SQRT_P (fcode)) + { + tree powfn = mathfn_built_in (type, BUILT_IN_POW); - SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); - dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); - tree_root = build_real (type, dconstroot); - arglist = tree_cons (NULL_TREE, arg0, - build_tree_list (NULL_TREE, tree_root)); - return build_function_call_expr (powfn, arglist); + if (powfn) + { + tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); + tree tree_root; + REAL_VALUE_TYPE dconstroot = dconstthird; + + SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); + dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); + tree_root = build_real (type, dconstroot); + arglist = tree_cons (NULL_TREE, arg0, + build_tree_list (NULL_TREE, tree_root)); + return build_function_call_expr (powfn, arglist); + } } + /* Optimize cbrt(cbrt(x)) -> pow(x,1/9) iff x is nonnegative. */ + if (BUILTIN_CBRT_P (fcode)) + { + tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); + if (tree_expr_nonnegative_p (arg0)) + { + tree powfn = mathfn_built_in (type, BUILT_IN_POW); + + if (powfn) + { + tree tree_root; + REAL_VALUE_TYPE dconstroot; + + real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird); + dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); + tree_root = build_real (type, dconstroot); + arglist = tree_cons (NULL_TREE, arg0, + build_tree_list (NULL_TREE, tree_root)); + return build_function_call_expr (powfn, arglist); + } + } + } + + /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative. */ + if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF + || fcode == BUILT_IN_POWL) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); + if (tree_expr_nonnegative_p (arg00)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0); + const REAL_VALUE_TYPE dconstroot + = real_value_truncate (TYPE_MODE (type), dconstthird); + tree narg01 = fold (build2 (MULT_EXPR, type, arg01, + build_real (type, dconstroot))); + arglist = tree_cons (NULL_TREE, arg00, + build_tree_list (NULL_TREE, narg01)); + return build_function_call_expr (powfn, arglist); + } + } } return NULL_TREE; } @@ -6849,7 +6891,6 @@ fold_builtin_logarithm (tree exp, const REAL_VALUE_TYPE *value) static tree fold_builtin_pow (tree fndecl, tree arglist, tree type) { - enum built_in_function fcode; tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); @@ -6928,42 +6969,61 @@ fold_builtin_pow (tree fndecl, tree arglist, tree type) } } - /* Optimize pow(expN(x),y) = expN(x*y). */ - fcode = builtin_mathfn_code (arg0); - if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode)) + if (flag_unsafe_math_optimizations) { - tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); - tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); - arg = fold (build2 (MULT_EXPR, type, arg, arg1)); - arglist = build_tree_list (NULL_TREE, arg); - return build_function_call_expr (expfn, arglist); - } + const enum built_in_function fcode = builtin_mathfn_code (arg0); - /* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */ - if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode)) - { - tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1)); - tree narg1 = fold (build2 (MULT_EXPR, type, arg1, - build_real (type, dconsthalf))); + /* Optimize pow(expN(x),y) = expN(x*y). */ + if (BUILTIN_EXPONENT_P (fcode)) + { + tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); + arg = fold (build2 (MULT_EXPR, type, arg, arg1)); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (expfn, arglist); + } - arglist = tree_cons (NULL_TREE, narg0, - build_tree_list (NULL_TREE, narg1)); - return build_function_call_expr (fndecl, arglist); - } + /* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */ + if (BUILTIN_SQRT_P (fcode)) + { + tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree narg1 = fold (build2 (MULT_EXPR, type, arg1, + build_real (type, dconsthalf))); - /* Optimize pow(pow(x,y),z) = pow(x,y*z). */ - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_POW - || fcode == BUILT_IN_POWF - || fcode == BUILT_IN_POWL)) - { - tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); - tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1))); - tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1)); - arglist = tree_cons (NULL_TREE, arg00, - build_tree_list (NULL_TREE, narg1)); - return build_function_call_expr (fndecl, arglist); + arglist = tree_cons (NULL_TREE, narg0, + build_tree_list (NULL_TREE, narg1)); + return build_function_call_expr (fndecl, arglist); + } + + /* Optimize pow(cbrt(x),y) = pow(x,y/3) iff x is nonnegative. */ + if (BUILTIN_CBRT_P (fcode)) + { + tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); + if (tree_expr_nonnegative_p (arg)) + { + const REAL_VALUE_TYPE dconstroot + = real_value_truncate (TYPE_MODE (type), dconstthird); + tree narg1 = fold (build2 (MULT_EXPR, type, arg1, + build_real (type, dconstroot))); + arglist = tree_cons (NULL_TREE, arg, + build_tree_list (NULL_TREE, narg1)); + return build_function_call_expr (fndecl, arglist); + } + } + + /* Optimize pow(pow(x,y),z) = pow(x,y*z). */ + if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF + || fcode == BUILT_IN_POWL) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1))); + tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1)); + arglist = tree_cons (NULL_TREE, arg00, + build_tree_list (NULL_TREE, narg1)); + return build_function_call_expr (fndecl, arglist); + } } + return NULL_TREE; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fd38a0ef1c8..9d40f911286 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2005-03-09 Kaveh R. Ghazi + + * gcc.dg/builtins-10.c: Reactivate disabled test. + * gcc.dg/torture/builtin-power-1.c: Likewise. Also add tests for + new cbrt transformations. + 2005-03-09 Mark Mitchell PR c++/20208 diff --git a/gcc/testsuite/gcc.dg/builtins-10.c b/gcc/testsuite/gcc.dg/builtins-10.c index 53158a0f852..d90e61ab326 100644 --- a/gcc/testsuite/gcc.dg/builtins-10.c +++ b/gcc/testsuite/gcc.dg/builtins-10.c @@ -18,8 +18,8 @@ extern double fabs(double); void test(double x) { - /*if (sqrt(pow(x,4.0)) != x*x) - link_error (); */ + if (sqrt(pow(x,4.0)) != x*x) + link_error (); if (pow(sqrt(x),4.0) != x*x) link_error (); diff --git a/gcc/testsuite/gcc.dg/torture/builtin-power-1.c b/gcc/testsuite/gcc.dg/torture/builtin-power-1.c index 7cdc00c23fb..7b890bb0816 100644 --- a/gcc/testsuite/gcc.dg/torture/builtin-power-1.c +++ b/gcc/testsuite/gcc.dg/torture/builtin-power-1.c @@ -22,6 +22,7 @@ extern float FN##f(float, float); \ extern long double FN##l(long double, long double); +PROTOTYPE(fabs) PROTOTYPE(sqrt) PROTOTYPE(cbrt) PROTOTYPE2(pow) @@ -32,39 +33,45 @@ void test(double d1, double d2, double d3, { /* Test N1root(N2root(x)) -> pow(x,1/(N1*N2)). */ /* E.g. sqrt(cbrt(x)) -> pow(x,1/6). */ -#define ROOT_ROOT(FN1,N1,FN2,N2) \ + /* The `ABS' argument is `fabs' when the transformation only works + for nonnegative arguments. Otherwise it's blank. */ +#define ROOT_ROOT(FN1,N1,FN2,N2,ABS) \ extern void link_failure_##FN1##_##FN2(void); \ - if (FN1(FN2(d1)) != pow(d1,1.0/(N1*N2)) \ - || C99CODE (FN1##f(FN2##f(f1)) != powf(f1,1.0F/(N1*N2))) \ - || C99CODE (FN1##l(FN2##l(ld1)) != powl(ld1,1.0L/(N1*N2)))) \ + if (FN1(FN2(ABS(d1))) != pow(ABS(d1),1.0/(N1*N2)) \ + || C99CODE (FN1##f(FN2##f(ABS(f1))) != powf(ABS(f1),1.0F/(N1*N2))) \ + || C99CODE (FN1##l(FN2##l(ABS(ld1))) != powl(ABS(ld1),1.0L/(N1*N2)))) \ link_failure_##FN1##_##FN2() - ROOT_ROOT(sqrt,2,sqrt,2); - ROOT_ROOT(sqrt,2,cbrt,3); - ROOT_ROOT(cbrt,3,sqrt,2); - /*ROOT_ROOT(cbrt,3,cbrt,3); Intentionally not implemented. */ + ROOT_ROOT(sqrt,2,sqrt,2,); + ROOT_ROOT(sqrt,2,cbrt,3,); + ROOT_ROOT(cbrt,3,sqrt,2,); + ROOT_ROOT(cbrt,3,cbrt,3,fabs); /* Test pow(Nroot(x),y) -> pow(x,y/N). */ -#define POW_ROOT(FN,N) \ + /* The `ABS' argument is `fabs' when the transformation only works + for nonnegative arguments. Otherwise it's blank. */ +#define POW_ROOT(FN,N,ABS) \ extern void link_failure_pow_##FN(void); \ - if (pow(FN(d1), d2) != pow(d1,d2/N) \ - || powf(FN##f(f1),f2) != powf(f1,f2/N) \ - || powl(FN##l(ld1),ld2) != powl(ld1,ld2/N)) \ + if (pow(FN(ABS(d1)), d2) != pow(ABS(d1),d2/N) \ + || powf(FN##f(ABS(f1)),f2) != powf(ABS(f1),f2/N) \ + || powl(FN##l(ABS(ld1)),ld2) != powl(ABS(ld1),ld2/N)) \ link_failure_pow_##FN() - POW_ROOT(sqrt,2); - /*POW_ROOT(cbrt,3); Intentionally not implemented. */ + POW_ROOT(sqrt,2,); + POW_ROOT(cbrt,3,fabs); /* Test Nroot(pow(x,y)) -> pow(x,y/N). */ -#define ROOT_POW(FN,N) \ + /* The `ABS' argument is `fabs' when the transformation only works + for nonnegative arguments. Otherwise it's blank. */ +#define ROOT_POW(FN,N,ABS) \ extern void link_failure_##FN##_pow(void); \ - if (FN(pow(d1, d2)) != pow(d1,d2/N) \ - || FN##f(powf(f1,f2)) != powf(f1,f2/N) \ - || FN##l(powl(ld1,ld2)) != powl(ld1,ld2/N)) \ + if (FN(pow(ABS(d1), d2)) != pow(ABS(d1),d2/N) \ + || FN##f(powf(ABS(f1),f2)) != powf(ABS(f1),f2/N) \ + || FN##l(powl(ABS(ld1),ld2)) != powl(ABS(ld1),ld2/N)) \ link_failure_##FN##_pow() - /*ROOT_POW(sqrt,2); Invalid. */ - /*ROOT_POW(cbrt,3); Intentionally not implemented. */ + ROOT_POW(sqrt,2,fabs); + ROOT_POW(cbrt,3,fabs); /* Test pow(pow(x,y),z) -> pow(x,y*z). */ #define POW_POW \ -- 2.30.2