ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/sys/i386/include/ieeefp.h
(Generate patch)

Comparing trunk/sys/i386/include/ieeefp.h (file contents):
Revision 5087 by laffer1, Sat Mar 31 17:05:11 2012 UTC vs.
Revision 5088 by laffer1, Fri Aug 3 00:59:05 2012 UTC

# Line 1 | Line 1
1 < /* $MidnightBSD$ */
1 > /* $MidnightBSD: src/sys/i386/include/ieeefp.h,v 1.2 2012/03/31 17:05:09 laffer1 Exp $ */
2   /*-
3 + * Copyright (c) 2003 Peter Wemm.
4   * Copyright (c) 1990 Andrew Moore, Talke Studio
5   * All rights reserved.
6   *
# Line 32 | Line 33
33   * SUCH DAMAGE.
34   *
35   *      from: @(#) ieeefp.h     1.0 (Berkeley) 9/23/93
36 < * $FreeBSD: src/sys/i386/include/ieeefp.h,v 1.11 2005/03/15 15:53:39 das Exp $
36 > * $FreeBSD$
37   */
38  
38 /*
39 *      IEEE floating point type and constant definitions.
40 */
41
39   #ifndef _MACHINE_IEEEFP_H_
40   #define _MACHINE_IEEEFP_H_
41  
42 + /*
43 + * IEEE floating point type, constant and function definitions.
44 + * XXX: FP*FLD and FP*OFF are undocumented pollution.
45 + */
46 +
47   #ifndef _SYS_CDEFS_H_
48   #error this file needs sys/cdefs.h as a prerequisite
49   #endif
50  
51   /*
52 < * FP rounding modes
52 > * Rounding modes.
53   */
54   typedef enum {
55          FP_RN=0,        /* round to nearest */
56 <        FP_RM,          /* round down to minus infinity */
57 <        FP_RP,          /* round up to plus infinity */
56 >        FP_RM,          /* round down towards minus infinity */
57 >        FP_RP,          /* round up towards plus infinity */
58          FP_RZ           /* truncate */
59   } fp_rnd_t;
60  
61   /*
62 < * FP precision modes
62 > * Precision (i.e., rounding precision) modes.
63   */
64   typedef enum {
65          FP_PS=0,        /* 24 bit (single-precision) */
# Line 69 | Line 71 | typedef enum {
71   #define fp_except_t     int
72  
73   /*
74 < * FP exception masks
74 > * Exception bit masks.
75   */
76   #define FP_X_INV        0x01    /* invalid operation */
77   #define FP_X_DNML       0x02    /* denormal */
# Line 80 | Line 82 | typedef enum {
82   #define FP_X_STK        0x40    /* stack fault */
83  
84   /*
85 < * FP registers
85 > * FPU control word bit-field masks.
86   */
87 < #define FP_MSKS_REG     0       /* exception masks */
88 < #define FP_PRC_REG      0       /* precision */
89 < #define FP_RND_REG      0       /* direction */
88 < #define FP_STKY_REG     1       /* sticky flags */
87 > #define FP_MSKS_FLD     0x3f    /* exception masks field */
88 > #define FP_PRC_FLD      0x300   /* precision control field */
89 > #define FP_RND_FLD      0xc00   /* rounding control field */
90  
91   /*
92 < * FP register bit field masks
92 > * FPU status word bit-field masks.
93   */
93 #define FP_MSKS_FLD     0x3f    /* exception masks field */
94 #define FP_PRC_FLD      0x300   /* precision control field */
95 #define FP_RND_FLD      0xc00   /* round control field */
94   #define FP_STKY_FLD     0x3f    /* sticky flags field */
95  
96   /*
97 < * FP register bit field offsets
97 > * FPU control word bit-field offsets (shift counts).
98   */
99   #define FP_MSKS_OFF     0       /* exception masks offset */
100   #define FP_PRC_OFF      8       /* precision control offset */
101 < #define FP_RND_OFF      10      /* round control offset */
101 > #define FP_RND_OFF      10      /* rounding control offset */
102 >
103 > /*
104 > * FPU status word bit-field offsets (shift counts).
105 > */
106   #define FP_STKY_OFF     0       /* sticky flags offset */
107  
108   #ifdef __GNUCLIKE_ASM
109  
110 + #define __fldcw(addr)   __asm __volatile("fldcw %0" : : "m" (*(addr)))
111   #define __fldenv(addr)  __asm __volatile("fldenv %0" : : "m" (*(addr)))
112 < #define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr)))
112 > #define __fnclex()      __asm __volatile("fnclex")
113   #define __fnstcw(addr)  __asm __volatile("fnstcw %0" : "=m" (*(addr)))
114 + #define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr)))
115   #define __fnstsw(addr)  __asm __volatile("fnstsw %0" : "=m" (*(addr)))
116  
117   /*
118 < * return the contents of a FP register
118 > * Load the control word.  Be careful not to trap if there is a currently
119 > * unmasked exception (ones that will become freshly unmasked are not a
120 > * problem).  This case must be handled by a save/restore of the
121 > * environment or even of the full x87 state.  Accessing the environment
122 > * is very inefficient, so only do it when necessary.
123   */
124 < static __inline__ int
125 < __fpgetreg(int _reg)
124 > static __inline void
125 > __fnldcw(unsigned short _cw, unsigned short _newcw)
126   {
127 <        unsigned short _mem;
127 >        struct {
128 >                unsigned _cw;
129 >                unsigned _other[6];
130 >        } _env;
131 >        unsigned short _sw;
132  
133 <        /*-
134 <         * This is more efficient than it looks.  The switch gets optimized
135 <         * away if _reg is constant.
136 <         *
137 <         * The default case only supports _reg == 0.  We could handle more
138 <         * registers (e.g., tags) using fnstenv, but the interface doesn't
139 <         * support more.
140 <         */
129 <        switch(_reg) {
130 <        default:
131 <                __fnstcw(&_mem);
132 <                break;
133 <        case FP_STKY_REG:
134 <                __fnstsw(&_mem);
135 <                break;
133 >        if ((_cw & FP_MSKS_FLD) != FP_MSKS_FLD) {
134 >                __fnstsw(&_sw);
135 >                if (((_sw & ~_cw) & FP_STKY_FLD) != 0) {
136 >                        __fnstenv(&_env);
137 >                        _env._cw = _newcw;
138 >                        __fldenv(&_env);
139 >                        return;
140 >                }
141          }
142 <        return _mem;
142 >        __fldcw(&_newcw);
143   }
144  
145 < /*
146 < * set a FP mode; return previous mode
142 < */
143 < static __inline__ int
144 < __fpsetreg(int _m, int _reg, int _fld, int _off)
145 > static __inline fp_rnd_t
146 > fpgetround(void)
147   {
148 <        unsigned _env[7];
147 <        unsigned _p;
148 >        unsigned short _cw;
149  
150 <        /*
151 <         * _reg == 0 could be handled better using fnstcw/fldcw.
151 <         */
152 <        __fnstenv(_env);
153 <        _p =  (_env[_reg] & _fld) >> _off;
154 <        _env[_reg] = (_env[_reg] & ~_fld) | (_m << _off & _fld);
155 <        __fldenv(_env);
156 <        return _p;
150 >        __fnstcw(&_cw);
151 >        return ((fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF));
152   }
153  
154 < #endif /* __GNUCLIKE_ASM */
154 > static __inline fp_rnd_t
155 > fpsetround(fp_rnd_t _m)
156 > {
157 >        fp_rnd_t _p;
158 >        unsigned short _cw, _newcw;
159  
160 +        __fnstcw(&_cw);
161 +        _p = (fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF);
162 +        _newcw = _cw & ~FP_RND_FLD;
163 +        _newcw |= (_m << FP_RND_OFF) & FP_RND_FLD;
164 +        __fnldcw(_cw, _newcw);
165 +        return (_p);
166 + }
167 +
168 + static __inline fp_prec_t
169 + fpgetprec(void)
170 + {
171 +        unsigned short _cw;
172 +
173 +        __fnstcw(&_cw);
174 +        return ((fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF));
175 + }
176 +
177 + static __inline fp_prec_t
178 + fpsetprec(fp_prec_t _m)
179 + {
180 +        fp_prec_t _p;
181 +        unsigned short _cw, _newcw;
182 +
183 +        __fnstcw(&_cw);
184 +        _p = (fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF);
185 +        _newcw = _cw & ~FP_PRC_FLD;
186 +        _newcw |= (_m << FP_PRC_OFF) & FP_PRC_FLD;
187 +        __fnldcw(_cw, _newcw);
188 +        return (_p);
189 + }
190 +
191   /*
192 < * SysV/386 FP control interface
192 > * Get or set the exception mask.
193 > * Note that the x87 mask bits are inverted by the API -- a mask bit of 1
194 > * means disable for x87 and SSE, but for fp*mask() it means enable.
195   */
196 < #define fpgetround()    ((fp_rnd_t)                                     \
197 <        ((__fpgetreg(FP_RND_REG) & FP_RND_FLD) >> FP_RND_OFF))
198 < #define fpsetround(m)   ((fp_rnd_t)                                     \
199 <        __fpsetreg((m), FP_RND_REG, FP_RND_FLD, FP_RND_OFF))
200 < #define fpgetprec()     ((fp_prec_t)                                    \
201 <        ((__fpgetreg(FP_PRC_REG) & FP_PRC_FLD) >> FP_PRC_OFF))
202 < #define fpsetprec(m)    ((fp_prec_t)                                    \
203 <        __fpsetreg((m), FP_PRC_REG, FP_PRC_FLD, FP_PRC_OFF))
204 < #define fpgetmask()     ((fp_except_t)                                  \
205 <        ((~__fpgetreg(FP_MSKS_REG) & FP_MSKS_FLD) >> FP_MSKS_OFF))
206 < #define fpsetmask(m)    ((fp_except_t)                                  \
207 <        (~__fpsetreg(~(m), FP_MSKS_REG, FP_MSKS_FLD, FP_MSKS_OFF)) &    \
208 <            (FP_MSKS_FLD >> FP_MSKS_OFF))
209 < #define fpgetsticky()   ((fp_except_t)                                  \
210 <        ((__fpgetreg(FP_STKY_REG) & FP_STKY_FLD) >> FP_STKY_OFF))
211 < #define fpresetsticky(m) ((fp_except_t)                                 \
212 <        __fpsetreg(0, FP_STKY_REG, (m), FP_STKY_OFF))
196 >
197 > static __inline fp_except_t
198 > fpgetmask(void)
199 > {
200 >        unsigned short _cw;
201 >
202 >        __fnstcw(&_cw);
203 >        return ((~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF);
204 > }
205 >
206 > static __inline fp_except_t
207 > fpsetmask(fp_except_t _m)
208 > {
209 >        fp_except_t _p;
210 >        unsigned short _cw, _newcw;
211 >
212 >        __fnstcw(&_cw);
213 >        _p = (~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF;
214 >        _newcw = _cw & ~FP_MSKS_FLD;
215 >        _newcw |= (~_m << FP_MSKS_OFF) & FP_MSKS_FLD;
216 >        __fnldcw(_cw, _newcw);
217 >        return (_p);
218 > }
219 >
220 > static __inline fp_except_t
221 > fpgetsticky(void)
222 > {
223 >        unsigned _ex;
224 >        unsigned short _sw;
225 >
226 >        __fnstsw(&_sw);
227 >        _ex = (_sw & FP_STKY_FLD) >> FP_STKY_OFF;
228 >        return ((fp_except_t)_ex);
229 > }
230 >
231 > static __inline fp_except_t
232 > fpresetsticky(fp_except_t _m)
233 > {
234 >        struct {
235 >                unsigned _cw;
236 >                unsigned _sw;
237 >                unsigned _other[5];
238 >        } _env;
239 >        fp_except_t _p;
240 >
241 >        _m &= FP_STKY_FLD >> FP_STKY_OFF;
242 >        _p = fpgetsticky();
243 >        if ((_p & ~_m) == _p)
244 >                return (_p);
245 >        if ((_p & ~_m) == 0) {
246 >                __fnclex();
247 >                return (_p);
248 >        }
249 >        __fnstenv(&_env);
250 >        _env._sw &= ~_m;
251 >        __fldenv(&_env);
252 >        return (_p);
253 > }
254 >
255 > #endif /* __GNUCLIKE_ASM */
256  
257   /* Suppress prototypes in the MI header. */
258   #define _IEEEFP_INLINED_        1

Comparing trunk/sys/i386/include/ieeefp.h (property cvs2svn:cvs-rev):
Revision 5087 by laffer1, Sat Mar 31 17:05:11 2012 UTC vs.
Revision 5088 by laffer1, Fri Aug 3 00:59:05 2012 UTC

# Line 1 | Line 1
1 < 1.2
1 > 1.3

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines