Patch for libgfortran; broken isnan/isfinite/fpclassify

Steve Ellcey sje@cup.hp.com
Fri Sep 23 21:11:00 GMT 2005


On HP-UX HPPA platforms the isnan/isfinite/fpclassify macros exist but
only work on float and double types.  They do not work on long double
types even though the HP-UX HPPA platform has a long double type.

This patch adds macros to test for a functional
isnan/isfinite/fpclassify macros and only allows there use if they look
OK.  If isnan/isfinite are broken but fpclassify looks OK there are
defines to implement isnan and isfinite in terms of fpclassify.  If
fpclassify doesn't look good either then it implements 'cheap'
isnan/isfinite macros that are based on comparisions that should work
OK on all platforms.

I also changed io/write.c to remove a TODO comment related to these
macros and intrinsics/c99_functions.c to remove an ifdef that we don't
need if we always define isfinite().

I tested this on HPPA HP-UX platforms and IA64 HP-UX and Linux platforms
with no regressions.  On HPPA, the BROKEN ifdefs are set and the
gfortran.dg/large_real_kind_1.f90 tests that were failing now pass.  On
IA64 HP-UX and Linux I made sure that the BROKEN ifdefs were not set.  I
don't have a cygwin setup but if someone does and if the BROKEN macros
work properly (they might need to be extended) then the __CYGWIN__ check
should be able to be removed.

OK to check in on the main line?

Steve Ellcey
sje@cup.hp.com

libgfortran/ChangeLog:

2005-09-23  Steve Ellcey  <sje@cup.hp.com>

	* acinclude.m4 (LIBGFOR_CHECK_FOR_BROKEN_ISFINITE): New.
	(LIBGFOR_CHECK_FOR_BROKEN_ISNAN): New.
	(LIBGFOR_CHECK_FOR_BROKEN_FPCLASSIFY): New.
	* configure.ac (LIBGFOR_CHECK_FOR_BROKEN_ISFINITE): Add use.
	(LIBGFOR_CHECK_FOR_BROKEN_ISNAN): Add use.
	(LIBGFOR_CHECK_FOR_BROKEN_FPCLASSIFY): Add use.
	* libgfortan.h (isfinite): undef if broken, set if needed.
	(isnan): undef if broken, set if needed.
        (fpclassify): undef if broken, set if needed.
	* io/write.c: Remove TODO comment about working isfinite.
	* intrinsics/c99_functions.c (round): Use isfinite instead
	of fpclassify.
	* intrinsics/c99_functions.c (roundf): Ditto.

*** gcc.orig/libgfortran/acinclude.m4	Fri Sep 23 13:40:12 2005
--- gcc/libgfortran/acinclude.m4	Fri Sep 23 13:39:24 2005
*************** esac])])
*** 230,232 ****
--- 230,339 ----
  if test x"$have_crlf" = xyes; then
    AC_DEFINE(HAVE_CRLF, 1, [Define if CRLF is line terminator.])
  fi])
