This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: PR29335 evaluate transcendentals at compile-time using MPFR [take 2]


This patch is my second iteration of PR29335 to enable evaluating
transcendentals at compile-time using MPFR.  It incorporates feedback from
Joseph and Steve.  Notable changes are:

1.  MPFR precision for the trancedental calculation is set to the
precision of the tree type requested for the result.

2.  If -frounding-math, the result must have been exact within the
specified precision.

3.  Not really notable, but I shortened the buffers used for the
intermediate strings from 256 to 128 bytes.  Still should be more than
enough.


It seems like we've converged on requiring the user to obtain GMP/MPFR
themselves instead of building it in-tree.  So this patch depends on my
other patch to require GMP/MPFR for all frontends, posted here:
http://gcc.gnu.org/ml/gcc-patches/2006-10/msg00720.html

There are already checks in the testsuite to test simple args (mainly 0.0)
for sin, cos and tan in gcc.dg/torture/builtin-math-1.c. I've also
verified some non-zero values and the -frounding-math/exact stuff by hand.

I'll add a few more tests, including checks for -frounding-math,
exactness, etc.  Anyone want to recommend things to check?


Anyway, tested on sparc-sun-solaris2.10, no regressions.
Okay for stage1 mainline?

		Thanks,
		--Kaveh


2006-10-13  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	PR middle-end/29335
	* builtins.c (fold_builtin_sin, fold_builtin_cos,
	fold_builtin_tan): Fold all constant arguments.  Take a "type"
	argument as necessary.
	(do_mpfr_arg1): New.
	* real.c, real.h (real_from_mpfr, mpfr_from_real): New.

diff -rup orig/egcc-SVN20061011/gcc/builtins.c egcc-SVN20061011/gcc/builtins.c
--- orig/egcc-SVN20061011/gcc/builtins.c	2006-10-10 20:01:27.000000000 -0400
+++ egcc-SVN20061011/gcc/builtins.c	2006-10-13 16:45:20.898176180 -0400
@@ -149,9 +149,9 @@ static tree fold_builtin_sqrt (tree, tre
 static tree fold_builtin_cbrt (tree, tree);
 static tree fold_builtin_pow (tree, tree, tree);
 static tree fold_builtin_powi (tree, tree, tree);
-static tree fold_builtin_sin (tree);
+static tree fold_builtin_sin (tree, tree);
 static tree fold_builtin_cos (tree, tree, tree);
-static tree fold_builtin_tan (tree);
+static tree fold_builtin_tan (tree, tree);
 static tree fold_builtin_atan (tree, tree);
 static tree fold_builtin_trunc (tree, tree);
 static tree fold_builtin_floor (tree, tree);
@@ -204,6 +204,7 @@ static unsigned HOST_WIDE_INT target_s;
 static char target_percent_c[3];
 static char target_percent_s[3];
 static char target_percent_s_newline[4];
+static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t));

 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
