diff options
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/builtins.c | 191 | ||||
-rw-r--r-- | gcc/real.h | 3 | ||||
-rw-r--r-- | gcc/toplev.c | 20 |
4 files changed, 211 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b347aff1db8..2b944bc0cf8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2009-05-15 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * builtins.c (do_mpc_arg1, fold_builtin_ccos): New. + (fold_builtin_cexp): Ensure we get a complex REAL_TYPE. + Evaluate constant arguments. + (fold_builtin_carg): Ensure we get a complex REAL_TYPE. + (fold_builtin_1): Likewise, also evaluate constant arguments. + Remove superfluous break. + (do_mpc_ckconv): New. + * real.h: Include mpc.h. + * toplev.c (print_version): Output MPC version info if available. + 2009-05-15 Sandra Loosemore <sandra@codesourcery.com> * fold-const.c (fold_convert_const_real_from_real): Check for diff --git a/gcc/builtins.c b/gcc/builtins.c index e12418983bf..b704394f31e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -58,6 +58,9 @@ along with GCC; see the file COPYING3. If not see #ifndef PAD_VARARGS_DOWN #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN #endif +#ifdef HAVE_mpc +static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t)); +#endif /* Define the names of the builtin function types and codes. */ const char *const built_in_class_names[4] @@ -7886,6 +7889,33 @@ fold_builtin_cosh (tree arg, tree type, tree fndecl) return NULL_TREE; } +/* Fold function call to builtin ccos (or ccosh if HYPER is TRUE) with + argument ARG. TYPE is the type of the return value. Return + NULL_TREE if no simplification can be made. */ + +static tree +fold_builtin_ccos (tree arg, tree type ATTRIBUTE_UNUSED, tree fndecl, + bool hyper ATTRIBUTE_UNUSED) +{ + if (validate_arg (arg, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE) + { + tree tmp; + +#ifdef HAVE_mpc + /* Calculate the result when the argument is a constant. */ + if ((tmp = do_mpc_arg1 (arg, type, (hyper ? mpc_cosh : mpc_cos)))) + return tmp; +#endif + + /* Optimize fn(-x) into fn(x). */ + if ((tmp = fold_strip_sign_ops (arg))) + return build_call_expr (fndecl, 1, tmp); + } + + return NULL_TREE; +} + /* Fold function call to builtin tan, tanf, or tanl with argument ARG. Return NULL_TREE if no simplification can be made. */ @@ -7960,10 +7990,20 @@ fold_builtin_cexp (tree arg0, tree type) { tree rtype; tree realp, imagp, ifn; +#ifdef HAVE_mpc + tree res; +#endif - if (!validate_arg (arg0, COMPLEX_TYPE)) + if (!validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) return NULL_TREE; +#ifdef HAVE_mpc + /* Calculate the result when the argument is a constant. */ + if ((res = do_mpc_arg1 (arg0, type, mpc_exp))) + return res; +#endif + rtype = TREE_TYPE (TREE_TYPE (arg0)); /* In case we can figure out the real part of arg0 and it is constant zero @@ -9670,7 +9710,8 @@ fold_builtin_fmin_fmax (tree arg0, tree arg1, tree type, bool max) static tree fold_builtin_carg (tree arg, tree type) { - if (validate_arg (arg, COMPLEX_TYPE)) + if (validate_arg (arg, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE) { tree atan2_fn = mathfn_built_in (type, BUILT_IN_ATAN2); @@ -10215,12 +10256,14 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore) return fold_builtin_abs (arg0, type); CASE_FLT_FN (BUILT_IN_CONJ): - if (validate_arg (arg0, COMPLEX_TYPE)) + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) return fold_build1 (CONJ_EXPR, type, arg0); break; CASE_FLT_FN (BUILT_IN_CREAL): - if (validate_arg (arg0, COMPLEX_TYPE)) + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) return non_lvalue (fold_build1 (REALPART_EXPR, type, arg0));; break; @@ -10230,16 +10273,49 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore) break; CASE_FLT_FN (BUILT_IN_CCOS): + return fold_builtin_ccos(arg0, type, fndecl, /*hyper=*/ false); + CASE_FLT_FN (BUILT_IN_CCOSH): - /* These functions are "even", i.e. f(x) == f(-x). */ - if (validate_arg (arg0, COMPLEX_TYPE)) - { - tree narg = fold_strip_sign_ops (arg0); - if (narg) - return build_call_expr (fndecl, 1, narg); - } + return fold_builtin_ccos(arg0, type, fndecl, /*hyper=*/ true); + +#ifdef HAVE_mpc + CASE_FLT_FN (BUILT_IN_CSIN): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_sin); break; - + + CASE_FLT_FN (BUILT_IN_CSINH): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_sinh); + break; + + CASE_FLT_FN (BUILT_IN_CTAN): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_tan); + break; + + CASE_FLT_FN (BUILT_IN_CTANH): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_tanh); + break; + + CASE_FLT_FN (BUILT_IN_CLOG): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_log); + break; + + CASE_FLT_FN (BUILT_IN_CSQRT): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_sqrt); + break; +#endif + CASE_FLT_FN (BUILT_IN_CABS): return fold_builtin_cabs (arg0, type, fndecl); @@ -10293,7 +10369,6 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore) CASE_FLT_FN (BUILT_IN_COS): return fold_builtin_cos (arg0, type, fndecl); - break; CASE_FLT_FN (BUILT_IN_TAN): return fold_builtin_tan (arg0, type); @@ -13127,6 +13202,50 @@ do_mpfr_ckconv (mpfr_srcptr m, tree type, int inexact) return NULL_TREE; } +#ifdef HAVE_mpc +/* Helper function for do_mpc_arg*(). Ensure M is a normal complex + number and no overflow/underflow occurred. INEXACT is true if M + was not exactly calculated. TYPE is the tree type for the result. + This function assumes that you cleared the MPFR flags and then + calculated M to see if anything subsequently set a flag prior to + entering this function. Return NULL_TREE if any checks fail. */ + +static tree +do_mpc_ckconv (mpc_srcptr m, tree type, int inexact) +{ + /* Proceed iff we get a normal number, i.e. not NaN or Inf and no + overflow/underflow occurred. If -frounding-math, proceed iff the + result of calling FUNC was exact. */ + if (mpfr_number_p (MPC_RE (m)) && mpfr_number_p (MPC_IM (m)) + && !mpfr_overflow_p () && !mpfr_underflow_p () + && (!flag_rounding_math || !inexact)) + { + REAL_VALUE_TYPE re, im; + + real_from_mpfr (&re, MPC_RE (m), type, GMP_RNDN); + real_from_mpfr (&im, MPC_IM (m), type, GMP_RNDN); + /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values, + check for overflow/underflow. If the REAL_VALUE_TYPE is zero + but the mpft_t is not, then we underflowed in the + conversion. */ + if (real_isfinite (&re) && real_isfinite (&im) + && (re.cl == rvc_zero) == (mpfr_zero_p (MPC_RE (m)) != 0) + && (im.cl == rvc_zero) == (mpfr_zero_p (MPC_IM (m)) != 0)) + { + REAL_VALUE_TYPE re_mode, im_mode; + + real_convert (&re_mode, TYPE_MODE (TREE_TYPE (type)), &re); + real_convert (&im_mode, TYPE_MODE (TREE_TYPE (type)), &im); + /* Proceed iff the specified mode can hold the value. */ + if (real_identical (&re_mode, &re) && real_identical (&im_mode, &im)) + return build_complex (type, build_real (TREE_TYPE (type), re_mode), + build_real (TREE_TYPE (type), im_mode)); + } + } + return NULL_TREE; +} +#endif /* HAVE_mpc */ + /* 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. If MIN and/or MAX are not NULL, then the supplied ARG must be @@ -13523,6 +13642,52 @@ do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type) return result; } +#ifdef HAVE_mpc +/* If argument ARG is a COMPLEX_CST, call the one-argument mpc + 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_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t)) +{ + tree result = NULL_TREE; + + STRIP_NOPS (arg); + + /* To proceed, MPFR must exactly represent the target floating point + format, which only happens when the target base equals two. */ + if (TREE_CODE (arg) == COMPLEX_CST && !TREE_OVERFLOW (arg) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE + && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg))))->b == 2) + { + const REAL_VALUE_TYPE *const re = TREE_REAL_CST_PTR (TREE_REALPART (arg)); + const REAL_VALUE_TYPE *const im = TREE_REAL_CST_PTR (TREE_IMAGPART (arg)); + + if (real_isfinite (re) && real_isfinite (im)) + { + const struct real_format *const fmt = + REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type))); + const int prec = fmt->p; + const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN; + int inexact; + mpc_t m; + + mpc_init2 (m, prec); + mpfr_from_real (MPC_RE(m), re, rnd); + mpfr_from_real (MPC_IM(m), im, rnd); + mpfr_clear_flags (); + inexact = func (m, m, rnd); + result = do_mpc_ckconv (m, type, inexact); + mpc_clear (m); + } + } + + return result; +} +#endif /* HAVE_mpc */ + /* FIXME tuples. The functions below provide an alternate interface for folding builtin function calls presented as GIMPLE_CALL statements rather diff --git a/gcc/real.h b/gcc/real.h index 834a24b7185..0fc915cae5b 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -24,6 +24,9 @@ #ifndef GENERATOR_FILE #include <gmp.h> #include <mpfr.h> +#ifdef HAVE_mpc +#include <mpc.h> +#endif #endif #include "machmode.h" diff --git a/gcc/toplev.c b/gcc/toplev.c index 68dc6a3bcfa..346887b5153 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1170,8 +1170,13 @@ print_version (FILE *file, const char *indent) N_("%s%s%s %sversion %s (%s) compiled by CC, ") #endif ; +#ifdef HAVE_mpc static const char fmt2[] = - N_("GMP version %s, MPFR version %s.\n"); + N_("GMP version %s, MPFR version %s, MPC version %s\n"); +#else + static const char fmt2[] = + N_("GMP version %s, MPFR version %s\n"); +#endif static const char fmt3[] = N_("%s%swarning: %s header version %s differs from library version %s.\n"); static const char fmt4[] = @@ -1203,7 +1208,11 @@ print_version (FILE *file, const char *indent) #endif fprintf (file, file == stderr ? _(fmt2) : fmt2, - GCC_GMP_STRINGIFY_VERSION, MPFR_VERSION_STRING); + GCC_GMP_STRINGIFY_VERSION, MPFR_VERSION_STRING +#ifdef HAVE_mpc + , MPC_VERSION_STRING +#endif + ); if (strcmp (GCC_GMP_STRINGIFY_VERSION, gmp_version)) fprintf (file, file == stderr ? _(fmt3) : fmt3, @@ -1214,6 +1223,13 @@ print_version (FILE *file, const char *indent) file == stderr ? _(fmt3) : fmt3, indent, *indent != 0 ? " " : "", "MPFR", MPFR_VERSION_STRING, mpfr_get_version ()); +#ifdef HAVE_mpc + if (strcmp (MPC_VERSION_STRING, mpc_get_version ())) + fprintf (file, + file == stderr ? _(fmt3) : fmt3, + indent, *indent != 0 ? " " : "", + "MPC", MPC_VERSION_STRING, mpc_get_version ()); +#endif fprintf (file, file == stderr ? _(fmt4) : fmt4, indent, *indent != 0 ? " " : "", |