[PATCH] Enforce GMP/MPFR version requires and fix fortran/28276,27021

Steve Kargl sgk@troutmask.apl.washington.edu
Tue Sep 12 21:20:00 GMT 2006


The attached patch has been tested on amd64-*-freebsd, and it
should only impact gfortran.  However, the patch does touch
the toplevel configure.in, and hence, configure.

markm, I cc'd you because of the pending branching of 4.2 and
the fact I touch configure.in.  If you prefer that I hold the
patch until after the branching, I can do so.

The patch causes configure to check that the version of 
GMP is 4.1 or newer and that MPFR is version 2.2.0 or
newer.  For older versions of GMP, configure will die.
For older versions of MPFR, configure simply checks that
any version of MPFR is available.  If no version of
MPFR is available, configure will die.  If an older version
of MPFR is found, it will be used; however, several known
problems with older MPFRs prevent the bug fixes for PR
fortran/28276 and fortran/27021 from functioning (ie.,
the old buggy gfortran code is still used).

This patch also removes the local hacks for handling subnormal
numbers and the folding of atan2().  Again, if an older version
of MPFR is found, the old buggy gfortran code is used.

2006-09-12  Steven G. Kargl  <kargl@gcc.gnu.org>

	* configure.in: Check for GMP 4.1 or newer.  Check for MPFR 2.2.0 
	or newer.
	* configure: Regenerated.
	* doc/install.texi: Document required versions of GMP and MPFR.
	* fortran/arith.c (arctangent2): Conditionally include code.
	(gfc_check_real_range): Use mpfr_subnormalize in preference to local
	hack.
	* fortran/simplify.c: Wrap Copyright to new line.
	(gfc_simplify_atan2): Use mpfr_atan2 in preference to arctangent2().
        (gfc_simplify_log): Ditto.


	PR fortran/28276
	* fortran/simplify.c (gfc_simplify_exponent): Use mpfr_get_exp in
	preference to broken local hack.
	* fortran/trans-intrinsic.c (gfc_get_intrinsic_lib_fndecl): Append
	l for long double functions.

	PR fortran/27021
	* fortran/simplify.c (gfc_simplify_nearest): Use mpfr_nexttoward and
	mpfr_subnormalize to handle numbers near zero in preference to broken
	 local hack.

	PR fortran/28276
	* testsuite/gfortran.dg/exponent_1.f90: New test.

	PR fortran/27021
	* testsuite/gfortran.dg/nearest_1.f90: New test.

-- 
Steve
-------------- next part --------------
Index: gcc/doc/install.texi
===================================================================
--- gcc/doc/install.texi	(revision 116905)
+++ gcc/doc/install.texi	(working copy)
@@ -290,17 +290,20 @@ Necessary (only on some platforms) to un
 systems' @command{tar} programs will also work, only try GNU
 @command{tar} if you have problems.
 
-@item GNU Multiple Precision Library (GMP) version 4.0 (or later)
+@item GNU Multiple Precision Library (GMP) version 4.1 (or later)
 
-Necessary to build the Fortran frontend.  If you don't have it
+Necessary to build the Fortran frontend.  If you do not have it
 installed in your library search path, you will have to configure with
 the @option{--with-gmp} or @option{--with-gmp-dir} configure option.
 
-@item MPFR Library
+@item MPFR Library version 2.2 (or later)
 
 Necessary to build the Fortran frontend.  It can be downloaded from
