summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/probe_math_exception.c33
-rw-r--r--libc/sysdeps/linux/i386/bits/mathinline.h17
-rw-r--r--libm/math_private.h44
-rw-r--r--libm/s_finite.c9
-rw-r--r--libm/s_finitef.c9
5 files changed, 83 insertions, 29 deletions
diff --git a/docs/probe_math_exception.c b/docs/probe_math_exception.c
index dbeccc5cc..dbc9020d4 100644
--- a/docs/probe_math_exception.c
+++ b/docs/probe_math_exception.c
@@ -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 @@ int main(int argc, char **argv)
#endif
if (fetestexcept(FE_ALL_EXCEPT))
printf("\n");
- printf("done\n");
+ else
+ printf("no math exceptions raised\n");
+
+ printf("%.40g\n", t);
return 0;
}
diff --git a/libc/sysdeps/linux/i386/bits/mathinline.h b/libc/sysdeps/linux/i386/bits/mathinline.h
index ca7277d76..5caf73353 100644
--- a/libc/sysdeps/linux/i386/bits/mathinline.h
+++ b/libc/sysdeps/linux/i386/bits/mathinline.h
@@ -713,11 +713,22 @@ __inline_mathcodeNP2 (drem, __x, __y, \
__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, \
diff --git a/libm/math_private.h b/libm/math_private.h
index 0601f2c3d..2c5a30ac2 100644
--- a/libm/math_private.h
+++ b/libm/math_private.h
@@ -188,14 +188,24 @@ 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_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 @@ extern int __kernel_rem_pio2 (double*,double*,int,int,int,const int*) attribu
__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,19 +237,22 @@ extern int __kernel_rem_pio2 (double*,double*,int,int,int,const int*) attribu
__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
diff --git a/libm/s_finite.c b/libm/s_finite.c
index 50fc11b50..9bbc00286 100644
--- a/libm/s_finite.c
+++ b/libm/s_finite.c
@@ -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)
diff --git a/libm/s_finitef.c b/libm/s_finitef.c
index b7c853d4a..b427ea691 100644
--- a/libm/s_finitef.c
+++ b/libm/s_finitef.c
@@ -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)