@@ -7153,17 +7154,17 @@ fold_builtin_cbrt (tree arglist, tree ty
 /* Fold function call to builtin sin, sinf, or sinl.  Return
    NULL_TREE if no simplification can be made.  */
 static tree
-fold_builtin_sin (tree arglist)
+fold_builtin_sin (tree arglist, tree type)
 {
-  tree arg = TREE_VALUE (arglist);
+  tree arg = TREE_VALUE (arglist), res;

   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return NULL_TREE;

-  /* Optimize sin (0.0) = 0.0.  */
-  if (real_zerop (arg))
-    return arg;
-
+  /* Calculate the result when the argument is a constant.  */
+  if ((res = do_mpfr_arg1 (arg, type, mpfr_sin)))
+    return res;
+
   return NULL_TREE;
 }

@@ -7172,15 +7173,15 @@ fold_builtin_sin (tree arglist)
 static tree
 fold_builtin_cos (tree arglist, tree type, tree fndecl)
 {
-  tree arg = TREE_VALUE (arglist);
+  tree arg = TREE_VALUE (arglist), res;

   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return NULL_TREE;

-  /* Optimize cos (0.0) = 1.0.  */
-  if (real_zerop (arg))
-    return build_real (type, dconst1);
-
+  /* Calculate the result when the argument is a constant.  */
+  if ((res = do_mpfr_arg1 (arg, type, mpfr_cos)))
+    return res;
+
   /* Optimize cos(-x) into cos (x).  */
   if (TREE_CODE (arg) == NEGATE_EXPR)
     {
@@ -7195,18 +7196,18 @@ fold_builtin_cos (tree arglist, tree typ
 /* Fold function call to builtin tan, tanf, or tanl.  Return
    NULL_TREE if no simplification can be made.  */
 static tree
-fold_builtin_tan (tree arglist)
+fold_builtin_tan (tree arglist, tree type)
 {
   enum built_in_function fcode;
-  tree arg = TREE_VALUE (arglist);
+  tree arg = TREE_VALUE (arglist), res;

   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return NULL_TREE;

-  /* Optimize tan(0.0) = 0.0.  */
-  if (real_zerop (arg))
-    return arg;
-
+  /* Calculate the result when the argument is a constant.  */
+  if ((res = do_mpfr_arg1 (arg, type, mpfr_tan)))
+    return res;
+
   /* Optimize tan(atan(x)) = x.  */
   fcode = builtin_mathfn_code (arg);
   if (flag_unsafe_math_optimizations
@@ -8948,7 +8949,7 @@ fold_builtin_1 (tree fndecl, tree arglis
       return fold_builtin_cbrt (arglist, type);

     CASE_FLT_FN (BUILT_IN_SIN):
-      return fold_builtin_sin (arglist);
+      return fold_builtin_sin (arglist, type);

     CASE_FLT_FN (BUILT_IN_COS):
       return fold_builtin_cos (arglist, type, fndecl);
@@ -8973,7 +8974,7 @@ fold_builtin_1 (tree fndecl, tree arglis
       return fold_builtin_logarithm (fndecl, arglist, &dconst10);

     CASE_FLT_FN (BUILT_IN_TAN):
-      return fold_builtin_tan (arglist);
+      return fold_builtin_tan (arglist, type);

     CASE_FLT_FN (BUILT_IN_ATAN):
       return fold_builtin_atan (arglist, type);
@@ -11166,3 +11167,42 @@ init_target_chars (void)
     }
   return true;
 }
+
+/* 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.
+   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_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
+{
+  tree result = NULL_TREE;
+
+  STRIP_NOPS (arg);
+
+  if (TREE_CODE (arg) == REAL_CST)
+    {
+      const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+      REAL_VALUE_TYPE r = TREE_REAL_CST (arg);
+      mpfr_t m;
+      int exact;
+
+      mpfr_init2 (m, prec);
+      mpfr_from_real (m, &r);
+      exact = func (m, m, GMP_RNDN);
+
+      /* Proceed iff we don't get a NaN or Inf.  If -frounding-math is
+	 set, proceed iff the result of calling FUNC was exact,
+	 i.e. FUNC returned zero.  */
+      if (! mpfr_inf_p (m) && ! mpfr_nan_p (m)
+	  && (! flag_rounding_math || exact == 0))
+        {
+	  real_from_mpfr (&r, m);
+	  result = build_real (type, r);
+	}
+      mpfr_clear (m);
+    }
+
+  return result;
+}
diff -rup orig/egcc-SVN20061011/gcc/real.c egcc-SVN20061011/gcc/real.c
--- orig/egcc-SVN20061011/gcc/real.c	2006-03-16 20:01:37.000000000 -0500
+++ egcc-SVN20061011/gcc/real.c	2006-10-13 16:42:52.796759436 -0400
@@ -4922,3 +4922,45 @@ real_copysign (REAL_VALUE_TYPE *r, const
   r->sign = x->sign;
 }

+/* Convert from REAL_VALUE_TYPE to MPFR.  The caller is responsible
+   for initializing and clearing the MPFR parmeter.  */
+
+void
+mpfr_from_real (mpfr_ptr m, const REAL_VALUE_TYPE *r)
+{
+  /* We use a string as an intermediate type.  */
+  char buf[128];
+
+  real_to_decimal (buf, r, sizeof (buf), 0, 1);
+  gcc_assert (mpfr_set_str (m, buf, 10, GMP_RNDN) == 0);
+}
+
+/* Convert from MPFR to REAL_VALUE_TYPE.  */
+
+void
+real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m)
+{
+  /* We use a string as an intermediate type.  */
+  char buf[128], *rstr;
+  mp_exp_t exp;
+
+  rstr = mpfr_get_str (NULL, &exp, 16, 0, m, GMP_RNDN);
+
+  /* The additional 12 chars add space for the sprintf below.  This
+     leaves 6 digits for the exponent which is supposedly enough.  */
+  gcc_assert (rstr != NULL && strlen (rstr) < sizeof (buf) - 12);
+
+  /* REAL_VALUE_ATOF expects the exponent for mantissa * 2**exp,
+     mpfr_get_str returns the exponent for mantissa * 16**exp, adjust
+     for that.  */
+  exp *= 4;
+
+  if (rstr[0] == '-')
+    sprintf (buf, "-0x.%sp%d", &rstr[1], (int) exp);
+  else
+    sprintf (buf, "0x.%sp%d", rstr, (int) exp);
+
+  mpfr_free_str (rstr);
+
+  real_from_string (r, buf);
+}
diff -rup orig/egcc-SVN20061011/gcc/real.h egcc-SVN20061011/gcc/real.h
--- orig/egcc-SVN20061011/gcc/real.h	2006-01-23 00:24:02.000000000 -0500
+++ egcc-SVN20061011/gcc/real.h	2006-10-13 15:08:20.405074278 -0400
@@ -22,6 +22,8 @@
 #ifndef GCC_REAL_H
 #define GCC_REAL_H

+#include <gmp.h>
+#include <mpfr.h>
 #include "machmode.h"

 /* An expanded form of the represented number.  */
@@ -425,4 +427,10 @@ extern void real_round (REAL_VALUE_TYPE
 /* Set the sign of R to the sign of X.  */
 extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);

+/* Convert between MPFR and REAL_VALUE_TYPE.  The caller is
+   responsible for initializing and clearing the MPFR parameter.  */
+
+extern void real_from_mpfr (REAL_VALUE_TYPE *, mpfr_srcptr);
+extern void mpfr_from_real (mpfr_ptr, const REAL_VALUE_TYPE *);
+
 #endif /* ! GCC_REAL_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]