-@uref{http://www.mpfr.org/}.  It is also included in the current GMP
-release (4.1.3) when configured with @option{--enable-mpfr}.
+@uref{http://www.mpfr.org/}.  The version of MPFR that is bundled with
+GMP 4.1.x contains numerous bugs.  Although gfortran will appear
+to function with the buggy verions of MPFR, there are few gfortran bugs
+that will not be fixed to use this version.  It is strongly
+recommended to upgrade to at least MPFR version 2.2.
 
 The @option{--with-mpfr} or @option{--with-mpfr-dir} configure option should
 be used if your MPFR Library is not installed in your library search path.
Index: gcc/fortran/arith.c
===================================================================
--- gcc/fortran/arith.c	(revision 116905)
+++ gcc/fortran/arith.c	(working copy)
@@ -75,6 +75,7 @@ gfc_set_model (mpfr_t x)
   mpfr_set_default_prec (mpfr_get_prec (x));
 }
 
+#if !defined(MPFR_VERSION_MAJOR)
 /* Calculate atan2 (y, x)
 
 atan2(y, x) = atan(y/x)				if x > 0,
@@ -124,7 +125,7 @@ arctangent2 (mpfr_t y, mpfr_t x, mpfr_t 
 
   mpfr_clear (t);
 }
-
+#endif
 
 /* Given an arithmetic error code, return a pointer to a string that
    explains the error.  */
@@ -407,6 +408,7 @@ gfc_check_real_range (mpfr_t p, int kind
     }
   else if (mpfr_cmp (q, gfc_real_kinds[i].tiny) < 0)
     {
+#if !defined(MPFR_VERSION_MAJOR)
       /* MPFR operates on a number with a given precision and enormous
 	exponential range.  To represent subnormal numbers, the exponent is
 	allowed to become smaller than emin, but always retains the full
@@ -428,13 +430,30 @@ gfc_check_real_range (mpfr_t p, int kind
       sprintf (s, "0.%sE%d", bin, (int) e);
       mpfr_set_str (q, s, gfc_real_kinds[i].radix, GMP_RNDN);
 
+      gfc_free (s);
+      gfc_free (bin);
+#else
+      mp_exp_t emin, emax;
+
+      /* Save current values of emin and emax.  */
+      emin = mpfr_get_emin ();
+      emax = mpfr_get_emax ();
+
+      /* Set emin and emax for the current model number.  */
+      mpfr_set_emin ((mp_exp_t) gfc_real_kinds[i].min_exponent - 1);
+      mpfr_set_emax ((mp_exp_t) gfc_real_kinds[i].max_exponent - 1);
+      mpfr_subnormalize (q, 0, GFC_RND_MODE);
+
+      /* Reset emin and emax.  */
+      mpfr_set_emin (emin);
+      mpfr_set_emax (emax);
+#endif
+
+      /* Copy sign if needed.  */
       if (mpfr_sgn (p) < 0)
 	mpfr_neg (p, q, GMP_RNDN);
       else
 	mpfr_set (p, q, GMP_RNDN);
-
-      gfc_free (s);
-      gfc_free (bin);
 
       retval = ARITH_OK;
     }
Index: gcc/fortran/trans-intrinsic.c
===================================================================
--- gcc/fortran/trans-intrinsic.c	(revision 116905)
+++ gcc/fortran/trans-intrinsic.c	(working copy)
@@ -590,12 +590,18 @@ gfc_get_intrinsic_lib_fndecl (gfc_intrin
 
   if (m->libm_name)
     {
-      gcc_assert (ts->kind == 4 || ts->kind == 8 || ts->kind == 10
-                 || ts->kind == 16);
-      snprintf (name, sizeof (name), "%s%s%s",
-		ts->type == BT_COMPLEX ? "c" : "",
-		m->name,
-		ts->kind == 4 ? "f" : "");
+      if (ts->kind == 4)
+	snprintf (name, sizeof (name), "%s%s%s",
+		ts->type == BT_COMPLEX ? "c" : "", m->name, "f");
+      else if (ts->kind == 8)
+	snprintf (name, sizeof (name), "%s%s",
+		ts->type == BT_COMPLEX ? "c" : "", m->name);
+      else
+	{
+	  gcc_assert (ts->kind == 10 || ts->kind == 16);
+	  snprintf (name, sizeof (name), "%s%s%s",
+		ts->type == BT_COMPLEX ? "c" : "", m->name, "l");
+	}
     }
   else
     {
Index: gcc/fortran/simplify.c
===================================================================
--- gcc/fortran/simplify.c	(revision 116905)
+++ gcc/fortran/simplify.c	(working copy)
@@ -1,6 +1,6 @@
 /* Simplify intrinsic functions at compile-time.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
-   Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
    Contributed by Andy Vaught & Katherine Holcomb
 
 This file is part of GCC.
@@ -607,7 +607,11 @@ gfc_simplify_atan2 (gfc_expr * y, gfc_ex
       return &gfc_bad_expr;
     }
 
+#if !defined(MPFR_VERSION_MAJOR)
   arctangent2 (y->value.real, x->value.real, result->value.real);
+#else
+  mpfr_atan2 (result->value.real, y->value.real, x->value.real, GFC_RND_MODE);
+#endif
 
   return range_check (result, "ATAN2");
 }
@@ -1054,9 +1058,12 @@ gfc_expr *
 gfc_simplify_exponent (gfc_expr * x)
 {
   int i;
-  mpfr_t tmp;
   gfc_expr *result;
 
+#if !defined(MPFR_VERSION_MAJOR)
+  mpfr_t tmp;
+#endif
+
   if (x->expr_type != EXPR_CONSTANT)
     return NULL;
 
@@ -1071,6 +1078,9 @@ gfc_simplify_exponent (gfc_expr * x)
       return result;
     }
 
+#if !defined(MPFR_VERSION_MAJOR)
+  /* PR fortran/28276 suffers from a buggy MPFR, and this block of code
+     does not function correctly.  */
   mpfr_init (tmp);
 
   mpfr_abs (tmp, x->value.real, GFC_RND_MODE);
@@ -1085,6 +1095,11 @@ gfc_simplify_exponent (gfc_expr * x)
     mpz_add_ui (result->value.integer,result->value.integer, 1);
 
   mpfr_clear (tmp);
+#else
+  /* Requires MPFR 2.2.0 or newer.  */
+  i = (int) mpfr_get_exp (x->value.real);
+  mpz_set_si (result->value.integer, i);
+#endif
 
   return range_check (result, "EXPONENT");
 }
@@ -2146,8 +2161,13 @@ gfc_simplify_log (gfc_expr * x)
       mpfr_init (xr);
       mpfr_init (xi);
 
-      arctangent2 (x->value.complex.i, x->value.complex.r,
-	           result->value.complex.i);
+#if !defined(MPFR_VERSION_MAJOR)
+      arctangent2 (x->value.complex.i, x->value.complex.r, result->value.complex.i);
+#else
+      mpfr_atan2 (result->value.complex.i, x->value.complex.i, x->value.complex.r,
+		  GFC_RND_MODE);
+#endif
+
 
       mpfr_mul (xr, x->value.complex.r, x->value.complex.r, GFC_RND_MODE);
       mpfr_mul (xi, x->value.complex.i, x->value.complex.i, GFC_RND_MODE);
@@ -2474,27 +2494,28 @@ gfc_simplify_nearest (gfc_expr * x, gfc_
 {
   gfc_expr *result;
   mpfr_t tmp;
-  int direction, sgn;
+  int sgn;
+#if !defined(MPFR_VERSION_MAJOR)
+  int direction;
+#else
+  mp_exp_t emin, emax;
+#endif
 
   if (x->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT)
     return NULL;
 
-  gfc_set_model_kind (x->ts.kind);
-  result = gfc_copy_expr (x);
-
-  direction = mpfr_sgn (s->value.real);
-
-  if (direction == 0)
+  if (mpfr_sgn (s->value.real) == 0)
     {
-      gfc_error ("Second argument of NEAREST at %L may not be zero",
-		 &s->where);
-      gfc_free (result);
+      gfc_error ("Second argument of NEAREST at %L shall not be zero", &s->where);
       return &gfc_bad_expr;
     }
 
-  /* TODO: Use mpfr_nextabove and mpfr_nextbelow once we move to a
-     newer version of mpfr.  */
+  gfc_set_model_kind (x->ts.kind);
+  result = gfc_copy_expr (x);
+
+#if !defined(MPFR_VERSION_MAJOR)
 
+  direction = mpfr_sgn (s->value.real);
   sgn = mpfr_sgn (x->value.real);
 
   if (sgn == 0)
@@ -2539,6 +2560,28 @@ gfc_simplify_nearest (gfc_expr * x, gfc_
       if (sgn < 0)
 	mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE);
     }
+#else
+
+  /* Save current values of emin and emax.  */
+  emin = mpfr_get_emin ();
+  emax = mpfr_get_emax ();
+
+  /* Set emin and emax for the current model number.  */
+  sgn = gfc_validate_kind (BT_REAL, x->ts.kind, 0);
+  mpfr_set_emin ((mp_exp_t) gfc_real_kinds[sgn].min_exponent - 1);
+  mpfr_set_emax ((mp_exp_t) gfc_real_kinds[sgn].max_exponent - 1);
+
+  sgn = mpfr_sgn (s->value.real); 
+  mpfr_init (tmp);
+  mpfr_set_inf (tmp, sgn);
+  mpfr_nexttoward (result->value.real, tmp);
+  mpfr_subnormalize (result->value.real, 0, GFC_RND_MODE);
+ 
+  mpfr_set_emin (emin);
+  mpfr_set_emax (emax);
+ 
+  mpfr_clear(tmp);
+#endif
 
   return range_check (result, "NEAREST");
 }
Index: configure.in
===================================================================
--- configure.in	(revision 116905)
+++ configure.in	(working copy)
@@ -1103,17 +1103,23 @@ CFLAGS="$CFLAGS $gmpinc"
 # Check GMP actually works
 AC_MSG_CHECKING([for correct version of gmp.h])
 AC_TRY_COMPILE([#include "gmp.h"],[
-#if __GNU_MP_VERSION < 3
+#if __GNU_MP_VERSION < 4 || (__GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR < 1)
 choke me
 #endif
-], [AC_MSG_RESULT([yes])],
-  [AC_MSG_RESULT([no]); have_gmp=no])
+], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]); have_gmp=no])
 
 if test x"$have_gmp" = xyes; then
