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]

[libgfortran] PR 16137: libgfortran on non-C99 targets


The following patch is my proposed solution to PR libgfortran/16137,
which is the inability to link libgfortran on targets without full
C99 support due to missing symbols.  The solution is to provide
replacement/stub implementations (much like libstdc++-v3 does);
checking for the required functions in configure and then providing
implementations in instrinsics/c99_functions.c when not available.

Most stub implementations are "obvious", but the one bit of cleverness
was the implementation of a portable nextafterf implementation thats
independent of the precise floating point format or its layout in
memory.  Hopefully, gfortran's use of nextafterf doesn't depend upon
its operation with denormalized numbers.  My attempts to support denorms
ran afoul of the target libm's inability to handle denormal arguments
to ldexp.  The implementation below always returns normalized values,
for example, returing FLT_MIN as the next value after zero.  I believe
this is conforming, or atleast good enough for fortran work.

The net result is that on sparc-sun-solaris2.8 there are 450 less
unexpected failures, and 978 more expected passes on the gfortran
testsuite.  On first inspection many of the remaining failures look
like LD_LIBRARY_PATH problems failing to find libgmp.so correctly.


There may be issues with people trying to link both C++ and Fortran95
code on Solaris due to duplicate symbols in their runtimes.  However,
I'd expect this to be rare, and no reason to prevent using Fortran on
its own.


The following patch has been tested on both i686-pc-linux-gnu and
sparc-sun-solaris2.8 with a full bootstrap, including gfortran, and
regression tested with a top-level "make -k check" with no new failures.

Ok for mainline?



2004-08-02  Roger Sayle  <roger@eyesopen.com>

	PR libgfortran/16137
	* configure.ac: Add tests for acosf, asinf, atan2f, atanf, ceilf,
	copysignf, cosf, coshf, expf, floorf, frexpf, hypotf, logf, log10f,
	scalbnf, sinf, sinhf, sqrtf, tanf and tanhf in libm.
	* config.h.in: Regenerate.
	* configure: Regenerate.

	* instrinsics/c99_functions.c (acosf, asinf, atan2f, atanf, ceilf,
	copysignf, cosf, coshf, expf, floorf, frexpf, hypotf, logf, log10f,
	nextafterf, scalbnf, sinf, sinhf, sqrtf, tanf, tanhf): New stub
	implementations for targets that don't support C99 float functions.


