diff options
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/builtins.c | 88 | ||||
-rw-r--r-- | gcc/real.c | 44 | ||||
-rw-r--r-- | gcc/real.h | 8 |
4 files changed, 128 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26a10a8..8e31f4b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2006-10-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + PR middle-end/29335 + * builtins.c (fold_builtin_sin, fold_builtin_cos, + fold_builtin_tan): Fold all constant arguments. Take a "type" + argument as necessary. + (do_mpfr_arg1): New. + * real.c, real.h (real_from_mpfr, mpfr_from_real): New. + 2006-10-23 Bob Wilson <bob.wilson@acm.org> * config/xtensa/lib1funcs.asm: Use C-style comments. diff --git a/gcc/builtins.c b/gcc/builtins.c index 5bd927b..2d517f5 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -150,9 +150,9 @@ 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); +static tree fold_builtin_sin (tree, tree); static tree fold_builtin_cos (tree, tree, tree); -static tree fold_builtin_tan (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); @@ -205,6 +205,7 @@ 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)); /* Return true if NODE should be considered for inline expansion regardless of the optimization level. This means whenever a function is invoked with @@ -7206,17 +7207,17 @@ fold_builtin_cbrt (tree arglist, tree type) /* 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) +fold_builtin_sin (tree arglist, tree type) { - tree arg = TREE_VALUE (arglist); + tree arg = TREE_VALUE (arglist), res; if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) return NULL_TREE; - /* Optimize sin (0.0) = 0.0. */ - if (real_zerop (arg)) - return arg; - + /* Calculate the result when the argument is a constant. */ + if ((res = do_mpfr_arg1 (arg, type, mpfr_sin))) + return res; + return NULL_TREE; } @@ -7225,15 +7226,15 @@ fold_builtin_sin (tree arglist) static tree fold_builtin_cos (tree arglist, tree type, tree fndecl) { - tree arg = TREE_VALUE (arglist); + tree arg = TREE_VALUE (arglist), res; if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) return NULL_TREE; - /* Optimize cos (0.0) = 1.0. */ - if (real_zerop (arg)) - return build_real (type, dconst1); - + /* Calculate the result when the argument is a constant. */ + if ((res = do_mpfr_arg1 (arg, type, mpfr_cos))) + return res; + /* Optimize cos(-x) into cos (x). */ if (TREE_CODE (arg) == NEGATE_EXPR) { @@ -7248,18 +7249,18 @@ fold_builtin_cos (tree arglist, tree type, tree fndecl) /* Fold function call to builtin tan, tanf, or tanl. Return NULL_TREE if no simplification can be made. */ static tree -fold_builtin_tan (tree arglist) +fold_builtin_tan (tree arglist, tree type) { enum built_in_function fcode; - tree arg = TREE_VALUE (arglist); + tree arg = TREE_VALUE (arglist), res; if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) return NULL_TREE; - /* Optimize tan(0.0) = 0.0. */ - if (real_zerop (arg)) - return arg; - + /* Calculate the result when the argument is a constant. */ + if ((res = do_mpfr_arg1 (arg, type, mpfr_tan))) + return res; + /* Optimize tan(atan(x)) = x. */ fcode = builtin_mathfn_code (arg); if (flag_unsafe_math_optimizations @@ -9039,7 +9040,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) return fold_builtin_cbrt (arglist, type); CASE_FLT_FN (BUILT_IN_SIN): - return fold_builtin_sin (arglist); + return fold_builtin_sin (arglist, type); CASE_FLT_FN (BUILT_IN_COS): return fold_builtin_cos (arglist, type, fndecl); @@ -9064,7 +9065,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) return fold_builtin_logarithm (fndecl, arglist, &dconst10); CASE_FLT_FN (BUILT_IN_TAN): - return fold_builtin_tan (arglist); + return fold_builtin_tan (arglist, type); CASE_FLT_FN (BUILT_IN_ATAN): return fold_builtin_atan (arglist, type); @@ -11278,3 +11279,48 @@ init_target_chars (void) } return true; } + +/* 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. */ + +static tree +do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t)) +{ + tree result = NULL_TREE; + + STRIP_NOPS (arg); + + if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) + { + REAL_VALUE_TYPE r = TREE_REAL_CST (arg); + + if (!real_isnan (&r) && !real_isinf (&r)) + { + const enum machine_mode mode = TYPE_MODE (type); + const int prec = REAL_MODE_FORMAT (mode)->p; + int exact; + mpfr_t m; + + mpfr_init2 (m, prec); + mpfr_from_real (m, &r); + exact = func (m, m, GMP_RNDN); + + /* Proceed iff we get a normal number, i.e. not NaN or Inf. + If -frounding-math is set, proceed iff the result of + calling FUNC was exact, i.e. FUNC returned zero. */ + if (mpfr_number_p (m) + && (! flag_rounding_math || exact == 0)) + { + real_from_mpfr (&r, m); + real_convert (&r, mode, &r); + result = build_real (type, r); + } + mpfr_clear (m); + } + } + + return result; +} @@ -4922,3 +4922,47 @@ real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x) r->sign = x->sign; } +/* Convert from REAL_VALUE_TYPE to MPFR. The caller is responsible + for initializing and clearing the MPFR parmeter. */ + +void +mpfr_from_real (mpfr_ptr m, const REAL_VALUE_TYPE *r) +{ + /* We use a string as an intermediate type. */ + char buf[128]; + + real_to_hexadecimal (buf, r, sizeof (buf), 0, 1); + /* mpfr_set_str() parses hexadecimal floats from strings in the same + format that GCC will output them. Nothing extra is needed. */ + gcc_assert (mpfr_set_str (m, buf, 16, GMP_RNDN) == 0); +} + +/* Convert from MPFR to REAL_VALUE_TYPE. */ + +void +real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m) +{ + /* We use a string as an intermediate type. */ + char buf[128], *rstr; + mp_exp_t exp; + + rstr = mpfr_get_str (NULL, &exp, 16, 0, m, GMP_RNDN); + + /* The additional 12 chars add space for the sprintf below. This + leaves 6 digits for the exponent which is supposedly enough. */ + gcc_assert (rstr != NULL && strlen (rstr) < sizeof (buf) - 12); + + /* REAL_VALUE_ATOF expects the exponent for mantissa * 2**exp, + mpfr_get_str returns the exponent for mantissa * 16**exp, adjust + for that. */ + exp *= 4; + + if (rstr[0] == '-') + sprintf (buf, "-0x.%sp%d", &rstr[1], (int) exp); + else + sprintf (buf, "0x.%sp%d", rstr, (int) exp); + + mpfr_free_str (rstr); + + real_from_string (r, buf); +} @@ -22,6 +22,8 @@ #ifndef GCC_REAL_H #define GCC_REAL_H +#include <gmp.h> +#include <mpfr.h> #include "machmode.h" /* An expanded form of the represented number. */ @@ -425,4 +427,10 @@ extern void real_round (REAL_VALUE_TYPE *, enum machine_mode, /* Set the sign of R to the sign of X. */ extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); +/* Convert between MPFR and REAL_VALUE_TYPE. The caller is + responsible for initializing and clearing the MPFR parameter. */ + +extern void real_from_mpfr (REAL_VALUE_TYPE *, mpfr_srcptr); +extern void mpfr_from_real (mpfr_ptr, const REAL_VALUE_TYPE *); + #endif /* ! GCC_REAL_H */ |