-  AC_MSG_CHECKING([for MPFR])
+  AC_MSG_CHECKING([for correct version of mpfr.h])
+  AC_TRY_COMPILE([#include "gmp.h"
+#include <mpfr.h>],[
+#if MPFR_VERSION_MAJOR < 2 || (MPFR_VERSION_MAJOR == 2 && MPFR_VERSION_MINOR < 2)
+  choke me
+#endif
+], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([buggy version of MPFR detected])])
 
   saved_LIBS="$LIBS"
   LIBS="$LIBS $gmplibs"
+  AC_MSG_CHECKING([for any version of mpfr.h])
   AC_TRY_LINK([#include <gmp.h>
 #include <mpfr.h>], [mpfr_t n; mpfr_init(n);],
     [AC_MSG_RESULT([yes])],  [AC_MSG_RESULT([no]); have_gmp=no])
@@ -1258,7 +1264,7 @@ if test -d ${srcdir}/gcc; then
         case ,${enable_languages},:${have_gmp}:${need_gmp} in
           *,${language},*:no:yes)
             # Specifically requested language; tell them.
-            AC_MSG_ERROR([GMP with MPFR support is required to build $language])
+            AC_MSG_ERROR([GMP 4.1 and MPFR 2.2 or newer versions required by $language])
             ;;
           *:no:yes)
             # Silently disable.


More information about the Fortran mailing list