[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