[PATCH take 2]: Integrate GCC with the complex math library MPC (middle-end)
Kaveh R. GHAZI
ghazi@caip.rutgers.edu
Fri May 15 16:01:00 GMT 2009
This patch is "take 2" of the middle-end bits for the MPC integration
originally posted and explained here:
http://gcc.gnu.org/ml/gcc-patches/2009-03/msg00672.html
The only change from the last patch iteration is a one-line bugfix for the
enumeration type of the "rnd" variable:
< + const mpc_rnd_t rnd = fmt->round_towards_zero ? (MPC_RNDZZ) : (MPC_RNDNN);
---
> + const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
I accidentally used an MPC enum where an MPFR one was actually needed.
Chalk one up for the new -Wc++-compat warnings!
Tested in conjunction with the MPC configury patch, no regressions.
Note: it's safe to install this patch separately from the other MPC bits.
Okay for mainline?
Thanks,
--Kaveh
2009-03-12 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.
diff -rup orig/egcc-SVN20090514/gcc/builtins.c egcc-SVN20090514/gcc/builtins.c
--- orig/egcc-SVN20090514/gcc/builtins.c 2009-05-06 02:01:25.000000000 +0200
+++ egcc-SVN20090514/gcc/builtins.c 2009-05-15 08:01:43.000000000 +0200
@@ -58,6 +58,9 @@ along with GCC; see the file COPYING3.
#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,
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
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,
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,
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,
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
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,
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 -rup orig/egcc-SVN20090514/gcc/real.h egcc-SVN20090514/gcc/real.h
--- orig/egcc-SVN20090514/gcc/real.h 2009-04-23 02:00:52.000000000 +0200
+++ egcc-SVN20090514/gcc/real.h 2009-05-15 07:47:52.000000000 +0200
@@ -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 -rup orig/egcc-SVN20090514/gcc/toplev.c egcc-SVN20090514/gcc/toplev.c
--- orig/egcc-SVN20090514/gcc/toplev.c 2009-05-09 06:30:24.000000000 +0200
+++ egcc-SVN20090514/gcc/toplev.c 2009-05-15 07:47:52.000000000 +0200
@@ -1170,8 +1170,13 @@ print_version (FILE *file, const char *i
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 *i
#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 *i
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 ? " " : "",
More information about the Gcc-patches
mailing list