svn commit: trunk/uClibc: docs libc/sysdeps/linux/i386/bits libm

vda at uclibc.org vda at uclibc.org
Wed Feb 11 17:37:21 UTC 2009


Author: vda
Date: 2009-02-11 17:37:21 +0000 (Wed, 11 Feb 2009)
New Revision: 25300

Log:
docs/probe_math_exception.c:
	update example
libc/sysdeps/linux/i386/bits/mathinline.h:
	improve __finite() macro, add __finitef macro
	(why they aren't always macros? why aren't they arch independent?)
libm/math_private.h:
	much better comments on math_opt_barrier() and math_force_eval()
libm/s_finite[f].c:
	improve out-of-line __finite[f]() too (one byte less, yay...)



Modified:
   trunk/uClibc/docs/probe_math_exception.c
   trunk/uClibc/libc/sysdeps/linux/i386/bits/mathinline.h
   trunk/uClibc/libm/math_private.h
   trunk/uClibc/libm/s_finite.c
   trunk/uClibc/libm/s_finitef.c


Changeset:
Modified: trunk/uClibc/docs/probe_math_exception.c
===================================================================
--- trunk/uClibc/docs/probe_math_exception.c	2009-02-11 17:32:39 UTC (rev 25299)
+++ trunk/uClibc/docs/probe_math_exception.c	2009-02-11 17:37:21 UTC (rev 25300)
@@ -5,20 +5,40 @@
 #define _ISOC99_SOURCE 1
 #define _GNU_SOURCE    1
 
+#include <stdint.h>
 #include <math.h>
 #include <fenv.h>
 #include <stdio.h>
 
 int main(int argc, char **argv)
 {
-	float infF = HUGE_VALF * 2;
+	float largest, small, t, inf_float;
 
+	largest = small = 1;
+	while (1) {
+		t = largest + small;
+		/* optimizations may make plain "t == largest" unreliable */
+		if (memcmp(&t, &largest, sizeof(float)) == 0)
+			break;
+		if (isfinite(t)) {
+			largest = t;
+			small *= 2;
+			continue;
+		}
+		small /= 2;
+	}
+	inf_float = largest + largest;
+	//printf("%.40g ", largest);
+	//printf("[%llx]\n", (long long) (*(uint32_t *)&largest));
+
 	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
+	//t = 1.0 / 0.0; // simple test: FE_DIVBYZERO
+	//t = nextafterf(largest, 1); // glibc 2.8: no math exceptions raised
+	//t = nextafterf(largest, largest); // glibc 2.8: no math exceptions raised
+	//t = nextafterf(largest, inf_float); // glibc 2.8: FE_INEXACT FE_OVERFLOW
 
-#define PREX(ex) do { if (fetestexcept(ex)) printf(#ex); } while(0)
+#define PREX(ex) do { if (fetestexcept(ex)) printf(#ex " "); } while(0)
 #ifdef FE_INEXACT
 	PREX(FE_INEXACT);
 #endif
@@ -36,6 +56,9 @@
 #endif
 	if (fetestexcept(FE_ALL_EXCEPT))
 		printf("\n");
-	printf("done\n");
+	else
+		printf("no math exceptions raised\n");
+
+	printf("%.40g\n", t);
 	return 0;
 }

Modified: trunk/uClibc/libc/sysdeps/linux/i386/bits/mathinline.h
===================================================================
--- trunk/uClibc/libc/sysdeps/linux/i386/bits/mathinline.h	2009-02-11 17:32:39 UTC (rev 25299)
+++ trunk/uClibc/libc/sysdeps/linux/i386/bits/mathinline.h	2009-02-11 17:37:21 UTC (rev 25300)
@@ -713,11 +713,22 @@
 __MATH_INLINE int
 __NTH (__finite (double __x))
 {
-  return (__extension__
-	  (((((union { double __d; int __i[2]; }) {__d: __x}).__i[1]
-	     | 0x800fffffu) + 1) >> 31));
+  union { double __d; int __i[2]; } u;
+  u.__d = __x;
+  /* Finite numbers have at least one zero bit in exponent. */
+  /* All other numbers will result in 0xffffffff after OR: */
+  return (u.__i[1] | 0x800fffff) != 0xffffffff;
 }
 
