summaryrefslogtreecommitdiffstats
path: root/sys/i386/include/ieeefp.h
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>2008-01-11 18:27:01 +0000
committerbde <bde@FreeBSD.org>2008-01-11 18:27:01 +0000
commitb1a379ee656f7f3ee5bb8d3f47b2fd30ee48b8eb (patch)
tree16a832da476a257c12b147ebb2243e595b3218a5 /sys/i386/include/ieeefp.h
parent466cc1c021f230db7007d6a57d79d2cefb5c0993 (diff)
downloadFreeBSD-src-b1a379ee656f7f3ee5bb8d3f47b2fd30ee48b8eb.zip
FreeBSD-src-b1a379ee656f7f3ee5bb8d3f47b2fd30ee48b8eb.tar.gz
Separate fpresetsticky() from the other fpset functions so that the
others can be replaced cleanly by the amd64 versions. There is no current amd64 version to merge, but there is an old one which is similar. Fix the following bugs in fpresetsticky(): - garbage args clobbered non-sticky bits in the status register - the return value was usually garbage since it was masked with the arg instead of with the field selector. Optimize fpresetsticky() to avoid using the environment as in feclearexcept() (use only fnclex() if possible) and also to avoid using fnclex() for null changes. The second of these optimizations might not be so good since its branch might cost more than it saves.
Diffstat (limited to 'sys/i386/include/ieeefp.h')
-rw-r--r--sys/i386/include/ieeefp.h31
1 files changed, 27 insertions, 4 deletions
diff --git a/sys/i386/include/ieeefp.h b/sys/i386/include/ieeefp.h
index 37068e7..22b4f5d 100644
--- a/sys/i386/include/ieeefp.h
+++ b/sys/i386/include/ieeefp.h
@@ -115,6 +115,7 @@ typedef enum {
#ifdef __GNUCLIKE_ASM
#define __fldenv(addr) __asm __volatile("fldenv %0" : : "m" (*(addr)))
+#define __fnclex() __asm __volatile("fnclex")
#define __fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))
#define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr)))
#define __fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr)))
@@ -165,8 +166,6 @@ __fpsetreg(int _m, int _reg, int _fld, int _off)
return _p;
}
-#endif /* __GNUCLIKE_ASM */
-
/*
* SysV/386 FP control interface
*/
@@ -185,8 +184,32 @@ __fpsetreg(int _m, int _reg, int _fld, int _off)
(FP_MSKS_FLD >> FP_MSKS_OFF))
#define fpgetsticky() ((fp_except_t) \
((__fpgetreg(FP_STKY_REG) & FP_STKY_FLD) >> FP_STKY_OFF))
-#define fpresetsticky(m) ((fp_except_t) \
- __fpsetreg(0, FP_STKY_REG, (m), FP_STKY_OFF))
+
+static __inline fp_except_t
+fpresetsticky(fp_except_t _m)
+{
+ struct {
+ unsigned _cw;
+ unsigned _sw;
+ unsigned _other[5];
+ } _env;
+ fp_except_t _p;
+
+ _m &= FP_STKY_FLD >> FP_STKY_OFF;
+ _p = fpgetsticky();
+ if ((_p & ~_m) == _p)
+ return (_p);
+ if ((_p & ~_m) == 0) {
+ __fnclex();
+ return (_p);
+ }
+ __fnstenv(&_env);
+ _env._sw &= ~_m;
+ __fldenv(&_env);
+ return (_p);
+}
+
+#endif /* __GNUCLIKE_ASM */
/* Suppress prototypes in the MI header. */
#define _IEEEFP_INLINED_ 1
OpenPOWER on IntegriCloud