Index: configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/configure.ac,v
retrieving revision 1.6
diff -c -3 -p -r1.6 configure.ac
*** configure.ac	18 Jul 2004 12:46:39 -0000	1.6
--- configure.ac	2 Aug 2004 02:10:19 -0000
*************** AC_CHECK_LIB([m],[csin],[need_math="no"]
*** 160,171 ****
  # Check for library functions.
  AC_CHECK_FUNCS(getrusage times)

! # Check for some C99 functions
! AC_CHECK_LIB([m],[round],[AC_DEFINE([HAVE_ROUND],[1],["c99 function"])])
! AC_CHECK_LIB([m],[roundf],[AC_DEFINE([HAVE_ROUNDF],[1],["c99 function"])])
! # And other IEEE math functions
  AC_CHECK_LIB([m],[nextafter],[AC_DEFINE([HAVE_NEXTAFTER],[1],[libm includes nextafter])])
  AC_CHECK_LIB([m],[nextafterf],[AC_DEFINE([HAVE_NEXTAFTERF],[1],[libm includes nextafterf])])

  # Let the user override this
  AC_ARG_ENABLE(cmath,
--- 160,190 ----
  # Check for library functions.
  AC_CHECK_FUNCS(getrusage times)

! # Check for C99 (and other IEEE) math functions
! AC_CHECK_LIB([m],[acosf],[AC_DEFINE([HAVE_ACOSF],[1],[libm includes acosf])])
! AC_CHECK_LIB([m],[asinf],[AC_DEFINE([HAVE_ASINF],[1],[libm includes asinf])])
! AC_CHECK_LIB([m],[atan2f],[AC_DEFINE([HAVE_ATAN2F],[1],[libm includes atan2f])])
! AC_CHECK_LIB([m],[atanf],[AC_DEFINE([HAVE_ATANF],[1],[libm includes atanf])])
! AC_CHECK_LIB([m],[ceilf],[AC_DEFINE([HAVE_CEILF],[1],[libm includes ceilf])])
! AC_CHECK_LIB([m],[copysignf],[AC_DEFINE([HAVE_COPYSIGNF],[1],[libm includes copysignf])])
! AC_CHECK_LIB([m],[cosf],[AC_DEFINE([HAVE_COSF],[1],[libm includes cosf])])
! AC_CHECK_LIB([m],[coshf],[AC_DEFINE([HAVE_COSHF],[1],[libm includes coshf])])
! AC_CHECK_LIB([m],[expf],[AC_DEFINE([HAVE_EXPF],[1],[libm includes expf])])
! AC_CHECK_LIB([m],[floorf],[AC_DEFINE([HAVE_FLOORF],[1],[libm includes floorf])])
! AC_CHECK_LIB([m],[frexpf],[AC_DEFINE([HAVE_FREXPF],[1],[libm includes frexpf])])
! AC_CHECK_LIB([m],[hypotf],[AC_DEFINE([HAVE_HYPOTF],[1],[libm includes hypotf])])
! AC_CHECK_LIB([m],[logf],[AC_DEFINE([HAVE_LOGF],[1],[libm includes logf])])
! AC_CHECK_LIB([m],[log10f],[AC_DEFINE([HAVE_LOG10F],[1],[libm includes log10f])])
  AC_CHECK_LIB([m],[nextafter],[AC_DEFINE([HAVE_NEXTAFTER],[1],[libm includes nextafter])])
  AC_CHECK_LIB([m],[nextafterf],[AC_DEFINE([HAVE_NEXTAFTERF],[1],[libm includes nextafterf])])
+ AC_CHECK_LIB([m],[round],[AC_DEFINE([HAVE_ROUND],[1],[libm includes round])])
+ AC_CHECK_LIB([m],[roundf],[AC_DEFINE([HAVE_ROUNDF],[1],[libm includes roundf])])
+ AC_CHECK_LIB([m],[scalbnf],[AC_DEFINE([HAVE_SCALBNF],[1],[libm includes scalbnf])])
+ AC_CHECK_LIB([m],[sinf],[AC_DEFINE([HAVE_SINF],[1],[libm includes sinf])])
+ AC_CHECK_LIB([m],[sinhf],[AC_DEFINE([HAVE_SINHF],[1],[libm includes sinhf])])
+ AC_CHECK_LIB([m],[sqrtf],[AC_DEFINE([HAVE_SQRTF],[1],[libm includes sqrtf])])
+ AC_CHECK_LIB([m],[tanf],[AC_DEFINE([HAVE_TANF],[1],[libm includes tanf])])
+ AC_CHECK_LIB([m],[tanhf],[AC_DEFINE([HAVE_TANHF],[1],[libm includes tanhf])])

  # Let the user override this
  AC_ARG_ENABLE(cmath,
Index: intrinsics/c99_functions.c
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/intrinsics/c99_functions.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 c99_functions.c
*** intrinsics/c99_functions.c	14 Jun 2004 17:27:20 -0000	1.2
--- intrinsics/c99_functions.c	3 Aug 2004 01:44:47 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 20,29 ****
--- 20,251 ----

  #include "config.h"
  #include <sys/types.h>
+ #include <float.h>
  #include <math.h>
  #include "libgfortran.h"


+ #ifndef HAVE_ACOSF
+ float
+ acosf(float x)
+ {
+   return (float) acos(x);
+ }
+ #endif
+
+ #ifndef HAVE_ASINF
+ float
+ asinf(float x)
+ {
+   return (float) asin(x);
+ }
+ #endif
+
+ #ifndef HAVE_ATAN2F
+ float
+ atan2f(float x, float y)
+ {
+   return (float) atan2(x, y);
+ }
+ #endif
+
+ #ifndef HAVE_ATANF
+ float
+ atanf(float x)
+ {
+   return (float) atan(x);
+ }
+ #endif
+
+ #ifndef HAVE_CEILF
+ float
+ ceilf(float x)
+ {
+   return (float) ceil(x);
+ }
+ #endif
+
+ #ifndef HAVE_COPYSIGNF
+ float
+ copysignf(float x, float y)
+ {
+   return (float) copysignf(x, y);
+ }
+ #endif
+
+ #ifndef HAVE_COSF
+ float
+ cosf(float x)
+ {
+   return (float) cos(x);
+ }
+ #endif
+
+ #ifndef HAVE_COSHF
+ float
+ coshf(float x)
+ {
+   return (float) cosh(x);
+ }
+ #endif
+
+ #ifndef HAVE_EXPF
+ float
+ expf(float x)
+ {
+   return (float) exp(x);
+ }
+ #endif
+
+ #ifndef HAVE_FLOORF
+ float
+ floorf(float x)
+ {
+   return (float) floor(x);
+ }
+ #endif
+
+ #ifndef HAVE_FREXPF
+ float
+ frexpf(float x, int *exp)
+ {
+   return (float) frexp(x, exp);
+ }
+ #endif
+
+ #ifndef HAVE_HYPOTF
+ float
+ hypotf(float x, float y)
+ {
+   return (float) hypot(x, y);
+ }
+ #endif
+
+ #ifndef HAVE_LOGF
+ float
+ logf(float x)
+ {
+   return (float) log(x);
+ }
+ #endif
+
+ #ifndef HAVE_LOG10F
+ float
+ log10f(float x)
+ {
+   return (float) log10(x);
+ }
+ #endif
+
+ #ifndef HAVE_SCALBNF
+ float
+ scalbnf(float x, int y)
+ {
+   return (float) scalbn(x, y);
+ }
+ #endif
+
+ #ifndef HAVE_SINF
+ float
+ sinf(float x)
+ {
+   return (float) sin(x);
+ }
+ #endif
+
+ #ifndef HAVE_SINHF
+ float
+ sinhf(float x)
+ {
+   return (float) sinh(x);
+ }
+ #endif
+
+ #ifndef HAVE_SQRTF
+ float
+ sqrtf(float x)
+ {
+   return (float) sqrt(x);
+ }
+ #endif
+
+ #ifndef HAVE_TANF
+ float
+ tanf(float x)
+ {
+   return (float) tan(x);
+ }
+ #endif
+
+ #ifndef HAVE_TANHF
+ float
+ tanhf(float x)
+ {
+   return (float) tanh(x);
+ }
+ #endif
+
+ #ifndef HAVE_NEXTAFTERF
+ /* This is a portable implementation of nextafterf that is intended to be
+    independent of the floating point format or its in memory representation.
+    This implementation skips denormalized values, for example returning
+    FLT_MIN as the next value after zero, as many target's frexpf, scalbnf
+    and ldexpf functions don't work as expected with denormalized values.  */
+ float
+ nextafterf(float x, float y)
+ {
+   int origexp, newexp;
+
+   if (isnan(x) || isnan(y))
+     return x+y;
+   if (x == y)
+     return x;
+
+   if (x == 0.0f)
+     return y > 0.0f ? FLT_MIN : -FLT_MIN;
+
+   frexpf(x, &origexp);
+   if (x >= 0.0)
+     {
+       if (y > x)
+ 	{
+ 	  if (x < FLT_MIN)
+ 	    return FLT_MIN;
+ 	  return x + scalbnf(FLT_EPSILON, origexp-1);
+ 	}
+       else if (x > FLT_MIN)
+ 	{
+ 	  float temp = x - scalbnf(FLT_EPSILON, origexp-1);
+ 	  frexpf(temp, &newexp);
+ 	  if (newexp == origexp)
+ 	    return temp;
+ 	  return x - scalbnf(FLT_EPSILON, origexp-2);
+ 	}
+       else
+ 	return 0.0f;
+     }
+   else
+     {
+       if (y < x)
+ 	{
+ 	  if (x > -FLT_MIN)
+ 	    return -FLT_MIN;
+ 	  return x - scalbnf(FLT_EPSILON, origexp-1);
+ 	}
+       else if (x < -FLT_MIN)
+ 	{
+ 	  float temp = x + scalbnf(FLT_EPSILON, origexp-1);
+ 	  frexpf(temp, &newexp);
+ 	  if (newexp == origexp)
+ 	    return temp;
+ 	  return x + scalbnf(FLT_EPSILON, origexp-2);
+ 	}
+       else
+ 	return 0.0f;
+     }
+ }
+ #endif
+
  /* Note that if HAVE_FPCLASSIFY is not defined, then NaN is not handled */

  /* Algorithm by Steven G. Kargl.  */


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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