Merge from vendor branch GCC:
[dragonfly.git] / sys / cpu / i386 / include / floatingpoint.h
1 /*-
2  * Copyright (c) 1993 Andrew Moore, Talke Studio
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *      from: @(#) floatingpoint.h      1.0 (Berkeley) 9/23/93
34  * $FreeBSD: src/sys/i386/include/floatingpoint.h,v 1.10.2.1 2002/06/30 00:55:09 bde Exp $
35  * $DragonFly: src/sys/cpu/i386/include/floatingpoint.h,v 1.3 2003/08/07 21:17:22 dillon Exp $
36  */
37
38 #ifndef _FLOATINGPOINT_H_
39 #define _FLOATINGPOINT_H_
40
41 /*
42  * IEEE floating point structure and function definitions
43  */
44
45 /*-
46  * XXX the following undocumented pollution is exported:
47  *      fpsetsticky().
48  *      FP*FLD, FP*OFF and FP*REG from <machine/ieeefp.h>
49  */
50
51 #include <sys/cdefs.h>
52 #include "ieeefp.h"
53
54 #ifdef __GNUC__
55
56 #define __fldenv(addr)  __asm __volatile("fldenv %0" : : "m" (*(addr)))
57 #define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr)))
58 #define __fnstcw(addr)  __asm __volatile("fnstcw %0" : "=m" (*(addr)))
59 #define __fnstsw(addr)  __asm __volatile("fnstsw %0" : "=m" (*(addr)))
60
61 /*
62  * return the contents of a FP register
63  */
64 static __inline__ int
65 __fpgetreg(int _reg)
66 {
67         unsigned short _mem;
68
69         /*-
70          * This is more efficient than it looks.  The switch gets optimized
71          * away if _reg is constant.
72          *
73          * The default case only supports _reg == 0.  We could handle more
74          * registers (e.g., tags) using fnstenv, but the interface doesn't
75          * support more.
76          */
77         switch(_reg) {
78         default:
79                 __fnstcw(&_mem);
80                 break;
81         case FP_STKY_REG:
82                 __fnstsw(&_mem);
83                 break;
84         }
85         return _mem;
86 }
87
88 /*
89  * set a FP mode; return previous mode
90  */
91 static __inline__ int
92 __fpsetreg(int _m, int _reg, int _fld, int _off)
93 {
94         unsigned _env[7];
95         unsigned _p;
96
97         /*
98          * _reg == 0 could be handled better using fnstcw/fldcw.
99          */
100         __fnstenv(_env);
101         _p =  (_env[_reg] & _fld) >> _off;
102         _env[_reg] = (_env[_reg] & ~_fld) | (_m << _off & _fld);
103         __fldenv(_env);
104         return _p;
105 }
106
107 #endif /* __GNUC__ */
108
109 /*
110  * SysV/386 FP control interface
111  */
112 #define fpgetround()    ((fp_rnd_t)                                     \
113         ((__fpgetreg(FP_RND_REG) & FP_RND_FLD) >> FP_RND_OFF))
114 #define fpsetround(m)   ((fp_rnd_t)                                     \
115         __fpsetreg((m), FP_RND_REG, FP_RND_FLD, FP_RND_OFF))
116 #define fpgetprec()     ((fp_prec_t)                                    \
117         ((__fpgetreg(FP_PRC_REG) & FP_PRC_FLD) >> FP_PRC_OFF))
118 #define fpsetprec(m)    ((fp_prec_t)                                    \
119         __fpsetreg((m), FP_PRC_REG, FP_PRC_FLD, FP_PRC_OFF))
120 #define fpgetmask()     ((fp_except_t)                                  \
121         ((~__fpgetreg(FP_MSKS_REG) & FP_MSKS_FLD) >> FP_MSKS_OFF))
122 #define fpsetmask(m)    ((fp_except_t)                                  \
123         (~__fpsetreg(~(m), FP_MSKS_REG, FP_MSKS_FLD, FP_MSKS_OFF)) &    \
124             (FP_MSKS_FLD >> FP_MSKS_OFF))
125 #define fpgetsticky()   ((fp_except_t)                                  \
126         ((__fpgetreg(FP_STKY_REG) & FP_STKY_FLD) >> FP_STKY_OFF))
127 #define fpresetsticky(m) ((fp_except_t)                                 \
128         __fpsetreg(0, FP_STKY_REG, (m), FP_STKY_OFF))
129 #define fpsetsticky(m)  fpresetsticky(m)
130
131 #endif /* !_FLOATINGPOINT_H_ */