+__MATH_INLINE int
+__NTH (__finitef (float __x))
+{
+  union { float __d; int __i; } u;
+  u.__d = __x;
+  return (u.__i | 0x807fffff) != 0xffffffff;
+}
+
+
 /* Miscellaneous functions */
 # ifdef __FAST_MATH__
 __inline_mathcode (__coshm1, __x, \

Modified: trunk/uClibc/libm/math_private.h
===================================================================
--- trunk/uClibc/libm/math_private.h	2009-02-11 17:32:39 UTC (rev 25299)
+++ trunk/uClibc/libm/math_private.h	2009-02-11 17:37:21 UTC (rev 25300)
@@ -188,14 +188,24 @@
 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_opt_barrier(x): safely load x, even if it was manipulated
+ * by non-floationg point operations. This macro returns the value of x.
+ * This ensures compiler does not (ab)use its knowledge about x value
+ * and don't optimize future operations. Example:
+ * float x;
+ * SET_FLOAT_WORD(x, 0x80000001); // sets a bit pattern
+ * y = math_opt_barrier(x); // "compiler, do not cheat!"
+ * y = y * y; // compiler can't optimize, must use real multiply insn
  *
- * math_force_eval(x): force expression x to be evaluated and put into
+ * math_force_eval(x): force expression x to be evaluated.
+ * Useful if otherwise compiler may eliminate the expression
+ * as unused. This macro returns no value.
+ * Example: "void fn(float f) { f = f * f; }"
+ *   versus "void fn(float f) { f = f * f; math_force_eval(f); }"
+ *
+ * Currently, math_force_eval(x) stores x 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).
+ * There is no guarantee this will not change.
  */
 #if defined(__i386__)
 #define math_opt_barrier(x) ({ \
@@ -205,19 +215,20 @@
 	__x; \
 })
 #define math_force_eval(x) do {	\
-	if (sizeof(x) <= sizeof(double)) \
+	__typeof(x) __x = (x); \
+	if (sizeof(__x) <= sizeof(double)) \
 		/* "m": store x into a memory location */ \
-		__asm __volatile ("" : : "m" (x)); \
+		__asm __volatile ("" : : "m" (__x)); \
 	else /* long double */ \
 		/* "f": load x into (any) fpreg */ \
-		__asm __volatile ("" : : "f" (x)); \
+		__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)) \
+	if (sizeof(__x) <= sizeof(double)) \
 		/* "x": load into XMM SSE register */ \
 		__asm ("" : "=x" (__x) : "0" (__x)); \
 	else /* long double */ \
@@ -226,20 +237,23 @@
 	__x; \
 })
 #define math_force_eval(x) do { \
-	if (sizeof(x) <= sizeof(double)) \
+	__typeof(x) __x = (x); \
+	if (sizeof(__x) <= sizeof(double)) \
 		/* "x": load into XMM SSE register */ \
-		__asm __volatile ("" : : "x" (x)); \
+		__asm __volatile ("" : : "x" (__x)); \
 	else /* long double */ \
 		/* "f": load x into (any) fpreg */ \
-		__asm __volatile ("" : : "f" (x)); \
+		__asm __volatile ("" : : "f" (__x)); \
 } while (0)
 #endif
 
-/* Default implementation forces store to a memory location */
+/* Default implementations force 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
+#ifndef math_force_eval
+#define math_force_eval(x)  do { __typeof(x) __x = (x); __asm __volatile ("" : : "m" (__x)); } while (0)
+#endif
 
 
 #endif /* _MATH_PRIVATE_H_ */

Modified: trunk/uClibc/libm/s_finite.c
===================================================================
--- trunk/uClibc/libm/s_finite.c	2009-02-11 17:32:39 UTC (rev 25299)
+++ trunk/uClibc/libm/s_finite.c	2009-02-11 17:37:21 UTC (rev 25300)
@@ -22,8 +22,11 @@
 
 int __finite(double x)
 {
-	int32_t hx;
-	GET_HIGH_WORD(hx,x);
-	return (int)((u_int32_t)((hx&0x7fffffff)-0x7ff00000)>>31);
+	u_int32_t hx;
+
+	GET_HIGH_WORD(hx, x);
+	/* Finite numbers have at least one zero bit in exponent. */
+	/* All other numbers will result in 0xffffffff after OR: */
+	return (hx | 0x800fffff) != 0xffffffff;
 }
 libm_hidden_def(__finite)

Modified: trunk/uClibc/libm/s_finitef.c
===================================================================
--- trunk/uClibc/libm/s_finitef.c	2009-02-11 17:32:39 UTC (rev 25299)
+++ trunk/uClibc/libm/s_finitef.c	2009-02-11 17:37:21 UTC (rev 25300)
@@ -23,8 +23,11 @@
 
 int __finitef(float x)
 {
-	int32_t ix;
-	GET_FLOAT_WORD(ix,x);
-	return (int)((u_int32_t)((ix&0x7fffffff)-0x7f800000)>>31);
+	u_int32_t ix;
+
+	GET_FLOAT_WORD(ix, x);
+	/* Finite numbers have at least one zero bit in exponent. */
+	/* All other numbers will result in 0xffffffff after OR: */
+	return (ix | 0x807fffff) != 0xffffffff;
 }
 libm_hidden_def(__finitef)



More information about the uClibc-cvs mailing list