[PATCH take 2]: Integrate GCC with the complex math library MPC (middle-end)
Richard Guenther
richard.guenther@gmail.com
Fri May 15 16:21:00 GMT 2009
On Fri, May 15, 2009 at 6:01 PM, Kaveh R. GHAZI <ghazi@caip.rutgers.edu> wrote:
> 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?
What about testcases? (It will be of course interesting with
"optional" stuff ...)
Richard.
> 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