[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