svn commit: branches/uClibc-nptl: docs libm

vda at uclibc.org vda at uclibc.org
Sun Feb 8 02:04:27 UTC 2009


Author: vda
Date: 2009-02-08 02:04:26 +0000 (Sun, 08 Feb 2009)
New Revision: 25263

Log:
nextafterf: trying to correct FP exception handling



Added:
   branches/uClibc-nptl/docs/probe_math_exception.c

Modified:
   branches/uClibc-nptl/libm/math_private.h
   branches/uClibc-nptl/libm/s_nextafterf.c


Changeset:
Added: branches/uClibc-nptl/docs/probe_math_exception.c
===================================================================
--- branches/uClibc-nptl/docs/probe_math_exception.c	                        (rev 0)
+++ branches/uClibc-nptl/docs/probe_math_exception.c	2009-02-08 02:04:26 UTC (rev 25263)
@@ -0,0 +1,41 @@
+/* Small test program for probing how various math functions
+ * with specific operands set floating point exceptions
+ */
+
+#define _ISOC99_SOURCE 1
+#define _GNU_SOURCE    1
+
+#include <math.h>
+#include <fenv.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	float infF = HUGE_VALF * 2;
+
+	feclearexcept(FE_ALL_EXCEPT);
+
+//	printf("%.40e\n", 1.0 / 0.0); // FE_DIVBYZERO
+//	printf("%.40e\n", nextafterf(HUGE_VALF, infF)); // no exceptions in glibc 2.4
+
+#define PREX(ex) do { if (fetestexcept(ex)) printf(#ex); } while(0)
+#ifdef FE_INEXACT
+	PREX(FE_INEXACT);
+#endif
+#ifdef FE_DIVBYZERO
+	PREX(FE_DIVBYZERO);
+#endif
+#ifdef FE_UNDERFLOW
+	PREX(FE_UNDERFLOW);
+#endif
+#ifdef FE_OVERFLOW
+	PREX(FE_OVERFLOW);
+#endif
+#ifdef FE_INVALID
+	PREX(FE_INVALID);
+#endif
+	if (fetestexcept(FE_ALL_EXCEPT))
+		printf("\n");
+	printf("done\n");
+	return 0;
+}

Modified: branches/uClibc-nptl/libm/math_private.h
===================================================================
--- branches/uClibc-nptl/libm/math_private.h	2009-02-08 02:04:10 UTC (rev 25262)
+++ branches/uClibc-nptl/libm/math_private.h	2009-02-08 02:04:26 UTC (rev 25263)
@@ -187,4 +187,59 @@
 extern double __kernel_tan (double,double,int) attribute_hidden;
 extern int    __kernel_rem_pio2 (double*,double*,int,int,int,const int*) attribute_hidden;
 
+/*
+ * math_opt_barrier(x): force expression x to be evaluated and put into
+ * a floating point register or memory. This macro returns the value.
+ *
+ * math_force_eval(x): force expression x to be evaluated and put into
+ * a floating point register or memory *of the appropriate size*.
+ * This forces floating point flags to be set correctly
+ * (for example, when float value is overflowing, but FPU registers
+ * are wide enough to "hide" this).
+ */
+#if defined(__i386__)
+#define math_opt_barrier(x) ({ \
+	__typeof(x) __x = (x); \
+	/* "t": load x into top-of-stack fpreg */ \
+	__asm ("" : "=t" (__x) : "0" (__x)); \
+	__x; \
+})
+#define math_force_eval(x) do {	\
+	if (sizeof(x) <= sizeof(double)) \
+		/* "m": store x into a memory location */ \
+		__asm __volatile ("" : : "m" (x)); \
+	else /* long double */ \
+		/* "f": load x into (any) fpreg */ \
+		__asm __volatile ("" : : "f" (x)); \
+} while (0)
+#endif
+
+#if defined(__x86_64__)
+#define math_opt_barrier(x) ({ \
+	__typeof(x) __x = (x); \
+	if (sizeof(x) <= sizeof(double)) \
+		/* "x": load into XMM SSE register */ \
+		__asm ("" : "=x" (__x) : "0" (__x)); \
+	else /* long double */ \
+		/* "t": load x into top-of-stack fpreg */ \
+		__asm ("" : "=t" (__x) : "0" (__x)); \
+	__x; \
+})
+#define math_force_eval(x) do { \
+	if (sizeof(x) <= sizeof(double)) \
+		/* "x": load into XMM SSE register */ \
+		__asm __volatile ("" : : "x" (x)); \
+	else /* long double */ \
+		/* "f": load x into (any) fpreg */ \
+		__asm __volatile ("" : : "f" (x)); \
+} while (0)
+#endif
+
+/* Default implementation forces store to a memory location */
+#ifndef math_opt_barrier
+#define math_opt_barrier(x) ({ __typeof(x) __x = (x); __asm ("" : "+m" (__x)); __x; })
+#define math_force_eval(x)  __asm __volatile ("" : : "m" (x))
+#endif
+
+
 #endif /* _MATH_PRIVATE_H_ */

Modified: branches/uClibc-nptl/libm/s_nextafterf.c
===================================================================
--- branches/uClibc-nptl/libm/s_nextafterf.c	2009-02-08 02:04:10 UTC (rev 25262)
+++ branches/uClibc-nptl/libm/s_nextafterf.c	2009-02-08 02:04:26 UTC (rev 25263)
@@ -16,11 +16,6 @@
 #include "math.h"
 #include "math_private.h"
 
-#ifndef math_opt_barrier
-# define math_opt_barrier(x) ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
-# define math_force_eval(x)  __asm __volatile ("" : : "m" (x))
-#endif
-
 float nextafterf(float x, float y)
 {
 	int32_t hx, hy, ix, iy;
@@ -38,12 +33,12 @@
 		return y;
 
 	if (ix == 0) { /* x == 0? */
-		float u;
+// glibc 2.4 does not seem to set underflow?
+//		float u;
 		/* return +-minsubnormal */
 		SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);
-		u = math_opt_barrier(x);
-		u = u * u;
-		math_force_eval(u); /* raise underflow flag */
+//		u = x * x; /* raise underflow flag */
+//		math_force_eval(u);
 		return x;
 	}
 
@@ -63,8 +58,6 @@
 	hy = hx & 0x7f800000;
 	if (hy >= 0x7f800000) {
 		x = x + x; /* overflow */
-//??		if (FLT_EVAL_METHOD != 0)
-//			asm ("" : "+m"(x));
 		return x; /* overflow */
 	}
 	if (hy < 0x00800000) {



More information about the uClibc-cvs mailing list