From 5d53cce4c05d1f4f730cce080233dc959f773059 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Wed, 11 Feb 2009 17:37:21 +0000 Subject: 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...) --- libm/math_private.h | 44 +++++++++++++++++++++++++++++--------------- libm/s_finite.c | 9 ++++++--- libm/s_finitef.c | 9 ++++++--- 3 files changed, 41 insertions(+), 21 deletions(-) (limited to 'libm') 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) -- cgit v1.2.3