]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/mips/math-emu/ieee754sp.c
MIPS: math-emu: Inline ieee754sp_issnan and ieee754dp_issnan.
[karo-tx-linux.git] / arch / mips / math-emu / ieee754sp.c
1 /* IEEE754 floating point arithmetic
2  * single precision
3  */
4 /*
5  * MIPS floating point support
6  * Copyright (C) 1994-2000 Algorithmics Ltd.
7  *
8  * ########################################################################
9  *
10  *  This program is free software; you can distribute it and/or modify it
11  *  under the terms of the GNU General Public License (Version 2) as
12  *  published by the Free Software Foundation.
13  *
14  *  This program is distributed in the hope it will be useful, but WITHOUT
15  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17  *  for more details.
18  *
19  *  You should have received a copy of the GNU General Public License along
20  *  with this program; if not, write to the Free Software Foundation, Inc.,
21  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * ########################################################################
24  */
25
26 #include <stdarg.h>
27 #include <linux/compiler.h>
28
29 #include "ieee754sp.h"
30
31 int ieee754sp_class(union ieee754sp x)
32 {
33         COMPXSP;
34         EXPLODEXSP;
35         return xc;
36 }
37
38 int ieee754sp_isnan(union ieee754sp x)
39 {
40         return ieee754sp_class(x) >= IEEE754_CLASS_SNAN;
41 }
42
43 static inline int ieee754sp_issnan(union ieee754sp x)
44 {
45         assert(ieee754sp_isnan(x));
46         return (SPMANT(x) & SP_MBIT(SP_FBITS-1));
47 }
48
49
50 union ieee754sp __cold ieee754sp_xcpt(union ieee754sp r, const char *op, ...)
51 {
52         struct ieee754xctx ax;
53
54         if (!ieee754_tstx())
55                 return r;
56
57         ax.op = op;
58         ax.rt = IEEE754_RT_SP;
59         ax.rv.sp = r;
60         va_start(ax.ap, op);
61         ieee754_xcpt(&ax);
62         va_end(ax.ap);
63         return ax.rv.sp;
64 }
65
66 union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r, const char *op, ...)
67 {
68         struct ieee754xctx ax;
69
70         assert(ieee754sp_isnan(r));
71
72         if (!ieee754sp_issnan(r))       /* QNAN does not cause invalid op !! */
73                 return r;
74
75         if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) {
76                 /* not enabled convert to a quiet NaN */
77                 SPMANT(r) &= (~SP_MBIT(SP_FBITS-1));
78                 if (ieee754sp_isnan(r))
79                         return r;
80                 else
81                         return ieee754sp_indef();
82         }
83
84         ax.op = op;
85         ax.rt = 0;
86         ax.rv.sp = r;
87         va_start(ax.ap, op);
88         ieee754_xcpt(&ax);
89         va_end(ax.ap);
90         return ax.rv.sp;
91 }
92
93 static unsigned get_rounding(int sn, unsigned xm)
94 {
95         /* inexact must round of 3 bits
96          */
97         if (xm & (SP_MBIT(3) - 1)) {
98                 switch (ieee754_csr.rm) {
99                 case IEEE754_RZ:
100                         break;
101                 case IEEE754_RN:
102                         xm += 0x3 + ((xm >> 3) & 1);
103                         /* xm += (xm&0x8)?0x4:0x3 */
104                         break;
105                 case IEEE754_RU:        /* toward +Infinity */
106                         if (!sn)        /* ?? */
107                                 xm += 0x8;
108                         break;
109                 case IEEE754_RD:        /* toward -Infinity */
110                         if (sn) /* ?? */
111                                 xm += 0x8;
112                         break;
113                 }
114         }
115         return xm;
116 }
117
118
119 /* generate a normal/denormal number with over,under handling
120  * sn is sign
121  * xe is an unbiased exponent
122  * xm is 3bit extended precision value.
123  */
124 union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
125 {
126         assert(xm);             /* we don't gen exact zeros (probably should) */
127
128         assert((xm >> (SP_FBITS + 1 + 3)) == 0);        /* no execess */
129         assert(xm & (SP_HIDDEN_BIT << 3));
130
131         if (xe < SP_EMIN) {
132                 /* strip lower bits */
133                 int es = SP_EMIN - xe;
134
135                 if (ieee754_csr.nod) {
136                         ieee754_setcx(IEEE754_UNDERFLOW);
137                         ieee754_setcx(IEEE754_INEXACT);
138
139                         switch(ieee754_csr.rm) {
140                         case IEEE754_RN:
141                         case IEEE754_RZ:
142                                 return ieee754sp_zero(sn);
143                         case IEEE754_RU:      /* toward +Infinity */
144                                 if (sn == 0)
145                                         return ieee754sp_min(0);
146                                 else
147                                         return ieee754sp_zero(1);
148                         case IEEE754_RD:      /* toward -Infinity */
149                                 if (sn == 0)
150                                         return ieee754sp_zero(0);
151                                 else
152                                         return ieee754sp_min(1);
153                         }
154                 }
155
156                 if (xe == SP_EMIN - 1
157                                 && get_rounding(sn, xm) >> (SP_FBITS + 1 + 3))
158                 {
159                         /* Not tiny after rounding */
160                         ieee754_setcx(IEEE754_INEXACT);
161                         xm = get_rounding(sn, xm);
162                         xm >>= 1;
163                         /* Clear grs bits */
164                         xm &= ~(SP_MBIT(3) - 1);
165                         xe++;
166                 } else {
167                         /* sticky right shift es bits
168                          */
169                         SPXSRSXn(es);
170                         assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
171                         assert(xe == SP_EMIN);
172                 }
173         }
174         if (xm & (SP_MBIT(3) - 1)) {
175                 ieee754_setcx(IEEE754_INEXACT);
176                 if ((xm & (SP_HIDDEN_BIT << 3)) == 0) {
177                         ieee754_setcx(IEEE754_UNDERFLOW);
178                 }
179
180                 /* inexact must round of 3 bits
181                  */
182                 xm = get_rounding(sn, xm);
183                 /* adjust exponent for rounding add overflowing
184                  */
185                 if (xm >> (SP_FBITS + 1 + 3)) {
186                         /* add causes mantissa overflow */
187                         xm >>= 1;
188                         xe++;
189                 }
190         }
191         /* strip grs bits */
192         xm >>= 3;
193
194         assert((xm >> (SP_FBITS + 1)) == 0);    /* no execess */
195         assert(xe >= SP_EMIN);
196
197         if (xe > SP_EMAX) {
198                 ieee754_setcx(IEEE754_OVERFLOW);
199                 ieee754_setcx(IEEE754_INEXACT);
200                 /* -O can be table indexed by (rm,sn) */
201                 switch (ieee754_csr.rm) {
202                 case IEEE754_RN:
203                         return ieee754sp_inf(sn);
204                 case IEEE754_RZ:
205                         return ieee754sp_max(sn);
206                 case IEEE754_RU:        /* toward +Infinity */
207                         if (sn == 0)
208                                 return ieee754sp_inf(0);
209                         else
210                                 return ieee754sp_max(1);
211                 case IEEE754_RD:        /* toward -Infinity */
212                         if (sn == 0)
213                                 return ieee754sp_max(0);
214                         else
215                                 return ieee754sp_inf(1);
216                 }
217         }
218         /* gen norm/denorm/zero */
219
220         if ((xm & SP_HIDDEN_BIT) == 0) {
221                 /* we underflow (tiny/zero) */
222                 assert(xe == SP_EMIN);
223                 if (ieee754_csr.mx & IEEE754_UNDERFLOW)
224                         ieee754_setcx(IEEE754_UNDERFLOW);
225                 return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
226         } else {
227                 assert((xm >> (SP_FBITS + 1)) == 0);    /* no execess */
228                 assert(xm & SP_HIDDEN_BIT);
229
230                 return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
231         }
232 }