summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/builtins.c191
-rw-r--r--gcc/real.h3
-rw-r--r--gcc/toplev.c20
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 ? " " : "",