From b53fed56360bb38807b13ec7b3c83d34c6b0b81a Mon Sep 17 00:00:00 2001 From: "Kaveh R. Ghazi" Date: Tue, 24 Oct 2006 17:44:36 +0000 Subject: [PATCH] re PR middle-end/29335 (transcendental functions with constant arguments should be resolved at compile-time) PR middle-end/29335 * builtins.c (fold_builtin_sin, fold_builtin_atan): Remove. (do_mpfr_arg1): Add `min', `max' and `inclusive' arguments. Update all callers. (BUILT_IN_SIN, BUILT_IN_ATAN): Handle in main switch. (BUILT_IN_ASIN, BUILT_IN_ACOS, BUILT_IN_ATAN, BUILT_IN_ASINH, BUILT_IN_ACOSH, BUILT_IN_ATANH, BUILT_IN_SINH, BUILT_IN_COSH, BUILT_IN_TANH): Calculate compile-time arguments using MPFR. testsuite: * gcc.dg/torture/builtin-math-3.c: New test. From-SVN: r118009 --- gcc/ChangeLog | 12 ++ gcc/builtins.c | 142 ++++++++++-------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/torture/builtin-math-3.c | 71 +++++++++ 4 files changed, 165 insertions(+), 64 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-math-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 811fd4c16bc..d47b94b74cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2006-10-24 Kaveh R. Ghazi + + PR middle-end/29335 + * builtins.c (fold_builtin_sin, fold_builtin_atan): Remove. + (do_mpfr_arg1): Add `min', `max' and `inclusive' arguments. + Update all callers. + (BUILT_IN_SIN, BUILT_IN_ATAN): Handle in main switch. + (BUILT_IN_ASIN, BUILT_IN_ACOS, BUILT_IN_ATAN, BUILT_IN_ASINH, + BUILT_IN_ACOSH, BUILT_IN_ATANH, BUILT_IN_SINH, BUILT_IN_COSH, + BUILT_IN_TANH): Calculate compile-time arguments using MPFR. + 2006-10-24 Richard Guenther PR middle-end/28796 @@ -21,6 +32,7 @@ 2006-10-24 Kaveh R. Ghazi + PR middle-end/29335 * builtins.c (fold_builtin_exponent): Evaluate constant arguments at compile-time using MPFR. Change parameter VALUE to FUNC, update all callers. diff --git a/gcc/builtins.c b/gcc/builtins.c index f77f8b24a1a..ebb9a857629 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -150,10 +150,8 @@ static tree fold_builtin_sqrt (tree, tree); static tree fold_builtin_cbrt (tree, tree); static tree fold_builtin_pow (tree, tree, tree); static tree fold_builtin_powi (tree, tree, tree); -static tree fold_builtin_sin (tree, tree); static tree fold_builtin_cos (tree, tree, tree); static tree fold_builtin_tan (tree, tree); -static tree fold_builtin_atan (tree, tree); static tree fold_builtin_trunc (tree, tree); static tree fold_builtin_floor (tree, tree); static tree fold_builtin_ceil (tree, tree); @@ -205,7 +203,8 @@ static unsigned HOST_WIDE_INT target_s; static char target_percent_c[3]; static char target_percent_s[3]; static char target_percent_s_newline[4]; -static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t), + const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, bool); /* Return true if NODE should be considered for inline expansion regardless of the optimization level. This means whenever a function is invoked with @@ -7204,23 +7203,6 @@ fold_builtin_cbrt (tree arglist, tree type) return NULL_TREE; } -/* Fold function call to builtin sin, sinf, or sinl. Return - NULL_TREE if no simplification can be made. */ -static tree -fold_builtin_sin (tree arglist, tree type) -{ - tree arg = TREE_VALUE (arglist), res; - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Calculate the result when the argument is a constant. */ - if ((res = do_mpfr_arg1 (arg, type, mpfr_sin))) - return res; - - return NULL_TREE; -} - /* Fold function call to builtin cos, cosf, or cosl. Return NULL_TREE if no simplification can be made. */ static tree @@ -7232,7 +7214,7 @@ fold_builtin_cos (tree arglist, tree type, tree fndecl) return NULL_TREE; /* Calculate the result when the argument is a constant. */ - if ((res = do_mpfr_arg1 (arg, type, mpfr_cos))) + if ((res = do_mpfr_arg1 (arg, type, mpfr_cos, NULL, NULL, 0))) return res; /* Optimize cos(-x) into cos (x). */ @@ -7258,7 +7240,7 @@ fold_builtin_tan (tree arglist, tree type) return NULL_TREE; /* Calculate the result when the argument is a constant. */ - if ((res = do_mpfr_arg1 (arg, type, mpfr_tan))) + if ((res = do_mpfr_arg1 (arg, type, mpfr_tan, NULL, NULL, 0))) return res; /* Optimize tan(atan(x)) = x. */ @@ -7272,35 +7254,6 @@ fold_builtin_tan (tree arglist, tree type) return NULL_TREE; } -/* Fold function call to builtin atan, atanf, or atanl. Return - NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_atan (tree arglist, tree type) -{ - - tree arg = TREE_VALUE (arglist); - - if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - return NULL_TREE; - - /* Optimize atan(0.0) = 0.0. */ - if (real_zerop (arg)) - return arg; - - /* Optimize atan(1.0) = pi/4. */ - if (real_onep (arg)) - { - REAL_VALUE_TYPE cst; - - real_convert (&cst, TYPE_MODE (type), &dconstpi); - SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2); - return build_real (type, cst); - } - - return NULL_TREE; -} - /* Fold function call to builtin trunc, truncf or truncl. Return NULL_TREE if no simplification can be made. */ @@ -7924,7 +7877,7 @@ fold_builtin_exponent (tree fndecl, tree arglist, tree arg = TREE_VALUE (arglist), res; /* Calculate the result when the argument is a constant. */ - if ((res = do_mpfr_arg1 (arg, type, func))) + if ((res = do_mpfr_arg1 (arg, type, func, NULL, NULL, 0))) return res; /* Optimize expN(logN(x)) = x. */ @@ -9026,12 +8979,72 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) CASE_FLT_FN (BUILT_IN_CBRT): return fold_builtin_cbrt (arglist, type); + CASE_FLT_FN (BUILT_IN_ASIN): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_asin, + &dconstm1, &dconst1, true); + break; + + CASE_FLT_FN (BUILT_IN_ACOS): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_acos, + &dconstm1, &dconst1, true); + break; + + CASE_FLT_FN (BUILT_IN_ATAN): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_atan, + NULL, NULL, 0); + break; + + CASE_FLT_FN (BUILT_IN_ASINH): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_asinh, + NULL, NULL, 0); + break; + + CASE_FLT_FN (BUILT_IN_ACOSH): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_acosh, + &dconst1, NULL, true); + break; + + CASE_FLT_FN (BUILT_IN_ATANH): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_atanh, + &dconstm1, &dconst1, false); + break; + CASE_FLT_FN (BUILT_IN_SIN): - return fold_builtin_sin (arglist, type); + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_sin, + NULL, NULL, 0); + break; CASE_FLT_FN (BUILT_IN_COS): return fold_builtin_cos (arglist, type, fndecl); + CASE_FLT_FN (BUILT_IN_TAN): + return fold_builtin_tan (arglist, type); + + CASE_FLT_FN (BUILT_IN_SINH): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_sinh, + NULL, NULL, 0); + break; + + CASE_FLT_FN (BUILT_IN_COSH): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_cosh, + NULL, NULL, 0); + break; + + CASE_FLT_FN (BUILT_IN_TANH): + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_tanh, + NULL, NULL, 0); + break; + CASE_FLT_FN (BUILT_IN_EXP): return fold_builtin_exponent (fndecl, arglist, mpfr_exp); @@ -9051,12 +9064,6 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) CASE_FLT_FN (BUILT_IN_LOG10): return fold_builtin_logarithm (fndecl, arglist, &dconst10); - CASE_FLT_FN (BUILT_IN_TAN): - return fold_builtin_tan (arglist, type); - - CASE_FLT_FN (BUILT_IN_ATAN): - return fold_builtin_atan (arglist, type); - CASE_FLT_FN (BUILT_IN_POW): return fold_builtin_pow (fndecl, arglist, type); @@ -11269,12 +11276,17 @@ init_target_chars (void) /* If argument ARG is a REAL_CST, call the one-argument mpfr function FUNC on it and return the resulting value as a tree with type TYPE. - The mpfr precision is set to the precision of TYPE. We assume that - function FUNC returns zero if the result could be calculated - exactly within the requested precision. */ + If MIN and/or MAX are not NULL, then the supplied ARG must be + within those bounds. If INCLUSIVE is true, then MIN/MAX are + acceptable values, otherwise they are not. The mpfr precision is + set to the precision of TYPE. We assume that function FUNC returns + zero if the result could be calculated exactly within the requested + precision. */ static tree -do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t)) +do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t), + const REAL_VALUE_TYPE *min, const REAL_VALUE_TYPE *max, + bool inclusive) { tree result = NULL_TREE; @@ -11284,7 +11296,9 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t)) { REAL_VALUE_TYPE r = TREE_REAL_CST (arg); - if (!real_isnan (&r) && !real_isinf (&r)) + if (!real_isnan (&r) && !real_isinf (&r) + && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , &r, min)) + && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , &r, max))) { const enum machine_mode mode = TYPE_MODE (type); const int prec = REAL_MODE_FORMAT (mode)->p; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 87c2154f9e1..97e3f75c6ac 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2006-10-24 Kaveh R. Ghazi + + * gcc.dg/torture/builtin-math-3.c: New test. + 2006-10-24 Erik Edelmann PR fortran/29393 diff --git a/gcc/testsuite/gcc.dg/torture/builtin-math-3.c b/gcc/testsuite/gcc.dg/torture/builtin-math-3.c new file mode 100644 index 00000000000..60f030b6e04 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-math-3.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2006 Free Software Foundation. + + Verify that built-in math function constant folding of constant + arguments is correctly performed by the compiler. + + Origin: Kaveh R. Ghazi, October 23, 2006. */ + +/* { dg-do link } */ + +/* All references to link_error should go away at compile-time. */ +extern void link_error(int); + +/* Test that FUNC(ARG) == (RES). */ +#define TESTIT(FUNC,ARG,RES) do { \ + if (__builtin_##FUNC##f(ARG) != RES) \ + link_error(__LINE__); \ + if (__builtin_##FUNC(ARG) != RES) \ + link_error(__LINE__); \ + if (__builtin_##FUNC##l(ARG) != RES) \ + link_error(__LINE__); \ + } while (0); + +/* Test that (LOW) < FUNC(ARG) < (HI). */ +#define TESTIT2(FUNC,ARG,LOW,HI) do { \ + if (__builtin_##FUNC##f(ARG) <= (LOW) || __builtin_##FUNC##f(ARG) >= (HI)) \ + link_error(__LINE__); \ + if (__builtin_##FUNC(ARG) <= (LOW) || __builtin_##FUNC(ARG) >= (HI)) \ + link_error(__LINE__); \ + if (__builtin_##FUNC##l(ARG) <= (LOW) || __builtin_##FUNC##l(ARG) >= (HI)) \ + link_error(__LINE__); \ + } while (0); + +int main (void) +{ + TESTIT2 (asin, -1, -3.15/2, -3.14/2); /* asin(-1) == -pi/2 */ + TESTIT (asin, 0, 0); /* asin(0) == 0 */ + TESTIT2 (asin, 1, 3.14/2, 3.15/2); /* asin(1) == pi/2 */ + + TESTIT2 (acos, -1, 3.14, 3.15); /* acos(-1) == pi */ + TESTIT2 (acos, 0, 3.14/2, 3.15/2); /* acos(0) == pi/2 */ + TESTIT (acos, 1, 0); /* acos(1) == 0 */ + + TESTIT2 (atan, -1, -3.15/4, -3.14/4); /* atan(-1) == -pi/4 */ + TESTIT (atan, 0, 0); /* atan(0) == 0 */ + TESTIT2 (atan, 1, 3.14/4, 3.15/4); /* atan(1) == pi/4 */ + + TESTIT2 (asinh, -1, -0.89, -0.88); /* asinh(-1) == -0.881... */ + TESTIT (asinh, 0, 0); /* asinh(0) == 0 */ + TESTIT2 (asinh, 1, 0.88, 0.89); /* asinh(1) == 0.881... */ + + TESTIT (acosh, 1, 0); /* acosh(1) == 0. */ + TESTIT2 (acosh, 2, 1.31, 1.32); /* acosh(2) == 1.316... */ + + TESTIT2 (atanh, -0.5, -0.55, -0.54); /* atanh(-0.5) == -0.549... */ + TESTIT (atanh, 0, 0); /* atanh(0) == 0 */ + TESTIT2 (atanh, 0.5, 0.54, 0.55); /* atanh(0.5) == 0.549... */ + + TESTIT2 (sinh, -1, -1.18, -1.17); /* sinh(-1) == -1.175... */ + TESTIT (sinh, 0, 0); /* sinh(0) == 0 */ + TESTIT2 (sinh, 1, 1.17, 1.18); /* sinh(1) == 1.175... */ + + TESTIT2 (cosh, -1, 1.54, 1.55); /* cosh(-1) == 1.543... */ + TESTIT (cosh, 0, 1); /* cosh(0) == 1 */ + TESTIT2 (cosh, 1, 1.54, 1.55); /* cosh(1) == 1.543... */ + + TESTIT2 (tanh, -1, -0.77, -0.76); /* tanh(-1) == -0.761... */ + TESTIT (tanh, 0, 0); /* tanh(0) == 0 */ + TESTIT2 (tanh, 1, 0.76, 0.77); /* tanh(1) == 0.761... */ + + return 0; +}