+ 
+ dnl Check whether isfinite works.
+ dnl The most common problem is that it does not work on long doubles.
+ AC_DEFUN([LIBGFOR_CHECK_FOR_BROKEN_ISFINITE], [
+   AC_CACHE_CHECK([whether isfinite works],
+                   have_broken_isfinite, [
+   libgfor_check_for_broken_isfinite_save_LIBS=$LIBS
+   LIBS="$LIBS -lm"
+   AC_TRY_RUN([
+ #ifdef HAVE_MATH_H
+ #include <math.h>
+ #endif
+ #include <float.h>
+ int main ()
+ {
+ #ifdef isfinite
+ #ifdef LDBL_MAX
+   if (!isfinite(LDBL_MAX)) return 1;
+ #endif
+ #ifdef DBL_MAX
+   if (!isfinite(DBL_MAX)) return 1;
+ #endif
+ #endif
+ return 0;
+ }], have_broken_isfinite=no, have_broken_isfinite=yes)]
+   LIBS=$libgfor_check_for_broken_isfinite_save_LIBS)
+ if test x"$have_broken_isfinite" = xyes; then
+   AC_DEFINE(HAVE_BROKEN_ISFINITE, 1, [Define if isfinite is broken.])
+ fi])
+ 
+ dnl Check whether isnan works.
+ dnl The most common problem is that it does not work on long doubles.
+ AC_DEFUN([LIBGFOR_CHECK_FOR_BROKEN_ISNAN], [
+   AC_CACHE_CHECK([whether isnan works],
+                   have_broken_isnan, [
+   libgfor_check_for_broken_isnan_save_LIBS=$LIBS
+   LIBS="$LIBS -lm"
+   AC_TRY_RUN([
+ #ifdef HAVE_MATH_H
+ #include <math.h>
+ #endif
+ #include <float.h>
+ int main ()
+ {
+ #ifdef isnan
+ #ifdef LDBL_MAX
+   {
+     long double x;
+     x = 0/0;
+     if (!isnan(x) return 1;
+     if (isnan(LDBL_MAX)) return 1;
+ #ifdef NAN
+     x = (long double) NAN;
+     if (!isnan(x) return 1;
+ #endif
+   }
+ #endif
+ #ifdef DBL_MAX
+   {
+     double y;
+     y = 0/0;
+     if (!isnan(y) return 1;
+     if (isnan(DBL_MAX)) return 1;
+ #ifdef NAN
+     x = (double) NAN;
+     if (!isnan(x) return 1;
+ #endif
+   }
+ #endif
+ #endif
+ return 0;
+ }], have_broken_isnan=no, have_broken_isnan=yes)]
+   LIBS=$libgfor_check_for_broken_isnan_save_LIBS)
+ if test x"$have_broken_isnan" = xyes; then
+   AC_DEFINE(HAVE_BROKEN_ISNAN, 1, [Define if isnan is broken.])
+ fi])
+ 
+ dnl Check whether fpclassify works correctly.
+ dnl The most common problem is that it does not work on long doubles.
+ AC_DEFUN([LIBGFOR_CHECK_FOR_BROKEN_FPCLASSIFY], [
+   AC_CACHE_CHECK([whether fpclassify works],
+                   have_broken_fpclassify, [
+   libgfor_check_for_broken_fpclassify_save_LIBS=$LIBS
+   LIBS="$LIBS -lm"
+   AC_TRY_RUN([
+ #ifdef HAVE_MATH_H
+ #include <math.h>
+ #endif
+ #include <float.h>
+ int main ()
+ {
+ #ifdef fpclassify
+ #ifdef LDBL_MAX
+         if (fpclassify(LDBL_MAX) == FP_NAN
+             || fpclassify(LDBL_MAX) == FP_INFINITE) return 1;
+ #endif
+ #ifdef DBL_MAX
+         if (fpclassify(DBL_MAX) == FP_NAN
+             || fpclassify(DBL_MAX) == FP_INFINITE) return 1;
+ #endif
+ #endif
+ return 0;
+ }], have_broken_fpclassify=no, have_broken_fpclassify=yes)]
+   LIBS=$libgfor_check_for_broken_fpclassify_save_LIBS)
+ if test x"$have_broken_fpclassify" = xyes; then
+   AC_DEFINE(HAVE_BROKEN_FPCLASSIFY, 1, [Define if fpclassify is broken.])
+ fi])
*** gcc.orig/libgfortran/configure.ac	Fri Sep 23 13:40:12 2005
--- gcc/libgfortran/configure.ac	Fri Sep 23 13:39:24 2005
*************** AC_CHECK_LIB([m],[y1f],[AC_DEFINE([HAVE_
*** 230,235 ****
--- 230,244 ----
  AC_CHECK_LIB([m],[yn],[AC_DEFINE([HAVE_YN],[1],[libm includes yn])])
  AC_CHECK_LIB([m],[ynf],[AC_DEFINE([HAVE_YNF],[1],[libm includes ynf])])
  
+ # Check for a isfinite macro that works on long doubles.
+ LIBGFOR_CHECK_FOR_BROKEN_ISFINITE
+ 
+ # Check for a isnan macro that works on long doubles.
+ LIBGFOR_CHECK_FOR_BROKEN_ISNAN
+ 
+ # Check for a fpclassify macro that works on long doubles.
+ LIBGFOR_CHECK_FOR_BROKEN_FPCLASSIFY
+ 
  # Fallback in case isfinite is not available.
  AC_CHECK_LIB([m],[finite],[AC_DEFINE([HAVE_FINITE],[1],[libm includes finite])])
  
*** gcc.orig/libgfortran/libgfortran.h	Fri Sep 23 13:40:12 2005
--- gcc/libgfortran/libgfortran.h	Fri Sep 23 13:39:25 2005
*************** typedef off_t gfc_offset;
*** 177,189 ****
  
     When isfinite is not available, try to use one of the
     alternatives, or bail out.  */
! #if (!defined(isfinite) || defined(__CYGWIN__))
  #undef isfinite
! #if defined(fpclassify)
  #define isfinite(x) (fpclassify(x) != FP_NAN && fpclassify(x) != FP_INFINITE)
  #else
! #define isfinite(x) ((x) - (x) == 0)
! #endif
  #endif /* !defined(isfinite)  */
  
  /* TODO: find the C99 version of these an move into above ifdef.  */
--- 177,209 ----
  
     When isfinite is not available, try to use one of the
     alternatives, or bail out.  */
! 
! #if (defined(isfinite) && (defined(HAVE_BROKEN_ISFINITE) || defined(__CYGWIN__)))
  #undef isfinite
! #endif
! 
! #if (defined(isnan) && defined(HAVE_BROKEN_ISNAN))
! #undef isnan
! #endif
! 
! #if (defined(fpclassify) && defined(HAVE_BROKEN_FPCLASSIFY))
! #undef fpclassify
! #endif
! 
! #if !defined(isfinite)
! #if !defined(fpclassify)
! #define isfinite(x) ((x) - (x) == 0)
! #else
  #define isfinite(x) (fpclassify(x) != FP_NAN && fpclassify(x) != FP_INFINITE)
+ #endif /* !defined(fpclassify) */
+ #endif /* !defined(isfinite)  */
+ 
+ #if !defined(isnan)
+ #if !defined(fpclassify)
+ #define isnan(x) ((x) != (x))
  #else
! #define isnan(x) (fpclassify(x) == FP_NAN)
! #endif /* !defined(fpclassify) */
  #endif /* !defined(isfinite)  */
  
  /* TODO: find the C99 version of these an move into above ifdef.  */
*** gcc.orig/libgfortran/io/write.c	Fri Sep 23 13:40:24 2005
--- gcc/libgfortran/io/write.c	Fri Sep 23 13:39:35 2005
*************** write_float (fnode *f, const char *sourc
*** 821,829 ****
  
    if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
      {
-       /* TODO: there are some systems where isfinite is not able to work
-                with long double variables. We should detect this case and
- 	       provide our own version for isfinite.  */
        res = isfinite (n); 
        if (res == 0)
  	{
--- 821,826 ----
*** gcc.orig/libgfortran/intrinsics/c99_functions.c	Fri Sep 23 13:40:32 2005
--- gcc/libgfortran/intrinsics/c99_functions.c	Fri Sep 23 13:39:49 2005
*************** double
*** 315,326 ****
  round(double x)
  {
     double t;
! #if defined(fpclassify)
!    int i;
!    i = fpclassify(x);
!    if (i == FP_INFINITE || i == FP_NAN)
       return (x);
- #endif
  
     if (x >= 0.0) 
      {
--- 315,322 ----
  round(double x)
  {
     double t;
!    if (!isfinite (x))
       return (x);
  
     if (x >= 0.0) 
      {
*************** float
*** 347,359 ****
  roundf(float x)
  {
     float t;
! #if defined(fpclassify)
!    int i;
! 
!    i = fpclassify(x);
!    if (i == FP_INFINITE || i == FP_NAN)
       return (x);
- #endif
  
     if (x >= 0.0) 
      {
--- 343,350 ----
  roundf(float x)
  {
     float t;
!    if (!isfinite (x))
       return (x);
  
     if (x >= 0.0) 
      {



More information about the Gcc-patches mailing list